rename IgnoreRedefinition to AllowOverride
[hiphop-php.git] / hphp / runtime / vm / func.h
blob2601b06914a448859a6886705799c82f02ac25b3
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_FUNC_H_
18 #define incl_HPHP_VM_FUNC_H_
20 #include "hphp/runtime/vm/bytecode.h"
21 #include "hphp/runtime/vm/type_constraint.h"
22 #include "hphp/runtime/vm/repo_helpers.h"
23 #include "hphp/runtime/vm/indexed_string_map.h"
24 #include "hphp/runtime/base/intercept.h"
26 namespace HPHP {
28 static const int kNumFixedPrologues = 6;
30 typedef TypedValue*(*BuiltinFunction)(ActRec* ar);
33 * Metadata about a php function or object method.
35 struct Func {
36 friend class FuncEmitter;
38 typedef hphp_hash_map<const StringData*, TypedValue, string_data_hash,
39 string_data_isame> UserAttributeMap;
41 struct ParamInfo { // Parameter default value info.
42 // construct a dummy ParamInfo
43 ParamInfo()
44 : m_builtinType(KindOfInvalid), m_funcletOff(InvalidAbsoluteOffset),
45 m_phpCode(nullptr), m_userType(nullptr) {
46 tvWriteUninit(&m_defVal);
49 template<class SerDe>
50 void serde(SerDe& sd) {
51 const StringData* tcName = m_typeConstraint.typeName();
52 TypeConstraint::Flags tcFlags = m_typeConstraint.flags();
54 sd(m_builtinType)
55 (m_funcletOff)
56 (m_defVal)
57 (m_phpCode)
58 (tcName)
59 (tcFlags)
60 (m_userAttributes)
61 (m_userType)
64 if (SerDe::deserializing) {
65 setTypeConstraint(TypeConstraint(tcName, tcFlags));
69 void setBuiltinType(DataType type) { m_builtinType = type; }
70 DataType builtinType() const { return m_builtinType; }
72 void setFuncletOff(Offset funcletOff) { m_funcletOff = funcletOff; }
73 Offset funcletOff() const { return m_funcletOff; }
75 bool hasDefaultValue() const {
76 return m_funcletOff != InvalidAbsoluteOffset;
78 bool hasNonNullDefaultValue() const {
79 return hasDefaultValue() && m_defVal.m_type != KindOfNull;
81 bool hasScalarDefaultValue() const {
82 return hasDefaultValue() && m_defVal.m_type != KindOfUninit;
84 void setDefaultValue(const TypedValue& defVal) { m_defVal = defVal; }
85 const TypedValue& defaultValue() const { return m_defVal; }
87 void setPhpCode(const StringData* phpCode) { m_phpCode = phpCode; }
88 const StringData* phpCode() const { return m_phpCode; }
90 void setTypeConstraint(const TypeConstraint& tc) { m_typeConstraint = tc; }
91 const TypeConstraint& typeConstraint() const { return m_typeConstraint; }
93 void addUserAttribute(const StringData* name, TypedValue tv) {
94 m_userAttributes[name] = tv;
96 void setUserAttributes(const Func::UserAttributeMap& uaMap) {
97 m_userAttributes = uaMap;
99 const Func::UserAttributeMap& userAttributes() const {
100 return m_userAttributes;
102 void setUserType(const StringData* userType) {
103 m_userType = userType;
105 const StringData* userType() const {
106 return m_userType;
109 private:
110 DataType m_builtinType; // typehint for builtins
111 Offset m_funcletOff; // If no default: InvalidAbsoluteOffset.
112 TypedValue m_defVal; // Set to uninit null if there is no default value
113 // or if there is a non-scalar default value.
114 const StringData* m_phpCode; // eval'able PHP code.
115 TypeConstraint m_typeConstraint;
117 Func::UserAttributeMap m_userAttributes;
118 // the type the user typed in source code, contains type parameters and all
119 const StringData* m_userType;
121 struct SVInfo { // Static variable info.
122 const StringData* name;
123 const StringData* phpCode; // eval'able PHP or NULL if no default.
125 template<class SerDe> void serde(SerDe& sd) { sd(name)(phpCode); }
128 typedef FixedVector<ParamInfo> ParamInfoVec;
129 typedef FixedVector<SVInfo> SVInfoVec;
130 typedef FixedVector<EHEnt> EHEntVec;
131 typedef FixedVector<FPIEnt> FPIEntVec;
133 typedef uint32_t FuncId;
134 static const FuncId InvalidId = -1LL;
136 Func(Unit& unit, Id id, int line1, int line2, Offset base,
137 Offset past, const StringData* name, Attr attrs, bool top,
138 const StringData* docComment, int numParams, bool isGenerator);
139 Func(Unit& unit, PreClass* preClass, int line1,
140 int line2, Offset base, Offset past,
141 const StringData* name, Attr attrs, bool top,
142 const StringData* docComment, int numParams, bool isGenerator);
143 ~Func();
144 static void destroy(Func* func);
146 Func* clone() const;
147 const Func* cloneAndSetClass(Class* cls) const;
149 void validate() const {
150 #ifdef DEBUG
151 assert(this && m_magic == kMagic);
152 #endif
155 FuncId getFuncId() const {
156 assert(m_funcId != InvalidId);
157 return m_funcId;
159 void setFuncId(FuncId id);
160 void setNewFuncId();
162 void rename(const StringData* name);
163 int numSlotsInFrame() const {
164 return shared()->m_numLocals + shared()->m_numIterators * kNumIterCells;
166 Id lookupVarId(const StringData* name) const;
169 * Return true if Offset o is inside the protected region of a fault
170 * funclet for iterId, otherwise false. itRef will be set to true if
171 * the iterator was initialized with MIterInit*, false if the iterator
172 * was initialized with IterInit*.
174 bool checkIterScope(Offset o, Id iterId, bool& itRef) const;
177 * Find the first EHEnt that covers a given offset, or return null.
179 const EHEnt* findEH(Offset o) const;
182 * Locate FPI regions by offset.
184 const FPIEnt* findFPI(Offset o) const;
185 const FPIEnt* findPrecedingFPI(Offset o) const;
187 void parametersCompat(const PreClass* preClass, const Func* imeth) const;
189 // This can be thought of as "if I look up this Func's name while in fromUnit,
190 // will I always get this Func back?" This is important for the translator: if
191 // this condition holds, it allows for some translation-time optimizations by
192 // making assumptions about where function calls will go.
193 bool isNameBindingImmutable(const Unit* fromUnit) const;
195 void setMaxStackCells(int cells) { m_maxStackCells = cells; }
196 int maxStackCells() const {
197 // All functions have to return something, which pushes at least 1 cell
198 assert(m_maxStackCells > 0);
199 return m_maxStackCells;
202 bool byRef(int32_t arg) const;
203 bool mustBeRef(int32_t arg) const;
204 void prettyPrint(std::ostream& out) const;
206 bool isPseudoMain() const { return m_name->empty(); }
207 bool isBuiltin() const { return (bool)info(); }
208 bool isMethod() const {
209 return !isPseudoMain() && (bool)cls();
211 bool isTraitMethod() const {
212 PreClass* pcls = preClass();
213 return pcls && (pcls->attrs() & AttrTrait);
215 bool isNonClosureMethod() const {
216 return isMethod() && !isClosureBody();
218 bool isPublic() const { return bool(m_attrs & AttrPublic); }
219 bool isStatic() const { return bool(m_attrs & AttrStatic); }
220 bool isAbstract() const { return bool(m_attrs & AttrAbstract); }
221 bool isUnique() const { return bool(m_attrs & AttrUnique); }
222 bool isDestructor() const {
223 return !strcmp(m_name->data(), "__destruct");
225 bool isPersistent() const { return m_attrs & AttrPersistent; }
226 static bool isMagicCallMethodName(const StringData* name) {
227 return name->isame(s___call) || name->isame(s___callStatic);
229 bool isMagicCallMethod() const {
230 return m_name->isame(s___call);
232 bool isMagicCallStaticMethod() const {
233 return m_name->isame(s___callStatic);
235 bool isMagic() const {
236 return isMagicCallMethod() || isMagicCallStaticMethod();
238 static bool isSpecial(const StringData* methName) {
239 return strncmp("86", methName->data(), 2) == 0;
241 bool isNoInjection() const { return bool(m_attrs & AttrNoInjection); }
243 HphpArray* getStaticLocals() const;
244 void getFuncInfo(ClassInfo::MethodInfo* mi) const;
246 Unit* unit() const { return m_unit; }
247 PreClass* preClass() const { return shared()->m_preClass; }
248 Class* cls() const { return m_cls; }
249 void setCls(Class* cls) {
250 m_cls = cls;
251 setFullName();
253 void setClsAndName(Class* cls, const StringData* name) {
254 m_cls = cls;
255 m_name = name;
256 setFullName();
258 Class* baseCls() const { return m_baseCls; }
259 void setBaseCls(Class* baseCls) { m_baseCls = baseCls; }
260 bool hasPrivateAncestor() const { return m_hasPrivateAncestor; }
261 void setHasPrivateAncestor(bool b) { m_hasPrivateAncestor = b; }
262 Id id() const {
263 assert(preClass() == nullptr);
264 return shared()->m_id;
266 Offset base() const { return shared()->m_base; }
267 const inline Opcode* getEntry() const {
268 return m_unit->entry() + shared()->m_base;
270 Offset past() const { return shared()->m_past; }
271 int line1() const { return shared()->m_line1; }
272 int line2() const { return shared()->m_line2; }
273 DataType returnType() const { return shared()->m_returnType; }
274 const SVInfoVec& staticVars() const { return shared()->m_staticVars; }
275 const StringData* name() const {
276 assert(m_name != nullptr);
277 return m_name;
279 CStrRef nameRef() const {
280 assert(m_name != nullptr);
281 return *(String*)(&m_name);
283 const StringData* fullName() const {
284 if (m_fullName == nullptr) return m_name;
285 return m_fullName;
287 CStrRef fullNameRef() const {
288 assert(m_fullName != nullptr);
289 return *(String*)(&m_fullName);
291 // Assembly linkage.
292 static size_t fullNameOffset() {
293 return offsetof(Func, m_fullName);
295 static size_t sharedOffset() {
296 return offsetof(Func, m_shared);
298 static size_t sharedBaseOffset() {
299 return offsetof(SharedData, m_base);
301 char &maybeIntercepted() const { return m_maybeIntercepted; }
302 int numParams() const { return m_numParams; }
303 const ParamInfoVec& params() const { return shared()->m_params; }
304 int numLocals() const { return shared()->m_numLocals; }
306 const StringData* const* localNames() const {
307 return shared()->m_localNames.accessList();
309 Id numNamedLocals() const { return shared()->m_localNames.size(); }
311 // Returns the name of a local variable, or null if this varid is an
312 // unnamed local.
313 const StringData* localVarName(Id id) const {
314 assert(id >= 0);
315 return id < numNamedLocals() ? shared()->m_localNames[id] : 0;
318 const StringData* returnTypeConstraint() const {
319 return shared()->m_retTypeConstraint;
322 int numIterators() const { return shared()->m_numIterators; }
323 const EHEntVec& ehtab() const { return shared()->m_ehtab; }
324 const FPIEntVec& fpitab() const { return shared()->m_fpitab; }
325 Attr attrs() const { return m_attrs; }
326 void setAttrs(Attr attrs) { m_attrs = attrs; }
327 bool top() const { return shared()->m_top; }
328 const StringData* docComment() const { return shared()->m_docComment; }
329 bool isClosureBody() const { return shared()->m_isClosureBody; }
330 bool isClonedClosure() const;
331 bool isGenerator() const { return shared()->m_isGenerator; }
332 bool isGeneratorFromClosure() const {
333 return shared()->m_isGeneratorFromClosure;
336 * If this function is a generator then it is implemented as a simple
337 * function that just returns another function. hasGeneratorAsBody() will be
338 * true for the outer functions and isGenerator() is true for the
339 * inner function.
341 * This isn't a pointer to the function itself because it was too hard to
342 * hook the parts up. If you know more and need it, there probably isn't a
343 * technical reason not to.
345 bool hasGeneratorAsBody() const { return shared()->m_hasGeneratorAsBody; }
346 const Func* getGeneratorBody(const StringData* name) const;
347 bool hasStaticLocals() const { return !shared()->m_staticVars.empty(); }
348 int numStaticLocals() const { return shared()->m_staticVars.size(); }
349 const ClassInfo::MethodInfo* info() const { return shared()->m_info; }
350 bool isAllowOverride() const;
351 const BuiltinFunction& nativeFuncPtr() const {
352 return shared()->m_nativeFuncPtr;
354 const BuiltinFunction& builtinFuncPtr() const {
355 return shared()->m_builtinFuncPtr;
357 const UserAttributeMap& userAttributes() const {
358 return shared()->m_userAttributes;
362 * Closure's __invoke()s have an extra pointer used to keep cloned versions
363 * of themselves with different contexts.
365 * const here is the equivalent of "mutable" since this is just a cache
367 Func*& nextClonedClosure() const {
368 assert(isClosureBody() || isGeneratorFromClosure());
369 return ((Func**)this)[-1];
372 static void* allocFuncMem(
373 const StringData* name, int numParams, bool needsNextClonedClosure);
375 void setPrologue(int index, unsigned char* tca) {
376 m_prologueTable[index] = tca;
378 void setFuncBody(unsigned char* fb) {
379 m_funcBody = fb;
381 unsigned char* getFuncBody() const {
382 return m_funcBody;
384 unsigned char* getPrologue(int index) const {
385 return m_prologueTable[index];
387 int numPrologues() const {
388 return getMaxNumPrologues(m_numParams);
390 static int getMaxNumPrologues(int numParams) {
391 // maximum number of prologues is numParams+2. The extra 2 are for
392 // the case where the number of actual params equals numParams and
393 // the case where the number of actual params is greater than
394 // numParams.
395 return numParams + 2;
397 void resetPrologues() {
398 // Useful when killing code; forget what we've learned about the contents
399 // of the translation cache.
400 initPrologues(m_numParams, isGenerator());
403 const NamedEntity* getNamedEntity() const {
404 assert(!m_shared->m_preClass);
405 return m_namedEntity;
407 Slot methodSlot() const {
408 assert(m_cls);
409 return m_methodSlot;
411 void setMethodSlot(Slot s) {
412 assert(m_cls);
413 m_methodSlot = s;
415 Func** getCachedAddr();
416 Func* getCached() { return *getCachedAddr(); }
417 void setCached();
418 unsigned getCachedOffset() const { return m_cachedOffset; }
420 public: // Offset accessors for the translator.
421 #define X(f) static size_t f##Off() { return offsetof(Func, m_##f); }
422 X(attrs);
423 X(unit);
424 X(cls);
425 X(numParams);
426 X(refBitVec);
427 X(fullName);
428 X(prologueTable);
429 X(maybeIntercepted);
430 X(maxStackCells);
431 X(funcBody);
432 #undef X
434 private:
435 typedef IndexedStringMap<const StringData*,true,Id> NamedLocalsMap;
437 struct SharedData : public AtomicCountable {
438 PreClass* m_preClass;
439 Id m_id;
440 Offset m_base;
441 Id m_numLocals;
442 Id m_numIterators;
443 Offset m_past;
444 int m_line1;
445 int m_line2;
446 DataType m_returnType;
447 const ClassInfo::MethodInfo* m_info; // For builtins.
448 uint64_t* m_refBitVec;
449 BuiltinFunction m_builtinFuncPtr;
450 BuiltinFunction m_nativeFuncPtr;
451 ParamInfoVec m_params; // m_params[i] corresponds to parameter i.
452 NamedLocalsMap m_localNames; // includes parameter names
453 SVInfoVec m_staticVars;
454 EHEntVec m_ehtab;
455 FPIEntVec m_fpitab;
456 const StringData* m_docComment;
457 bool m_top : 1; // Defined at top level.
458 bool m_isClosureBody : 1;
459 bool m_isGenerator : 1;
460 bool m_isGeneratorFromClosure : 1;
461 bool m_hasGeneratorAsBody : 1;
462 UserAttributeMap m_userAttributes;
463 const StringData* m_retTypeConstraint;
464 SharedData(PreClass* preClass, Id id, Offset base,
465 Offset past, int line1, int line2, bool top,
466 const StringData* docComment);
467 ~SharedData();
468 void atomicRelease();
470 typedef AtomicSmartPtr<SharedData> SharedDataPtr;
472 static const int kBitsPerQword = 64;
473 static const StringData* s___call;
474 static const StringData* s___callStatic;
475 static const int kMagic = 0xba5eba11;
477 private:
478 void setFullName();
479 void init(int numParams, bool isGenerator);
480 void initPrologues(int numParams, bool isGenerator);
481 void appendParam(bool ref, const ParamInfo& info,
482 std::vector<ParamInfo>& pBuilder);
483 void allocVarId(const StringData* name);
484 const SharedData* shared() const { return m_shared.get(); }
485 SharedData* shared() { return m_shared.get(); }
486 const Func* findCachedClone(Class* cls) const;
488 private:
489 Unit* m_unit;
490 Class* m_cls; // The Class that provided this method implementation
491 Class* m_baseCls; // The first Class in the inheritance hierarchy that
492 // declared this method; note that this may be an abstract
493 // class that did not provide an implementation
494 const StringData* m_name;
495 const StringData* m_fullName;
496 SharedDataPtr m_shared;
497 union {
498 const NamedEntity* m_namedEntity;
499 Slot m_methodSlot;
501 uint64_t* m_refBitVec;
502 public: // used by Unit
503 unsigned m_cachedOffset;
504 private:
505 #ifdef DEBUG
506 int m_magic; // For asserts only.
507 #endif
508 int m_maxStackCells;
509 int m_numParams;
510 Attr m_attrs;
511 FuncId m_funcId;
512 bool m_hasPrivateAncestor : 1; // This flag indicates if any of this
513 // Class's ancestors provide a
514 // "private" implementation for this
515 // method
516 // TODO(#1114385) intercept should work via invalidation.
517 mutable char m_maybeIntercepted; // -1, 0, or 1. Accessed atomically.
518 unsigned char* volatile m_funcBody; // Accessed from assembly.
519 // This must be the last field declared in this structure
520 // and the Func class should not be inherited from.
521 unsigned char* volatile m_prologueTable[kNumFixedPrologues];
524 class FuncEmitter {
525 public:
526 typedef std::vector<Func::SVInfo> SVInfoVec;
527 typedef std::vector<EHEnt> EHEntVec;
528 typedef std::vector<FPIEnt> FPIEntVec;
530 struct ParamInfo: public Func::ParamInfo {
531 ParamInfo() : m_ref(false) {}
533 void setRef(bool ref) { m_ref = ref; }
534 bool ref() const { return m_ref; }
536 template<class SerDe> void serde(SerDe& sd) {
537 Func::ParamInfo* parent = this;
538 parent->serde(sd);
539 sd(m_ref);
542 private:
543 bool m_ref; // True if parameter is passed by reference.
545 typedef std::vector<ParamInfo> ParamInfoVec;
547 FuncEmitter(UnitEmitter& ue, int sn, Id id, const StringData* n);
548 FuncEmitter(UnitEmitter& ue, int sn, const StringData* n,
549 PreClassEmitter* pce);
550 ~FuncEmitter();
552 void init(int line1, int line2, Offset base, Attr attrs, bool top,
553 const StringData* docComment);
554 void finish(Offset past, bool load);
556 template<class SerDe> void serdeMetaData(SerDe&);
558 EHEnt& addEHEnt();
559 FPIEnt& addFPIEnt();
561 Id newLocal();
562 void appendParam(const StringData* name, const ParamInfo& info);
563 void setParamFuncletOff(Id id, Offset off) {
564 m_params[id].setFuncletOff(off);
566 void allocVarId(const StringData* name);
567 Id lookupVarId(const StringData* name) const;
568 bool hasVar(const StringData* name) const;
569 Id numParams() const { return m_params.size(); }
571 void setReturnTypeConstraint(const StringData* retTypeConstraint) {
572 m_retTypeConstraint = retTypeConstraint;
575 Id allocIterator();
576 void freeIterator(Id id);
577 void setNumIterators(Id numIterators);
578 Id numIterators() const { return m_numIterators; }
580 Id allocUnnamedLocal();
581 void freeUnnamedLocal(Id id);
582 Id numLocals() const { return m_numLocals; }
583 void setNumLocals(Id numLocals);
585 void setMaxStackCells(int cells) { m_maxStackCells = cells; }
586 void addStaticVar(Func::SVInfo svInfo);
588 UnitEmitter& ue() const { return m_ue; }
589 PreClassEmitter* pce() const { return m_pce; }
590 void setIds(int sn, Id id) {
591 m_sn = sn;
592 m_id = id;
594 int sn() const { return m_sn; }
595 Id id() const {
596 assert(m_pce == nullptr);
597 return m_id;
599 Offset base() const { return m_base; }
600 Offset past() const { return m_past; }
601 const StringData* name() const { return m_name; }
602 const ParamInfoVec& params() const { return m_params; }
603 const EHEntVec& ehtab() const { return m_ehtab; }
604 EHEntVec& ehtab() { return m_ehtab; }
605 const FPIEntVec& fpitab() const { return m_fpitab; }
607 void setAttrs(Attr attrs) { m_attrs = attrs; }
608 Attr attrs() const { return m_attrs; }
610 void setTop(bool top) { m_top = top; }
611 bool top() { return m_top; }
613 bool isPseudoMain() const { return m_name->empty(); }
615 void setIsClosureBody(bool isClosureBody) { m_isClosureBody = isClosureBody; }
616 bool isClosureBody() const { return m_isClosureBody; }
618 void setIsGenerator(bool isGenerator) { m_isGenerator = isGenerator; }
619 bool isGenerator() const { return m_isGenerator; }
621 void setIsGeneratorFromClosure(bool b) { m_isGeneratorFromClosure = b; }
622 bool isGeneratorFromClosure() const { return m_isGeneratorFromClosure; }
624 void setHasGeneratorAsBody(bool b) { m_hasGeneratorAsBody = b; }
625 bool hasGeneratorAsBody() const { return m_hasGeneratorAsBody; }
627 void setContainsCalls() { m_containsCalls = true; }
629 void addUserAttribute(const StringData* name, TypedValue tv);
631 void commit(RepoTxn& txn) const;
632 Func* create(Unit& unit, PreClass* preClass = nullptr) const;
634 void setBuiltinFunc(const ClassInfo::MethodInfo* info,
635 BuiltinFunction bif, BuiltinFunction nif, Offset base);
637 private:
638 void sortEHTab();
639 void sortFPITab(bool load);
641 UnitEmitter& m_ue;
642 PreClassEmitter* m_pce;
643 int m_sn;
644 Id m_id;
645 Offset m_base;
646 Offset m_past;
647 int m_line1;
648 int m_line2;
649 const StringData* m_name;
651 ParamInfoVec m_params;
652 Func::NamedLocalsMap::Builder m_localNames;
653 Id m_numLocals;
654 int m_numUnnamedLocals;
655 int m_activeUnnamedLocals;
656 Id m_numIterators;
657 Id m_nextFreeIterator;
658 int m_maxStackCells;
659 SVInfoVec m_staticVars;
661 const StringData* m_retTypeConstraint;
663 EHEntVec m_ehtab;
664 FPIEntVec m_fpitab;
666 Attr m_attrs;
667 DataType m_returnType;
668 bool m_top;
669 const StringData* m_docComment;
670 bool m_isClosureBody;
671 bool m_isGenerator;
672 bool m_isGeneratorFromClosure;
673 bool m_hasGeneratorAsBody;
674 bool m_containsCalls;
676 Func::UserAttributeMap m_userAttributes;
678 const ClassInfo::MethodInfo* m_info;
679 BuiltinFunction m_builtinFuncPtr;
680 BuiltinFunction m_nativeFuncPtr;
683 class FuncRepoProxy : public RepoProxy {
684 friend class Func;
685 friend class FuncEmitter;
686 public:
687 explicit FuncRepoProxy(Repo& repo);
688 ~FuncRepoProxy();
689 void createSchema(int repoId, RepoTxn& txn);
691 #define FRP_IOP(o) FRP_OP(Insert##o, insert##o)
692 #define FRP_GOP(o) FRP_OP(Get##o, get##o)
693 #define FRP_OPS \
694 FRP_IOP(Func) \
695 FRP_GOP(Funcs)
696 class InsertFuncStmt : public RepoProxy::Stmt {
697 public:
698 InsertFuncStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
699 void insert(const FuncEmitter& fe,
700 RepoTxn& txn, int64_t unitSn, int funcSn, Id preClassId,
701 const StringData* name, bool top);
703 class GetFuncsStmt : public RepoProxy::Stmt {
704 public:
705 GetFuncsStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
706 void get(UnitEmitter& ue);
708 #define FRP_OP(c, o) \
709 public: \
710 c##Stmt& o(int repoId) { return *m_##o[repoId]; } \
711 private: \
712 c##Stmt m_##o##Local; \
713 c##Stmt m_##o##Central; \
714 c##Stmt* m_##o[RepoIdCount];
715 FRP_OPS
716 #undef FRP_OP
721 #endif