Use AtomicHashMap for NamedEntities and StaticStrings
[hiphop-php.git] / hphp / runtime / vm / unit.h
blobff6326ebd32482d8a8592a49724338335a525661
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_UNIT_H_
18 #define incl_HPHP_VM_UNIT_H_
20 // Expects that runtime/vm/core_types.h is already included.
21 #include "hphp/runtime/base/runtime_option.h"
22 #include "hphp/runtime/vm/hhbc.h"
23 #include "hphp/runtime/vm/class.h"
24 #include "hphp/runtime/vm/repo_helpers.h"
25 #include "hphp/runtime/vm/named_entity.h"
26 #include "hphp/runtime/base/array/hphp_array.h"
27 #include "hphp/util/range.h"
28 #include "hphp/util/parser/location.h"
29 #include "hphp/runtime/base/md5.h"
30 #include "hphp/util/tiny_vector.h"
32 namespace HPHP {
33 // Forward declarations.
34 namespace Compiler { class Peephole; }
35 struct ActRec;
37 class Func;
38 class FuncEmitter;
39 class Repo;
40 class FuncDict;
41 class Unit;
43 enum UnitOrigin {
44 UnitOriginFile = 0,
45 UnitOriginEval = 1
48 enum UnitMergeKind {
49 // UnitMergeKindClass is required to be 0 for correctness.
50 UnitMergeKindClass = 0,
51 UnitMergeKindUniqueDefinedClass = 1,
52 // Top level, scalar defines in the unit
53 UnitMergeKindDefine = 2,
54 // Top level, scalar defines that will be loaded once
55 // and preserved from request to request
56 UnitMergeKindPersistentDefine = 3,
57 UnitMergeKindGlobal = 4,
58 // 5 is available
59 UnitMergeKindReqDoc = 6,
60 UnitMergeKindDone = 7,
61 // We cannot add more kinds here; this has to fit in 3 bits.
64 enum UnitMergeState {
65 UnitMergeStateUnmerged = 0,
66 UnitMergeStateMerging = 1,
67 UnitMergeStateMerged = 2,
68 UnitMergeStateUniqueFuncs = 4,
69 UnitMergeStateNeedsCompact = 8,
70 UnitMergeStateEmpty = 32
73 inline bool ALWAYS_INLINE isMergeKindReq(UnitMergeKind k) {
74 return k == UnitMergeKindReqDoc;
77 struct UnitMergeInfo {
78 typedef IterRange<Func* const*> FuncRange;
79 typedef IterRange<Func**> MutableFuncRange;
81 unsigned m_firstHoistableFunc;
82 unsigned m_firstHoistablePreClass;
83 unsigned m_firstMergeablePreClass;
84 unsigned m_mergeablesSize;
85 void* m_mergeables[1];
87 static UnitMergeInfo* alloc(size_t num);
89 Func** funcBegin() const {
90 return (Func**)m_mergeables;
92 Func** funcEnd() const {
93 return funcBegin() + m_firstHoistablePreClass;
95 Func** funcHoistableBegin() const {
96 return funcBegin() + m_firstHoistableFunc;
98 MutableFuncRange nonMainFuncs() const {
99 return MutableFuncRange(funcBegin() + 1, funcEnd());
101 MutableFuncRange hoistableFuncs() const {
102 return MutableFuncRange(funcHoistableBegin(), funcEnd());
104 FuncRange funcs() const {
105 return FuncRange(funcBegin(), funcEnd());
107 MutableFuncRange mutableFuncs() {
108 return MutableFuncRange(funcBegin(), funcEnd());
110 void*& mergeableObj(int ix) { return ((void**)m_mergeables)[ix]; }
111 void* mergeableData(int ix) { return (char*)m_mergeables + ix*sizeof(void*); }
114 // Exception handler table entry.
115 class EHEnt {
116 public:
117 enum EHType {
118 EHType_Catch,
119 EHType_Fault
121 EHType m_ehtype;
122 Offset m_base;
123 Offset m_past;
124 int m_iterId;
125 bool m_itRef;
126 int m_parentIndex;
127 Offset m_fault;
128 typedef std::vector<std::pair<Id, Offset> > CatchVec;
129 CatchVec m_catches;
131 template<class SerDe> void serde(SerDe& sd) {
132 sd(m_ehtype)
133 (m_base)
134 (m_past)
135 (m_iterId)
136 (m_fault)
137 (m_itRef)
138 // eh.m_parentIndex is re-computed in sortEHTab, not serialized.
140 if (m_ehtype == EHType_Catch) {
141 sd(m_catches);
146 // Function paramater info region table entry.
147 class FPIEnt {
148 public:
149 Offset m_fpushOff;
150 Offset m_fcallOff;
151 Offset m_fpOff; // evaluation stack depth to current frame pointer
152 int m_parentIndex;
153 int m_fpiDepth;
155 template<class SerDe> void serde(SerDe& sd) {
156 sd(m_fpushOff)(m_fcallOff)(m_fpOff);
157 // These fields are recomputed by sortFPITab:
158 // m_parentIndex;
159 // m_fpiDepth;
163 class FPIEntComp {
164 public:
165 bool operator() (const FPIEnt &fpi1, const FPIEnt &fpi2) {
166 return fpi1.m_fpushOff < fpi2.m_fpushOff;
170 class SourceLoc {
171 public:
172 SourceLoc() : line0(1), char0(1), line1(1), char1(1) {}
173 explicit SourceLoc(const Location& l) { setLoc(&l); }
175 int line0;
176 int char0;
177 int line1;
178 int char1;
180 // {1, 1, 1, 1} is a special "invalid" value.
181 void reset() {
182 line0 = char0 = line1 = char1 = 1;
185 bool valid() {
186 return line0 != 1 || char0 != 1 || line1 != 1 || char1 != 1;
189 void setLoc(const Location *l) {
190 line0 = l->line0;
191 char0 = l->char0;
192 line1 = l->line1;
193 char1 = l->char1;
196 bool same(const SourceLoc *l) const {
197 return (this == l) ||
198 (line0 == l->line0 && char0 == l->char0 &&
199 line1 == l->line1 && char1 == l->char1);
202 bool operator==(const SourceLoc &l) const {
203 return same(&l);
207 class OffsetRange {
208 public:
209 OffsetRange() : m_base(0), m_past(0) {}
210 OffsetRange(Offset base, Offset past) : m_base(base), m_past(past) {}
211 Offset m_base;
212 Offset m_past;
214 typedef std::vector<OffsetRange> OffsetRangeVec;
216 template<typename T>
217 class TableEntry {
218 public:
219 TableEntry() : m_pastOffset(0) {}
221 TableEntry(Offset pastOffset, T val)
222 : m_pastOffset(pastOffset), m_val(val) {}
223 Offset pastOffset() const { return m_pastOffset; }
224 T val() const { return m_val; }
225 bool operator <(const TableEntry& other) const {
226 return m_pastOffset < other.m_pastOffset;
229 template<class SerDe> void serde(SerDe& sd) { sd(m_pastOffset)(m_val); }
231 private:
232 Offset m_pastOffset;
233 T m_val;
236 typedef TableEntry<int> LineEntry;
237 typedef std::vector<LineEntry> LineTable;
238 typedef TableEntry<const Func*> FuncEntry;
239 typedef std::vector<FuncEntry> FuncTable;
242 * Each Unit has one of these structs for each DefCns instruction. If
243 * the value is not known at Unit emission time, the 'value' field
244 * will be KindOfUninit. The 'owner' field is an opaque blob used by
245 * Units and ExecutionContexes to identify which PreConsts belong to
246 * them on destruction.
248 * If user code contains a call to define($s, ...) where $s is not a
249 * string known at compile time, it will be left as a normal call to
250 * the function define. If that code is ever executed, a PreConst will
251 * be created by that request's g_vmContext and destroyed at the end
252 * of the request.
254 struct PreConst {
255 TypedValue value;
256 void* owner;
257 const StringData* name;
260 typedef std::vector<PreConst> PreConstVec;
263 * This is the runtime representation of a typedef. Typedefs are only
264 * allowed when hip hop extensions are enabled.
266 * The m_kind field is KindOfObject whenever the typedef is basically
267 * just a name. At runtime we still might resolve this name to
268 * another typedef, becoming a typedef for KindOfArray or something in
269 * that request.
271 struct Typedef {
272 const StringData* m_name;
273 const StringData* m_value;
274 DataType m_kind;
276 template<class SerDe> void serde(SerDe& sd) {
277 sd(m_name)
278 (m_value)
279 (m_kind)
284 //==============================================================================
285 // (const StringData*) versus (StringData*)
287 // All (const StringData*) values are static strings that came from e.g.
288 // StringData::GetStaticString(). Therefore no reference counting is required.
290 //==============================================================================
293 * Metadata about a compilation unit.
295 * Contains the list of PreClasses and global functions, along with a
296 * special function called the 'pseudo-main', which is logically
297 * invoked (modulo optimizations that avoid it) during execution when
298 * the unit is included/required.
300 struct Unit {
301 friend class UnitEmitter;
302 friend class UnitRepoProxy;
303 friend class FuncDict;
305 typedef UnitMergeInfo::FuncRange FuncRange;
306 typedef UnitMergeInfo::MutableFuncRange MutableFuncRange;
308 typedef hphp_hash_map<const Class*, Func*,
309 pointer_hash<Class> > PseudoMainCacheMap;
311 class MetaInfo {
312 public:
313 enum Kind {
314 None,
315 String,
316 Class,
317 NopOut,
320 * Marks types that are proven to be a particular type by static
321 * analysis. Guards are not needed in these cases.
323 DataTypeInferred,
326 * Marks types that are predicted by static analysis. Guards
327 * will still be needed in case the prediction is wrong.
329 DataTypePredicted,
331 GuardedThis,
332 GuardedCls,
333 NoSurprise,
334 ArrayCapacity,
337 * Information about the known class of a property base in the
338 * middle of a vector instruction.
340 * In this case, m_arg is the index of the member code for the
341 * relevant property dim. (Unlike other cases, m_arg is not an
342 * index into the instruction inputs in NormalizedInstruction.)
344 * Whatever the base is when processing that member code will be
345 * an object of the supplied class type (or a null).
347 MVecPropClass,
350 * At a Ret{C,V} site, indicates which locals are known not to
351 * be reference counted. m_data is the id of the local variable
352 * that cannot be reference counted at this point.
354 NonRefCounted,
358 * This flag is used to mark that m_arg is an index into an
359 * MVector input list. (We need to know this so we can bump the
360 * indexes different amounts depending on the instruction type;
361 * see applyInputMetaData.)
363 static const int VectorArg = 1 << 7;
365 MetaInfo(Kind k, int a, Id d) : m_kind(k), m_arg(a), m_data(d) {
366 assert((int)m_arg == a);
368 MetaInfo() : m_kind(None), m_arg(-1), m_data(0) {}
371 * m_arg indicates which input the MetaInfo applies to.
373 * For instructions taking vector immediates, it is an index into
374 * the immediate elements, excluding any MW members (and including
375 * the base). (This is currently even if the instruction takes
376 * other stack arguments.)
378 Kind m_kind;
379 uint8_t m_arg;
380 Id m_data;
383 class MetaHandle {
385 The meta-data in Unit::m_bc_meta is stored as:
387 Offset <num entries>
388 Offset byte-code-offset-1
389 Offset byte-code-offset-2
391 Offset byte-code_offset-n
392 Offset INT_MAX # sentinel
393 Offset data-offset-1
394 Offset data-offset-2
396 Offset data-offset-n
397 Offset m_bc_meta_len # sentinel
398 uint8 m_kind1
399 uint8 m_arg1
400 VSI m_data1
402 uint8 m_kind-n
403 uint8 m_arg-n
404 VSI m_data-n
406 public:
407 MetaHandle() : index(nullptr), cur(0) {}
408 bool findMeta(const Unit* unit, Offset offset);
409 bool nextArg(MetaInfo& info);
410 private:
411 const Offset* index;
412 unsigned cur;
413 const uint8_t *ptr;
416 Unit();
417 ~Unit();
418 void* operator new(size_t sz);
419 void operator delete(void* p, size_t sz);
421 int repoId() const { return m_repoId; }
422 int64_t sn() const { return m_sn; }
424 PC entry() const { return m_bc; }
425 Offset bclen() const { return m_bclen; }
426 PC at(const Offset off) const {
427 assert(off >= 0 && off <= Offset(m_bclen));
428 return m_bc + off;
430 Offset offsetOf(const Opcode* op) const {
431 assert(op >= m_bc && op <= (m_bc + m_bclen));
432 return op - m_bc;
435 const StringData* filepath() const {
436 assert(m_filepath);
437 return m_filepath;
439 CStrRef filepathRef() const {
440 assert(m_filepath);
441 return *(String*)(&m_filepath);
443 const StringData* dirpath() const {
444 assert(m_dirpath);
445 return m_dirpath;
448 MD5 md5() const { return m_md5; }
450 static NamedEntity* GetNamedEntity(const StringData *)
451 __attribute__((__flatten__));
452 static size_t GetNamedEntityTableSize();
453 static Array getUserFunctions();
454 static Array getClassesInfo();
455 static Array getInterfacesInfo();
456 static Array getTraitsInfo();
458 size_t numLitstrs() const {
459 return m_namedInfo.size();
461 StringData* lookupLitstrId(Id id) const {
462 assert(id >= 0 && id < Id(m_namedInfo.size()));
463 return const_cast<StringData*>(m_namedInfo[id].first);
466 const NamedEntity* lookupNamedEntityId(Id id) const {
467 return lookupNamedEntityPairId(id).second;
470 const NamedEntityPair& lookupNamedEntityPairId(Id id) const {
471 assert(id < Id(m_namedInfo.size()));
472 const NamedEntityPair &ne = m_namedInfo[id];
473 assert(ne.first);
474 if (UNLIKELY(!ne.second)) {
475 const_cast<const NamedEntity*&>(ne.second) = GetNamedEntity(ne.first);
477 return ne;
480 size_t numArrays() const {
481 return m_arrays.size();
483 ArrayData* lookupArrayId(Id id) const {
484 return const_cast<ArrayData*>(m_arrays.at(id));
487 static Func *lookupFunc(const NamedEntity *ne);
488 static Func *lookupFunc(const StringData *funcName);
489 static Func *loadFunc(const NamedEntity *ne, const StringData* name);
490 static Func *loadFunc(const StringData* name);
492 static Class* defClass(const HPHP::PreClass* preClass,
493 bool failIsFatal = true);
494 void defTypedef(Id id);
496 static TypedValue* lookupCns(const StringData* cnsName);
497 static TypedValue* lookupPersistentCns(const StringData* cnsName);
498 static TypedValue* loadCns(const StringData* cnsName);
499 static bool defCns(const StringData* cnsName, const TypedValue* value,
500 bool persistent = false);
501 static uint64_t defCnsHelper(uint64_t ch,
502 const TypedValue* value,
503 const StringData* cnsName);
504 static void defDynamicSystemConstant(const StringData* cnsName,
505 const void* data);
506 static bool defCnsDynamic(const StringData* cnsName, TypedValue* value);
509 * Find the Class* for a defined class corresponding to the name
510 * `clsName'.
512 * Returns: nullptr if the class of the given name is not yet
513 * defined in this request.
515 static Class *lookupClass(const StringData *clsName) {
516 return lookupClass(GetNamedEntity(clsName));
520 * Find the Class* for a defined class with name mapped to the
521 * supplied NamedEntity.
523 * Returns: nullptr if the class is not yet defined in this request.
525 static Class *lookupClass(const NamedEntity *ne) {
526 Class* cls;
527 if (LIKELY((cls = ne->getCachedClass()) != nullptr)) {
528 return cls;
530 return nullptr;
534 * Same as lookupClass, except if it's not defined *and* is unique,
535 * return the Class* anyway.
537 * The point of this is that when jitting code before a unique class
538 * is defined, we can often still burn the Class* into the TC, since
539 * it will be defined by the time the code that needs the Class*
540 * runs (via autoload or whatnot).
542 static Class *lookupUniqueClass(const NamedEntity *ne) {
543 Class* cls = ne->clsList();
544 if (LIKELY(cls != nullptr)) {
545 if (cls->attrs() & AttrUnique && RuntimeOption::RepoAuthoritative) {
546 return cls;
548 return cls->getCached();
550 return nullptr;
553 static Class *lookupUniqueClass(const StringData *clsName) {
554 return lookupUniqueClass(GetNamedEntity(clsName));
557 static Class *loadClass(const NamedEntity *ne,
558 const StringData *name);
560 static Class *loadClass(const StringData *name) {
561 return loadClass(GetNamedEntity(name), name);
564 static Class *loadMissingClass(const NamedEntity *ne,
565 const StringData *name);
567 static Class* getClass(const StringData* name, bool tryAutoload) {
568 return getClass(GetNamedEntity(name), name, tryAutoload);
571 static Class* getClass(const NamedEntity *ne, const StringData *name,
572 bool tryAutoload);
573 static bool classExists(const StringData* name, bool autoload,
574 Attr typeAttrs);
576 const PreConst* lookupPreConstId(Id id) const {
577 assert(id < Id(m_preConsts.size()));
578 return &m_preConsts[id];
581 bool compileTimeFatal(const StringData*& msg, int& line) const;
582 const TypedValue *getMainReturn() const {
583 return &m_mainReturn;
585 private:
586 template <bool debugger>
587 void mergeImpl(void* tcbase, UnitMergeInfo* mi);
588 public:
589 Func* firstHoistable() const {
590 return *m_mergeInfo->funcHoistableBegin();
592 Func* getMain(Class* cls = nullptr) const;
593 // Ranges for iterating over functions.
594 MutableFuncRange nonMainFuncs() const {
595 return m_mergeInfo->nonMainFuncs();
597 MutableFuncRange hoistableFuncs() const {
598 return m_mergeInfo->hoistableFuncs();
600 void renameFunc(const StringData* oldName, const StringData* newName);
601 static void loadFunc(const Func *func);
602 FuncRange funcs() const {
603 return m_mergeInfo->funcs();
605 MutableFuncRange mutableFuncs() {
606 return m_mergeInfo->mutableFuncs();
608 Func* lookupFuncId(Id id) const {
609 assert(id < Id(m_mergeInfo->m_firstHoistablePreClass));
610 return m_mergeInfo->funcBegin()[id];
612 size_t numPreClasses() const {
613 return (size_t)m_preClasses.size();
615 PreClass* lookupPreClassId(Id id) const {
616 assert(id < Id(m_preClasses.size()));
617 return m_preClasses[id].get();
619 typedef std::vector<PreClassPtr> PreClassPtrVec;
620 typedef Range<PreClassPtrVec> PreClassRange;
621 void initialMerge();
622 void merge();
623 PreClassRange preclasses() const {
624 return PreClassRange(m_preClasses);
626 bool mergeClasses() const;
628 int getLineNumber(Offset pc) const;
629 bool getSourceLoc(Offset pc, SourceLoc& sLoc) const;
630 bool getOffsetRanges(int line, OffsetRangeVec& offsets) const;
631 bool getOffsetRange(Offset pc, OffsetRange& range) const;
633 Opcode getOpcode(size_t instrOffset) const {
634 assert(instrOffset < m_bclen);
635 return (Opcode)m_bc[instrOffset];
638 const Func* getFunc(Offset pc) const;
639 void setCacheId(unsigned id) {
640 m_cacheOffset = id >> 3;
641 m_cacheMask = 1 << (id & 7);
643 bool isMergeOnly() const { return m_mergeOnly; }
644 void clearMergeOnly() { m_mergeOnly = false; }
645 void* replaceUnit() const;
646 public:
647 static Mutex s_classesMutex;
649 struct PrintOpts {
650 PrintOpts()
651 : startOffset(kInvalidOffset)
652 , stopOffset(kInvalidOffset)
653 , showLines(true)
654 , indentSize(1)
657 PrintOpts& range(Offset start, Offset stop) {
658 startOffset = start;
659 stopOffset = stop;
660 return *this;
663 PrintOpts& noLineNumbers() {
664 showLines = false;
665 return *this;
668 PrintOpts& indent(int i) {
669 indentSize = i;
670 return *this;
673 Offset startOffset;
674 Offset stopOffset;
675 bool showLines;
676 int indentSize;
679 void prettyPrint(std::ostream&, PrintOpts = PrintOpts()) const;
680 std::string toString() const;
682 public: // Translator field access
683 static size_t bcOff() { return offsetof(Unit, m_bc); }
685 private:
686 // pseudoMain's return value, or KindOfUninit if its not known.
687 TypedValue m_mainReturn;
688 int64_t m_sn;
689 uchar const* m_bc;
690 size_t m_bclen;
691 uchar const* m_bc_meta;
692 size_t m_bc_meta_len;
693 const StringData* m_filepath;
694 const StringData* m_dirpath;
695 MD5 m_md5;
696 std::vector<NamedEntityPair> m_namedInfo;
697 std::vector<const ArrayData*> m_arrays;
698 PreClassPtrVec m_preClasses;
699 FixedVector<Typedef> m_typedefs;
700 UnitMergeInfo* m_mergeInfo;
701 unsigned m_cacheOffset;
702 int8_t m_repoId;
703 uint8_t m_mergeState;
704 uint8_t m_cacheMask;
705 bool m_mergeOnly;
706 LineTable m_lineTable;
707 FuncTable m_funcTable;
708 PreConstVec m_preConsts;
709 mutable PseudoMainCacheMap *m_pseudoMainCache;
712 class UnitEmitter {
713 friend class UnitRepoProxy;
714 friend class ::HPHP::Compiler::Peephole;
715 public:
716 explicit UnitEmitter(const MD5& md5);
717 ~UnitEmitter();
719 int repoId() const { return m_repoId; }
720 void setRepoId(int repoId) { m_repoId = repoId; }
721 int64_t sn() const { return m_sn; }
722 void setSn(int64_t sn) { m_sn = sn; }
723 Offset bcPos() const { return (Offset)m_bclen; }
724 void setBc(const uchar* bc, size_t bclen);
725 void setBcMeta(const uchar* bc_meta, size_t bc_meta_len);
726 const StringData* getFilepath() { return m_filepath; }
727 void setFilepath(const StringData* filepath) { m_filepath = filepath; }
728 void setMainReturn(const TypedValue* v) { m_mainReturn = *v; }
729 void setMergeOnly(bool b) { m_mergeOnly = b; }
730 const MD5& md5() const { return m_md5; }
731 Id addPreConst(const StringData* name, const TypedValue& value);
732 Id addTypedef(const Typedef& td);
733 Id mergeLitstr(const StringData* litstr);
734 Id mergeArray(ArrayData* a, const StringData* key=nullptr);
735 FuncEmitter* getMain();
736 void initMain(int line1, int line2);
737 FuncEmitter* newFuncEmitter(const StringData* n, bool top);
738 void appendTopEmitter(FuncEmitter* func);
739 FuncEmitter* newMethodEmitter(const StringData* n, PreClassEmitter* pce);
740 PreClassEmitter* newPreClassEmitter(const StringData* n,
741 PreClass::Hoistable hoistable);
742 PreClassEmitter* pce(Id preClassId) { return m_pceVec[preClassId]; }
745 * Record source location information for the last chunk of bytecode
746 * added to this UnitEmitter. Adjacent regions associated with the
747 * same source line will be collapsed as this is created.
749 void recordSourceLocation(const Location *sLoc, Offset start);
752 * Adds a new FuncEmitter to the unit. You can only do this once
753 * for the FuncEmitter (after you are done setting it up). Also,
754 * all FuncEmitter's added to the unit must not overlap.
756 * Takes ownership of `fe'.
758 void recordFunction(FuncEmitter *fe);
760 private:
761 template<class T>
762 void emitImpl(T n, int64_t pos) {
763 uchar *c = (uchar*)&n;
764 if (pos == -1) {
765 // Make sure m_bc is large enough.
766 while (m_bclen + sizeof(T) > m_bcmax) {
767 m_bc = (uchar*)realloc(m_bc, m_bcmax << 1);
768 m_bcmax <<= 1;
770 memcpy(&m_bc[m_bclen], c, sizeof(T));
771 m_bclen += sizeof(T);
772 } else {
773 assert(pos + sizeof(T) <= m_bclen);
774 for (uint i = 0; i < sizeof(T); ++i) {
775 m_bc[pos + i] = c[i];
779 public:
780 void emitOp(Op op, int64_t pos = -1) {
781 emitByte((uchar)op, pos);
783 void emitByte(uchar n, int64_t pos = -1) { emitImpl(n, pos); }
784 void emitInt32(int n, int64_t pos = -1) { emitImpl(n, pos); }
785 template<typename T> void emitIVA(T n) {
786 if (LIKELY((n & 0x7f) == n)) {
787 emitByte((unsigned char)n << 1);
788 } else {
789 assert((n & 0x7fffffff) == n);
790 emitInt32((n << 1) | 0x1);
793 void emitInt64(int64_t n, int64_t pos = -1) { emitImpl(n, pos); }
794 void emitDouble(double n, int64_t pos = -1) { emitImpl(n, pos); }
795 bool insert(UnitOrigin unitOrigin, RepoTxn& txn);
796 void commit(UnitOrigin unitOrigin);
797 Func* newFunc(const FuncEmitter* fe, Unit& unit, Id id, int line1, int line2,
798 Offset base, Offset past,
799 const StringData* name, Attr attrs, bool top,
800 const StringData* docComment, int numParams,
801 bool isClosureBody, bool isGenerator);
802 Func* newFunc(const FuncEmitter* fe, Unit& unit, PreClass* preClass,
803 int line1, int line2, Offset base, Offset past,
804 const StringData* name, Attr attrs, bool top,
805 const StringData* docComment, int numParams,
806 bool isClosureBody, bool isGenerator);
807 Unit* create();
808 void returnSeen() { m_returnSeen = true; }
809 void pushMergeableClass(PreClassEmitter* e);
810 void pushMergeableInclude(UnitMergeKind kind, const StringData* unitName);
811 void insertMergeableInclude(int ix, UnitMergeKind kind, Id id);
812 void pushMergeableDef(UnitMergeKind kind,
813 const StringData* name, const TypedValue& tv);
814 void insertMergeableDef(int ix, UnitMergeKind kind,
815 Id id, const TypedValue& tv);
816 private:
817 void setLines(const LineTable& lines);
819 private:
820 int m_repoId;
821 int64_t m_sn;
822 static const size_t BCMaxInit = 4096; // Initial bytecode size.
823 size_t m_bcmax;
824 uchar* m_bc;
825 size_t m_bclen;
826 uchar* m_bc_meta;
827 size_t m_bc_meta_len;
828 TypedValue m_mainReturn;
829 const StringData* m_filepath;
830 MD5 m_md5;
831 typedef hphp_hash_map<const StringData*, Id,
832 string_data_hash, string_data_same> LitstrMap;
833 LitstrMap m_litstr2id;
834 std::vector<const StringData*> m_litstrs;
835 typedef hphp_hash_map<const StringData*, Id,
836 string_data_hash, string_data_same> ArrayIdMap;
837 ArrayIdMap m_array2id;
838 typedef struct {
839 const StringData* serialized;
840 const ArrayData* array;
841 } ArrayVecElm;
842 typedef std::vector<ArrayVecElm> ArrayVec;
843 ArrayVec m_arrays;
844 int m_nextFuncSn;
845 bool m_mergeOnly;
846 typedef std::vector<FuncEmitter*> FeVec;
847 FeVec m_fes;
848 typedef hphp_hash_map<const StringData*, FuncEmitter*, string_data_hash,
849 string_data_isame> FuncEmitterMap;
850 FuncEmitterMap m_feMap;
851 typedef hphp_hash_map<const FuncEmitter*, const Func*,
852 pointer_hash<FuncEmitter> > FMap;
853 FMap m_fMap;
854 typedef std::vector<PreClassEmitter*> PceVec;
855 typedef std::vector<Id> IdVec;
856 PceVec m_pceVec;
857 typedef hphp_hash_set<const StringData*, string_data_hash,
858 string_data_isame> HoistedPreClassSet;
859 HoistedPreClassSet m_hoistablePreClassSet;
860 IdVec m_hoistablePceIdVec;
861 typedef std::vector<std::pair<UnitMergeKind, Id> > MergeableStmtVec;
862 MergeableStmtVec m_mergeableStmts;
863 std::vector<std::pair<Id,TypedValue> > m_mergeableValues;
864 bool m_allClassesHoistable;
865 bool m_returnSeen;
867 * m_sourceLocTab and m_feTab are interval maps. Each entry encodes
868 * an open-closed range of bytecode offsets.
870 * The m_sourceLocTab is keyed by the start of each half-open range.
871 * This is to allow appending new bytecode offsets that are part of
872 * the same range to coalesce.
874 * The m_feTab is keyed by the past-the-end offset. This is the
875 * format we'll want it in when we go to create a Unit.
877 std::vector<std::pair<Offset,SourceLoc> > m_sourceLocTab;
878 std::vector<std::pair<Offset,const FuncEmitter*> > m_feTab;
879 PreConstVec m_preConsts;
880 std::vector<Typedef> m_typedefs;
883 class UnitRepoProxy : public RepoProxy {
884 friend class Unit;
885 friend class UnitEmitter;
886 public:
887 explicit UnitRepoProxy(Repo& repo);
888 ~UnitRepoProxy();
889 void createSchema(int repoId, RepoTxn& txn);
890 Unit* load(const std::string& name, const MD5& md5);
892 #define URP_IOP(o) URP_OP(Insert##o, insert##o)
893 #define URP_GOP(o) URP_OP(Get##o, get##o)
894 #define URP_OPS \
895 URP_IOP(Unit) \
896 URP_GOP(Unit) \
897 URP_IOP(UnitLitstr) \
898 URP_GOP(UnitLitstrs) \
899 URP_IOP(UnitArray) \
900 URP_GOP(UnitArrays) \
901 URP_IOP(UnitPreConst) \
902 URP_GOP(UnitPreConsts) \
903 URP_IOP(UnitMergeable) \
904 URP_GOP(UnitMergeables) \
905 URP_IOP(UnitSourceLoc) \
906 URP_GOP(SourceLoc) \
907 URP_GOP(SourceLocPastOffsets) \
908 URP_GOP(SourceLocBaseOffset) \
909 URP_GOP(BaseOffsetAtPCLoc) \
910 URP_GOP(BaseOffsetAfterPCLoc)
911 class InsertUnitStmt : public RepoProxy::Stmt {
912 public:
913 InsertUnitStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
914 void insert(RepoTxn& txn, int64_t& unitSn, const MD5& md5, const uchar* bc,
915 size_t bclen, const uchar* bc_meta, size_t bc_meta_len,
916 const TypedValue* mainReturn, bool mergeOnly,
917 const LineTable& lines,
918 const std::vector<Typedef>&);
920 class GetUnitStmt : public RepoProxy::Stmt {
921 public:
922 GetUnitStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
923 bool get(UnitEmitter& ue, const MD5& md5);
925 class InsertUnitLitstrStmt : public RepoProxy::Stmt {
926 public:
927 InsertUnitLitstrStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
928 void insert(RepoTxn& txn, int64_t unitSn, Id litstrId,
929 const StringData* litstr);
931 class GetUnitLitstrsStmt : public RepoProxy::Stmt {
932 public:
933 GetUnitLitstrsStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
934 void get(UnitEmitter& ue);
936 class InsertUnitArrayStmt : public RepoProxy::Stmt {
937 public:
938 InsertUnitArrayStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
939 void insert(RepoTxn& txn, int64_t unitSn, Id arrayId,
940 const StringData* array);
942 class GetUnitArraysStmt : public RepoProxy::Stmt {
943 public:
944 GetUnitArraysStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
945 void get(UnitEmitter& ue);
947 class InsertUnitPreConstStmt : public RepoProxy::Stmt {
948 public:
949 InsertUnitPreConstStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
950 void insert(RepoTxn& txn, int64_t unitSn, const PreConst& pc,
951 Id id);
953 class GetUnitPreConstsStmt : public RepoProxy::Stmt {
954 public:
955 GetUnitPreConstsStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
956 void get(UnitEmitter& ue);
958 class InsertUnitMergeableStmt : public RepoProxy::Stmt {
959 public:
960 InsertUnitMergeableStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
961 void insert(RepoTxn& txn, int64_t unitSn,
962 int ix, UnitMergeKind kind,
963 Id id, TypedValue *value);
965 class GetUnitMergeablesStmt : public RepoProxy::Stmt {
966 public:
967 GetUnitMergeablesStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
968 void get(UnitEmitter& ue);
970 class InsertUnitSourceLocStmt : public RepoProxy::Stmt {
971 public:
972 InsertUnitSourceLocStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
973 void insert(RepoTxn& txn, int64_t unitSn, Offset pastOffset, int line0,
974 int char0, int line1, int char1);
976 class GetSourceLocStmt : public RepoProxy::Stmt {
977 public:
978 GetSourceLocStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
979 bool get(int64_t unitSn, Offset pc, SourceLoc& sLoc);
981 class GetSourceLocPastOffsetsStmt : public RepoProxy::Stmt {
982 public:
983 GetSourceLocPastOffsetsStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
984 bool get(int64_t unitSn, int line, OffsetRangeVec& ranges);
986 class GetSourceLocBaseOffsetStmt : public RepoProxy::Stmt {
987 public:
988 GetSourceLocBaseOffsetStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
989 bool get(int64_t unitSn, OffsetRange& range);
991 class GetBaseOffsetAtPCLocStmt : public RepoProxy::Stmt {
992 public:
993 GetBaseOffsetAtPCLocStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
994 bool get(int64_t unitSn, Offset pc, Offset& offset);
996 class GetBaseOffsetAfterPCLocStmt : public RepoProxy::Stmt {
997 public:
998 GetBaseOffsetAfterPCLocStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
999 bool get(int64_t unitSn, Offset pc, Offset& offset);
1001 #define URP_OP(c, o) \
1002 public: \
1003 c##Stmt& o(int repoId) { return *m_##o[repoId]; } \
1004 private: \
1005 c##Stmt m_##o##Local; \
1006 c##Stmt m_##o##Central; \
1007 c##Stmt* m_##o[RepoIdCount];
1008 URP_OPS
1009 #undef URP_OP
1013 * AllFuncs
1014 * MutableAllFuncs
1016 * Range over all Func's in a single unit.
1019 struct ConstPreClassMethodRanger {
1020 typedef Func* const* Iter;
1021 typedef const Func* Value;
1022 static Iter get(PreClassPtr pc) {
1023 return pc->methods();
1027 struct MutablePreClassMethodRanger {
1028 typedef Func** Iter;
1029 typedef Func* Value;
1030 static Func** get(PreClassPtr pc) {
1031 return pc->mutableMethods();
1034 template<typename FuncRange,
1035 typename GetMethods>
1036 class AllFuncsImpl {
1037 public:
1038 explicit AllFuncsImpl(const Unit* unit)
1039 : fr(unit->funcs())
1040 , mr(0, 0)
1041 , cr(unit->preclasses())
1043 if (fr.empty()) skip();
1045 bool empty() const { return fr.empty() && mr.empty() && cr.empty(); }
1046 typedef typename GetMethods::Value FuncPtr;
1047 FuncPtr front() const {
1048 assert(!empty());
1049 if (!fr.empty()) return fr.front();
1050 assert(!mr.empty());
1051 return mr.front();
1053 FuncPtr popFront() {
1054 FuncPtr f = !fr.empty() ? fr.popFront() :
1055 !mr.empty() ? mr.popFront() : 0;
1056 assert(f);
1057 if (fr.empty() && mr.empty()) skip();
1058 return f;
1060 private:
1061 void skip() {
1062 assert(fr.empty());
1063 while (!cr.empty() && mr.empty()) {
1064 PreClassPtr c = cr.popFront();
1065 mr = Unit::FuncRange(GetMethods::get(c),
1066 GetMethods::get(c) + c->numMethods());
1070 Unit::FuncRange fr;
1071 Unit::FuncRange mr;
1072 Unit::PreClassRange cr;
1075 typedef AllFuncsImpl<Unit::FuncRange, ConstPreClassMethodRanger> AllFuncs;
1076 typedef AllFuncsImpl<Unit::MutableFuncRange, MutablePreClassMethodRanger> MutableAllFuncs;
1080 * Range over all defined classes.
1082 class AllClasses {
1083 protected:
1084 NamedEntityMap::iterator m_next, m_end;
1085 Class* m_current;
1086 void next();
1087 void skip();
1088 public:
1089 AllClasses();
1090 bool empty() const;
1091 Class* front() const;
1092 Class* popFront();
1095 } // HPHP::VM
1096 #endif