2 +----------------------------------------------------------------------+
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"
33 // Forward declarations.
34 namespace Compiler
{ class Peephole
; }
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,
59 UnitMergeKindReqDoc
= 6,
60 UnitMergeKindDone
= 7,
61 // We cannot add more kinds here; this has to fit in 3 bits.
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.
128 typedef std::vector
<std::pair
<Id
, Offset
> > CatchVec
;
131 template<class SerDe
> void serde(SerDe
& sd
) {
138 // eh.m_parentIndex is re-computed in sortEHTab, not serialized.
140 if (m_ehtype
== EHType_Catch
) {
146 // Function paramater info region table entry.
151 Offset m_fpOff
; // evaluation stack depth to current frame pointer
155 template<class SerDe
> void serde(SerDe
& sd
) {
156 sd(m_fpushOff
)(m_fcallOff
)(m_fpOff
);
157 // These fields are recomputed by sortFPITab:
165 bool operator() (const FPIEnt
&fpi1
, const FPIEnt
&fpi2
) {
166 return fpi1
.m_fpushOff
< fpi2
.m_fpushOff
;
172 SourceLoc() : line0(1), char0(1), line1(1), char1(1) {}
173 explicit SourceLoc(const Location
& l
) { setLoc(&l
); }
180 // {1, 1, 1, 1} is a special "invalid" value.
182 line0
= char0
= line1
= char1
= 1;
186 return line0
!= 1 || char0
!= 1 || line1
!= 1 || char1
!= 1;
189 void setLoc(const Location
*l
) {
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 {
209 OffsetRange() : m_base(0), m_past(0) {}
210 OffsetRange(Offset base
, Offset past
) : m_base(base
), m_past(past
) {}
214 typedef std::vector
<OffsetRange
> OffsetRangeVec
;
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
); }
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
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
272 const StringData
* m_name
;
273 const StringData
* m_value
;
276 template<class SerDe
> void serde(SerDe
& sd
) {
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.
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
;
320 * Marks types that are proven to be a particular type by static
321 * analysis. Guards are not needed in these cases.
326 * Marks types that are predicted by static analysis. Guards
327 * will still be needed in case the prediction is wrong.
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).
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.
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.)
385 The meta-data in Unit::m_bc_meta is stored as:
388 Offset byte-code-offset-1
389 Offset byte-code-offset-2
391 Offset byte-code_offset-n
392 Offset INT_MAX # sentinel
397 Offset m_bc_meta_len # sentinel
407 MetaHandle() : index(nullptr), cur(0) {}
408 bool findMeta(const Unit
* unit
, Offset offset
);
409 bool nextArg(MetaInfo
& info
);
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
));
430 Offset
offsetOf(const Opcode
* op
) const {
431 assert(op
>= m_bc
&& op
<= (m_bc
+ m_bclen
));
435 const StringData
* filepath() const {
439 CStrRef
filepathRef() const {
441 return *(String
*)(&m_filepath
);
443 const StringData
* dirpath() const {
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
];
474 if (UNLIKELY(!ne
.second
)) {
475 const_cast<const NamedEntity
*&>(ne
.second
) = GetNamedEntity(ne
.first
);
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
,
506 static bool defCnsDynamic(const StringData
* cnsName
, TypedValue
* value
);
509 * Find the Class* for a defined class corresponding to the name
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
) {
527 if (LIKELY((cls
= ne
->getCachedClass()) != 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
) {
548 return cls
->getCached();
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
,
573 static bool classExists(const StringData
* name
, bool autoload
,
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
;
586 template <bool debugger
>
587 void mergeImpl(void* tcbase
, UnitMergeInfo
* mi
);
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
;
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;
647 static Mutex s_classesMutex
;
651 : startOffset(kInvalidOffset
)
652 , stopOffset(kInvalidOffset
)
657 PrintOpts
& range(Offset start
, Offset stop
) {
663 PrintOpts
& noLineNumbers() {
668 PrintOpts
& indent(int i
) {
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
); }
686 // pseudoMain's return value, or KindOfUninit if its not known.
687 TypedValue m_mainReturn
;
691 uchar
const* m_bc_meta
;
692 size_t m_bc_meta_len
;
693 const StringData
* m_filepath
;
694 const StringData
* m_dirpath
;
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
;
703 uint8_t m_mergeState
;
706 LineTable m_lineTable
;
707 FuncTable m_funcTable
;
708 PreConstVec m_preConsts
;
709 mutable PseudoMainCacheMap
*m_pseudoMainCache
;
713 friend class UnitRepoProxy
;
714 friend class ::HPHP::Compiler::Peephole
;
716 explicit UnitEmitter(const MD5
& md5
);
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
);
762 void emitImpl(T n
, int64_t pos
) {
763 uchar
*c
= (uchar
*)&n
;
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);
770 memcpy(&m_bc
[m_bclen
], c
, sizeof(T
));
771 m_bclen
+= sizeof(T
);
773 assert(pos
+ sizeof(T
) <= m_bclen
);
774 for (uint i
= 0; i
< sizeof(T
); ++i
) {
775 m_bc
[pos
+ i
] = c
[i
];
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);
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
);
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
);
817 void setLines(const LineTable
& lines
);
822 static const size_t BCMaxInit
= 4096; // Initial bytecode size.
827 size_t m_bc_meta_len
;
828 TypedValue m_mainReturn
;
829 const StringData
* m_filepath
;
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
;
839 const StringData
* serialized
;
840 const ArrayData
* array
;
842 typedef std::vector
<ArrayVecElm
> ArrayVec
;
846 typedef std::vector
<FuncEmitter
*> FeVec
;
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
;
854 typedef std::vector
<PreClassEmitter
*> PceVec
;
855 typedef std::vector
<Id
> IdVec
;
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
;
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
{
885 friend class UnitEmitter
;
887 explicit UnitRepoProxy(Repo
& repo
);
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)
897 URP_IOP(UnitLitstr) \
898 URP_GOP(UnitLitstrs) \
900 URP_GOP(UnitArrays) \
901 URP_IOP(UnitPreConst) \
902 URP_GOP(UnitPreConsts) \
903 URP_IOP(UnitMergeable) \
904 URP_GOP(UnitMergeables) \
905 URP_IOP(UnitSourceLoc) \
907 URP_GOP(SourceLocPastOffsets) \
908 URP_GOP(SourceLocBaseOffset) \
909 URP_GOP(BaseOffsetAtPCLoc) \
910 URP_GOP(BaseOffsetAfterPCLoc)
911 class InsertUnitStmt
: public RepoProxy::Stmt
{
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
{
922 GetUnitStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
923 bool get(UnitEmitter
& ue
, const MD5
& md5
);
925 class InsertUnitLitstrStmt
: public RepoProxy::Stmt
{
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
{
933 GetUnitLitstrsStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
934 void get(UnitEmitter
& ue
);
936 class InsertUnitArrayStmt
: public RepoProxy::Stmt
{
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
{
944 GetUnitArraysStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
945 void get(UnitEmitter
& ue
);
947 class InsertUnitPreConstStmt
: public RepoProxy::Stmt
{
949 InsertUnitPreConstStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
950 void insert(RepoTxn
& txn
, int64_t unitSn
, const PreConst
& pc
,
953 class GetUnitPreConstsStmt
: public RepoProxy::Stmt
{
955 GetUnitPreConstsStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
956 void get(UnitEmitter
& ue
);
958 class InsertUnitMergeableStmt
: public RepoProxy::Stmt
{
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
{
967 GetUnitMergeablesStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
968 void get(UnitEmitter
& ue
);
970 class InsertUnitSourceLocStmt
: public RepoProxy::Stmt
{
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
{
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
{
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
{
988 GetSourceLocBaseOffsetStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
989 bool get(int64_t unitSn
, OffsetRange
& range
);
991 class GetBaseOffsetAtPCLocStmt
: public RepoProxy::Stmt
{
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
{
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) \
1003 c##Stmt& o(int repoId) { return *m_##o[repoId]; } \
1005 c##Stmt m_##o##Local; \
1006 c##Stmt m_##o##Central; \
1007 c##Stmt* m_##o[RepoIdCount];
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
{
1038 explicit AllFuncsImpl(const Unit
* unit
)
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 {
1049 if (!fr
.empty()) return fr
.front();
1050 assert(!mr
.empty());
1053 FuncPtr
popFront() {
1054 FuncPtr f
= !fr
.empty() ? fr
.popFront() :
1055 !mr
.empty() ? mr
.popFront() : 0;
1057 if (fr
.empty() && mr
.empty()) skip();
1063 while (!cr
.empty() && mr
.empty()) {
1064 PreClassPtr c
= cr
.popFront();
1065 mr
= Unit::FuncRange(GetMethods::get(c
),
1066 GetMethods::get(c
) + c
->numMethods());
1072 Unit::PreClassRange cr
;
1075 typedef AllFuncsImpl
<Unit::FuncRange
, ConstPreClassMethodRanger
> AllFuncs
;
1076 typedef AllFuncsImpl
<Unit::MutableFuncRange
, MutablePreClassMethodRanger
> MutableAllFuncs
;
1080 * Range over all defined classes.
1084 NamedEntityMap::iterator m_next
, m_end
;
1091 Class
* front() const;