2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present 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 #include "hphp/parser/location.h"
22 #include "hphp/runtime/base/typed-value.h"
23 #include "hphp/runtime/base/repo-auth-type-array.h"
24 #include "hphp/runtime/vm/class.h"
25 #include "hphp/runtime/vm/containers.h"
26 #include "hphp/runtime/vm/hhbc.h"
27 #include "hphp/runtime/vm/named-entity.h"
28 #include "hphp/runtime/vm/named-entity-pair-table.h"
29 #include "hphp/runtime/vm/preclass.h"
30 #include "hphp/runtime/vm/record.h"
31 #include "hphp/runtime/vm/type-alias.h"
33 #include "hphp/util/compact-vector.h"
34 #include "hphp/util/fixed-vector.h"
35 #include "hphp/util/functional.h"
36 #include "hphp/util/hash-map.h"
37 #include "hphp/util/lock-free-ptr-wrapper.h"
38 #include "hphp/util/md5.h"
39 #include "hphp/util/mutex.h"
40 #include "hphp/util/service-data.h"
49 ///////////////////////////////////////////////////////////////////////////////
60 ///////////////////////////////////////////////////////////////////////////////
64 * Where was a given Unit defined from?
66 enum class UnitOrigin
{
71 ///////////////////////////////////////////////////////////////////////////////
75 * Delimiter pairs for a location in the source code.
82 explicit SourceLoc(const Location::Range
& l
);
85 * Reset to, or check for, the invalid state.
91 * Set to a parser Location.
93 void setLoc(const Location::Range
* l
);
98 bool same(const SourceLoc
* l
) const;
99 bool operator==(const SourceLoc
& l
) const;
102 * Start and end lines and characters.
104 * The default {1, 1, 1, 1} is an invalid sentinel value.
113 * Pair of (base, past) offsets.
118 OffsetRange(Offset base
, Offset past
)
127 using OffsetRangeVec
= std::vector
<OffsetRange
>;
130 * Generic entry for representing many-to-one mappings of Offset -> T.
132 * Each entry's `pastOffset' is expected to be the offset just past the range
133 * of offsets which logically map to its `val'. In this way, by maintaining a
134 * relatively sparse set of entries in a vector, we can use least upper bound
135 * searches on an offset key to find its corresponding T.
137 * The values of `pastOffset' in such a table are expected to be sorted and
138 * unique, but the values of `val' need not be.
150 TableEntry(Offset pastOffset
, T val
)
151 : m_pastOffset(pastOffset
)
158 Offset
pastOffset() const;
164 bool operator<(const TableEntry
& other
) const;
166 template<class SerDe
> void serde(SerDe
& sd
);
169 Offset m_pastOffset
{0};
174 * Table specializations.
176 using LineEntry
= TableEntry
<int>;
177 using SourceLocEntry
= TableEntry
<SourceLoc
>;
178 using LineInfo
= std::pair
<OffsetRange
, int>;
180 using LineTable
= std::vector
<LineEntry
>;
181 using SourceLocTable
= std::vector
<SourceLocEntry
>;
182 using FuncTable
= VMCompactVector
<const Func
*>;
185 * Get the line number or SourceLoc for Offset `pc' in `table'.
187 int getLineNumber(const LineTable
& table
, Offset pc
);
188 bool getSourceLoc(const SourceLocTable
& table
, Offset pc
, SourceLoc
& sLoc
);
189 void stashLineTable(const Unit
* unit
, LineTable table
);
190 void stashExtendedLineTable(const Unit
* unit
, SourceLocTable table
);
192 const SourceLocTable
& getSourceLocTable(const Unit
*);
195 * Sum of all Unit::m_bclen
197 extern ServiceData::ExportedTimeSeries
* g_hhbc_size
;
199 ///////////////////////////////////////////////////////////////////////////////
202 * Metadata about a compilation unit.
204 * Contains the list of PreClasses and global functions, along with a special
205 * function called the 'pseudomain', which is logically invoked (modulo
206 * optimizations that avoid it) during execution when the unit is included or
210 friend struct UnitExtended
;
211 friend struct UnitEmitter
;
212 friend struct UnitRepoProxy
;
214 /////////////////////////////////////////////////////////////////////////////
219 * The Unit's current merge state.
221 * Merging is the process by which functions, classes, and constants defined
222 * in a pseudomain are added to the unit in advance (or, optimistically,
223 * instead of) running the pseudomain's code. This is necessary for
224 * correctness in a number of cases---e.g., toplevel functions defined in the
225 * pseudomain need to be available before the line where the definition
228 * Whenever we want to evaluate a Unit, we call merge() on it, and then
229 * invoke its pseudomain only if necessary.
231 enum MergeState
: uint8_t {
235 UniqueFuncs
= 1 << 2,
236 NeedsCompact
= 1 << 3,
242 * Information on all the mergeable defs within a Unit.
244 * Allocated with a variable-length pointer array in m_mergeables, structured
246 * - the Unit's pseudomain
247 * - hoistable functions (i.e., toplevel functions that need to be available
248 * from the beginning of the pseudomain)
249 * - all other mergeable objects, with the bottom three bits of the pointer
250 * tagged with a MergeKind
253 using FuncRange
= folly::Range
<Func
* const*>;
254 using MutableFuncRange
= folly::Range
<Func
**>;
257 * Allocate a new MergeInfo with `num' mergeables.
259 static MergeInfo
* alloc(size_t num
);
264 * funcHoistableBegin() is in (funcBegin, funcEnd].
266 Func
** funcBegin() const;
267 Func
** funcEnd() const;
268 Func
** funcHoistableBegin() const;
273 * All ranges end at funcEnd().
275 FuncRange
funcs() const;
276 MutableFuncRange
mutableFuncs() const;
277 MutableFuncRange
nonMainFuncs() const;
280 * Get a reference or pointer to the mergeable at index `idx'.
282 void*& mergeableObj(int idx
);
283 void** mergeableData(int idx
);
285 unsigned m_firstHoistableFunc
;
286 unsigned m_firstHoistablePreClass
;
287 unsigned m_firstMergeablePreClass
;
288 unsigned m_mergeablesSize
;
289 void* m_mergeables
[1];
293 * Type of a mergeable object.
295 * This is encoded in the lowest three bits of a pointer to the object.
297 enum class MergeKind
{
298 Class
= 0, // Class is required to be 0 for correctness.
299 UniqueDefinedClass
= 1,
300 Define
= 2, // Toplevel scalar define.
301 PersistentDefine
= 3, // Cross-request persistent toplevel defines.
302 Global
= 4, // Global variable declarations.
306 // We cannot add more kinds here; this has to fit in 3 bits.
312 using FuncRange
= MergeInfo::FuncRange
;
313 using MutableFuncRange
= MergeInfo::MutableFuncRange
;
316 * Cache for pseudomains for this unit, keyed by Class context.
318 using PseudoMainCacheMap
= hphp_hash_map
<
319 const Class
*, Func
*, pointer_hash
<Class
>
322 using PreClassPtrVec
= VMCompactVector
<PreClassPtr
>;
323 using TypeAliasVec
= VMFixedVector
<TypeAlias
>;
325 /////////////////////////////////////////////////////////////////////////////
326 // Construction and destruction.
332 * New and delete using low memory.
334 void* operator new(size_t sz
);
335 void operator delete(void* p
, size_t sz
);
337 /////////////////////////////////////////////////////////////////////////////
338 // Basic accessors. [const]
341 * Repo ID and serial number.
352 * File and directory paths.
354 const StringData
* filepath() const;
355 const StringData
* dirpath() const;
358 * Was this unit created in response to an internal compiler error?
362 /////////////////////////////////////////////////////////////////////////////
366 * Start and size of the bytecode for the Unit.
369 Offset
bclen() const;
372 * Convert between PC and Offset from entry().
374 PC
at(Offset off
) const;
375 Offset
offsetOf(PC pc
) const;
378 * Is `pc' in this Unit?
380 bool contains(PC pc
) const;
383 * Get the Op at `instrOffset'.
385 Op
getOp(Offset instrOffset
) const;
387 /////////////////////////////////////////////////////////////////////////////
388 // Code locations. [const]
391 * Get the line number corresponding to `pc'.
393 * Return -1 if not found.
395 int getLineNumber(Offset pc
) const;
398 * Get the SourceLoc corresponding to `pc'.
400 * Return false if not found, else true.
402 bool getSourceLoc(Offset pc
, SourceLoc
& sLoc
) const;
405 * Get the Offset range(s) corresponding to `pc' or `line'.
407 * Return false if not found, else true.
409 bool getOffsetRange(Offset pc
, OffsetRange
& range
) const;
410 bool getOffsetRanges(int line
, OffsetRangeVec
& offsets
) const;
413 * Get next line with executable code starting from input `line'.
415 * Return -1 if not found.
417 int getNearestLineWithCode(int line
) const;
420 * Return the Func* for the code at offset `pc'.
422 * Return nullptr if the offset is not in a Func body (but this should be
425 const Func
* getFunc(Offset pc
) const;
427 /////////////////////////////////////////////////////////////////////////////
428 // Litstrs and NamedEntitys. [const]
431 * Size of the Unit's litstr table.
433 * This excludes litstrs that are instead found in the global table---thus,
434 * it is not a source of truth for the number of litstrs a Unit needs, only
435 * those it happens to own.
437 size_t numLitstrs() const;
440 * Is `id' a valid litstr in LitstrTable or the Unit's local
441 * NamedEntityPairTable?
443 bool isLitstrId(Id id
) const;
446 * Dispatch to either the global LitstrTable or the Unit's local
447 * NamedEntityPairTable, depending on whether `id' is global.
449 * @see: NamedEntityPairTable
451 StringData
* lookupLitstrId(Id id
) const;
452 const NamedEntity
* lookupNamedEntityId(Id id
) const;
453 NamedEntityPair
lookupNamedEntityPairId(Id id
) const;
455 /////////////////////////////////////////////////////////////////////////////
459 * Size of the Unit's scalar array table.
461 size_t numArrays() const;
464 * Look up a scalar array by ID.
466 const ArrayData
* lookupArrayId(Id id
) const;
469 * Look up a RepoAuthType::Array by ID
471 const RepoAuthType::Array
* lookupArrayTypeId(Id id
) const;
473 /////////////////////////////////////////////////////////////////////////////
474 // Funcs, PreClasses, and Records. [const]
477 * Look up a Func or PreClass or Record by ID.
479 Func
* lookupFuncId(Id id
) const;
480 PreClass
* lookupPreClassId(Id id
) const;
481 Record
* lookupRecordId(Id id
) const;
484 * Range over all Funcs or PreClasses or Records in the Unit.
486 FuncRange
funcs() const;
487 folly::Range
<PreClassPtr
*> preclasses();
488 folly::Range
<const PreClassPtr
*> preclasses() const;
489 folly::Range
<RecordPtr
*> records();
490 folly::Range
<const RecordPtr
*> records() const;
493 * Get a pseudomain for the Unit with the context class `cls'.
495 * We clone the toplevel pseudomain for each context class and cache the
496 * results in m_pseudoMainCache.
498 Func
* getMain(Class
* cls
) const;
500 // Return the cached EntryPoint
501 Func
* getCachedEntryPoint() const;
504 * Visit all functions and methods in this unit.
506 template<class Fn
> void forEachFunc(Fn fn
) const;
508 /////////////////////////////////////////////////////////////////////////////
509 // Func lookup. [static]
512 * Define `func' for this request by initializing its RDS handle.
514 static void defFunc(Func
* func
, bool debugger
);
517 * Look up the defined Func in this request with name `name', or with the name
518 * mapped to the NamedEntity `ne'.
520 * Return nullptr if the function is not yet defined in this request.
522 static Func
* lookupFunc(const NamedEntity
* ne
);
523 static Func
* lookupFunc(const StringData
* name
);
526 * Look up, or autoload and define, the Func in this request with name `name',
527 * or with the name mapped to the NamedEntity `ne'.
529 * @requires: NamedEntity::get(name) == ne
531 static Func
* loadFunc(const NamedEntity
* ne
, const StringData
* name
);
532 static Func
* loadFunc(const StringData
* name
);
535 * bind (or rebind) a func to the NamedEntity corresponding to its
538 static void bindFunc(Func
* func
);
541 * Lookup the builtin in this request with name `name', or nullptr if none
542 * exists. This does not access RDS so it is safe to use from within the
543 * compiler. Note that does not mean imply that the name binding for the
544 * builtin is immutable. The builtin could be renamed or intercepted.
546 static Func
* lookupBuiltin(const StringData
* name
);
548 /////////////////////////////////////////////////////////////////////////////
549 // Class lookup. [static]
552 * Define a new Class from `preClass' for this request.
554 * Raises a fatal error in various conditions (e.g., Class already defined,
555 * parent Class not defined, etc.) if `failIsFatal' is set).
557 * Also always fatals if a type alias already exists in this request with the
558 * same name as that of `preClass', regardless of the value of `failIsFatal'.
560 static Class
* defClass(const PreClass
* preClass
, bool failIsFatal
= true);
563 * Define a closure from preClass. Closures have unique names, so unlike
564 * defClass, this is a one time operation.
566 static Class
* defClosure(const PreClass
* preClass
);
569 * Set the NamedEntity for `alias' to refer to the class `original' in this
572 * Raises a warning and returns false if `alias' already refers to a
573 * Class in this request, or if original is not loaded, and autoload
574 * is false, or it can't be autoloaded. Returns true otherwise.
576 static bool aliasClass(const StringData
* original
, const StringData
* alias
,
580 * Look up the Class in this request with name `name', or with the name
581 * mapped to the NamedEntity `ne'.
583 * Return nullptr if the class is not yet defined in this request.
585 static Class
* lookupClass(const NamedEntity
* ne
);
586 static Class
* lookupClass(const StringData
* name
);
589 * Finds a class which is guaranteed to be unique in the specified
590 * context. The class has not necessarily been loaded in the
593 * Return nullptr if there is no such class.
595 static const Class
* lookupUniqueClassInContext(const NamedEntity
* ne
,
597 static const Class
* lookupUniqueClassInContext(const StringData
* name
,
601 * Look up, or autoload and define, the Class in this request with name
602 * `name', or with the name mapped to the NamedEntity `ne'.
604 * @requires: NamedEntity::get(name) == ne
606 static Class
* loadClass(const NamedEntity
* ne
, const StringData
* name
);
607 static Class
* loadClass(const StringData
* name
);
610 * Autoload the Class with name `name' and bind it `ne' in this request.
612 * @requires: NamedEntity::get(name) == ne
614 static Class
* loadMissingClass(const NamedEntity
* ne
, const StringData
* name
);
617 * Same as lookupClass(), but if `tryAutoload' is set, call and return
618 * loadMissingClass().
620 static Class
* getClass(const NamedEntity
* ne
, const StringData
* name
,
622 static Class
* getClass(const StringData
* name
, bool tryAutoload
);
625 * Whether a Class with name `name' of type `kind' has been defined in this
626 * request, autoloading it if `autoload' is set.
628 static bool classExists(const StringData
* name
,
629 bool autoload
, ClassKind kind
);
631 /////////////////////////////////////////////////////////////////////////////
632 // Record lookup. [static]
635 * Define a new Record from `record' for this request.
637 * Raises a fatal error in various conditions (e.g., Record already defined,
638 * etc.) if `failIsFatal' is set).
640 * Also always fatals if a type alias already exists in this request with the
641 * same name as that of `record', regardless of the value of `failIsFatal'.
643 static Record
* defRecord(Record
* record
, bool failIsFatal
= true);
646 * Look up the Record in this request with name `name', or with the name
647 * mapped to the NamedEntity `ne'.
649 * Return nullptr if the record is not yet defined in this request.
651 static Record
* lookupRecord(const NamedEntity
* ne
);
652 static Record
* lookupRecord(const StringData
* name
);
655 * Look up, or autoload and define, the Record in this request with name
656 * `name', or with the name mapped to the NamedEntity `ne'.
658 * @requires: NamedEntity::get(name) == ne
660 static Record
* loadRecord(const StringData
* name
);
662 /////////////////////////////////////////////////////////////////////////////
663 // Constant lookup. [static]
666 * Look up the value of the defined constant in this request with name
669 * Return nullptr if no such constant is defined.
671 static tv_rval
lookupCns(const StringData
* cnsName
);
674 * Look up the value of the persistent constant with name `cnsName'.
676 * Return nullptr if no such constant exists, or the constant is not
679 static const Cell
* lookupPersistentCns(const StringData
* cnsName
);
682 * Look up, or autoload and define, the value of the constant with name
683 * `cnsName' for this request.
685 static tv_rval
loadCns(const StringData
* cnsName
);
688 * Define a constant (either request-local or persistent) with name `cnsName'
691 * May raise notices or warnings if a constant with the given name is already
692 * defined or if value is invalid.
694 static bool defCns(const StringData
* cnsName
, const TypedValue
* value
);
697 * Define a constant with name `cnsName' with a magic callback. The
698 * Cell should be KindOfUninit, with a Native::ConstantCallback in
701 * The canonical examples are STDIN, STDOUT, and STDERR.
703 static bool defNativeConstantCallback(const StringData
* cnsName
, Cell cell
);
705 /////////////////////////////////////////////////////////////////////////////
708 folly::Range
<TypeAlias
*> typeAliases();
709 folly::Range
<const TypeAlias
*> typeAliases() const;
712 * Look up without autoloading a type alias named `name'. Returns nullptr
713 * if one cannot be found.
715 * If the type alias is found and `persistent' is provided, it will be set to
716 * whether or not the TypeAliasReq's RDS handle is persistent.
718 static const TypeAliasReq
* lookupTypeAlias(const StringData
* name
,
719 bool* persistent
= nullptr);
722 * Look up or attempt to autoload a type alias named `name'. Returns nullptr
723 * if one cannot be found or autoloaded.
725 * If the type alias is found and `persistent' is provided, it will be set to
726 * whether or not the TypeAliasReq's RDS handle is persistent.
728 static const TypeAliasReq
* loadTypeAlias(const StringData
* name
,
729 bool* persistent
= nullptr);
732 * Define the type alias given by `id', binding it to the appropriate
733 * NamedEntity for this request.
735 * returns true iff the bound type alias is persistent.
737 bool defTypeAlias(Id id
);
739 /////////////////////////////////////////////////////////////////////////////
742 const UserAttributeMap
& fileAttributes() const;
744 /////////////////////////////////////////////////////////////////////////////
748 * Merge the Unit if it is not already merged.
753 * Is it sufficient to merge the Unit, and skip invoking its pseudomain?
755 bool isMergeOnly() const;
758 * Is this Unit empty---i.e., does it define nothing and have no
761 bool isEmpty() const;
764 * Get the return value of the pseudomain, or KindOfUninit if not
767 * @requires: isMergeOnly()
769 const TypedValue
* getMainReturn() const;
771 /////////////////////////////////////////////////////////////////////////////
772 // Info arrays. [static]
775 * Generate class info arrays.
777 static Array
getClassesInfo();
778 static Array
getInterfacesInfo();
779 static Array
getTraitsInfo();
782 * Generate function info arrays.
784 static Array
getUserFunctions();
785 static Array
getSystemFunctions();
787 /////////////////////////////////////////////////////////////////////////////
788 // Pretty printer. [const]
792 : startOffset(kInvalidOffset
)
793 , stopOffset(kInvalidOffset
)
799 PrintOpts
& range(Offset start
, Offset stop
) {
805 PrintOpts
& noLineNumbers() {
810 PrintOpts
& noFuncs() {
815 PrintOpts
& indent(int i
) {
827 void prettyPrint(std::ostream
&, PrintOpts
= PrintOpts()) const;
828 std::string
toString() const;
830 /////////////////////////////////////////////////////////////////////////////
834 * Is this Unit a compile-time fatal?
836 * A compile-time fatal is encoded as a pseudomain that contains precisely:
838 * String <id>; Fatal;
840 * Decode enough of pseudomain to determine whether it contains a
841 * compile-time fatal, and if so, extract the error message and line number.
843 * Parse-time fatals are a subset of compile-time fatals.
845 bool compileTimeFatal(const StringData
*& msg
, int& line
) const;
846 bool parseFatal(const StringData
*& msg
, int& line
) const;
849 * Get or set whether this Unit is interpret-only.
851 * This is used by the debugger to signal to the JIT that eval'd commands
852 * should not be jitted.
854 bool isInterpretOnly() const;
855 void setInterpretOnly();
860 void* replaceUnit() const;
863 * Does this unit correspond to a file with "<?hh" at the top, irrespective of
864 * EnableHipHopSyntax?
866 bool isHHFile() const;
869 * Should calls from this unit use strict types? (This is always true for HH
872 * With strict types enabled only lossless int->float conversions are allowed
874 bool useStrictTypes() const;
877 * Should calls from this unit to builtins use strict types?
879 * This is true for PHP7 files with declare(strict_types=1), but not for Hack
880 * files or force_hh */
881 bool useStrictTypesForBuiltins() const;
883 UserAttributeMap
metaData() const;
885 // Return true, and set the m_serialized flag, iff this Unit hasn't
886 // been serialized yet (see prof-data-serialize.cpp).
887 bool serialize() const {
888 if (m_serialized
) return false;
889 const_cast<Unit
*>(this)->m_serialized
= true;
893 /////////////////////////////////////////////////////////////////////////////
894 // Offset accessors. [static]
896 static constexpr ptrdiff_t bcOff() {
897 return offsetof(Unit
, m_bc
);
900 /////////////////////////////////////////////////////////////////////////////
905 template<bool debugger
>
906 void mergeImpl(MergeInfo
* mi
);
907 UnitExtended
* getExtended();
908 const UnitExtended
* getExtended() const;
909 MergeInfo
* mergeInfo() const {
910 return m_mergeInfo
.load(std::memory_order_acquire
);
913 /////////////////////////////////////////////////////////////////////////////
916 // These are organized in reverse order of frequency of use. Do not re-order
917 // without checking perf!
919 unsigned char const* m_bc
{nullptr};
921 LowStringPtr m_filepath
{nullptr};
922 std::atomic
<MergeInfo
*> m_mergeInfo
{nullptr};
926 * m_mergeState is read without a lock, but only written to under
927 * unitInitLock (see unit.cpp).
929 std::atomic
<uint8_t> m_mergeState
{MergeState::Unmerged
};
931 bool m_interpretOnly
: 1;
933 bool m_useStrictTypes
: 1;
934 bool m_useStrictTypesForBuiltins
: 1;
936 bool m_serialized
: 1;
937 bool m_ICE
: 1; // was this unit the result of an internal compiler error
938 LowStringPtr m_dirpath
{nullptr};
940 TypedValue m_mainReturn
;
941 PreClassPtrVec m_preClasses
;
942 TypeAliasVec m_typeAliases
;
943 CompactVector
<RecordPtr
> m_records
;
945 * Cached the EntryPoint for an unit, since compactMergeInfo() inside of
946 * mergeImpl will drop the original EP.
948 Func
* m_cachedEntryPoint
{nullptr};
951 * The remaining fields are cold, and arbitrarily ordered.
954 int64_t m_sn
{-1}; // Note: could be 32-bit
956 VMFixedVector
<const ArrayData
*> m_arrays
;
957 mutable PseudoMainCacheMap
* m_pseudoMainCache
{nullptr};
958 mutable LockFreePtrWrapper
<VMCompactVector
<LineInfo
>> m_lineMap
;
959 UserAttributeMap m_metaData
;
960 UserAttributeMap m_fileAttributes
;
963 struct UnitExtended
: Unit
{
965 friend struct UnitEmitter
;
967 UnitExtended() { m_extended
= true; }
969 NamedEntityPairTable m_namedInfo
;
970 ArrayTypeTable m_arrayTypeTable
;
971 FuncTable m_funcTable
;
974 ///////////////////////////////////////////////////////////////////////////////
977 #define incl_HPHP_VM_UNIT_INL_H_
978 #include "hphp/runtime/vm/unit-inl.h"
979 #undef incl_HPHP_VM_UNIT_INL_H_
981 #endif // incl_HPHP_VM_UNIT_H_