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_EMITTER_H_
18 #define incl_HPHP_VM_UNIT_EMITTER_H_
26 #include "hphp/parser/location.h"
28 #include "hphp/runtime/base/string-data.h"
29 #include "hphp/runtime/base/typed-value.h"
30 #include "hphp/runtime/base/repo-auth-type-array.h"
31 #include "hphp/runtime/vm/preclass.h"
32 #include "hphp/runtime/vm/repo-helpers.h"
33 #include "hphp/runtime/vm/repo-status.h"
34 #include "hphp/runtime/vm/type-alias.h"
35 #include "hphp/runtime/vm/unit.h"
37 #include "hphp/util/functional.h"
38 #include "hphp/util/hash-map.h"
39 #include "hphp/util/hash-set.h"
40 #include "hphp/util/md5.h"
43 ///////////////////////////////////////////////////////////////////////////////
46 struct PreClassEmitter
;
55 * Report capacity of RepoAuthoritative mode bytecode arena.
57 * Returns 0 if !RuntimeOption::RepoAuthoritative.
59 size_t hhbc_arena_capacity();
61 ///////////////////////////////////////////////////////////////////////////////
64 * Pre-runtime representation of Unit used to emit bytecode and instantiate
68 friend struct UnitRepoProxy
;
70 /////////////////////////////////////////////////////////////////////////////
71 // Initialization and execution.
73 explicit UnitEmitter(const MD5
& md5
, const Native::FuncTable
&);
74 UnitEmitter(UnitEmitter
&&) = delete;
77 void setMd5(const MD5
& md5
) { m_md5
= md5
; }
79 * Commit this unit to a repo.
81 void commit(UnitOrigin unitOrigin
);
84 * Insert this unit in a repo as part of transaction `txn'.
86 RepoStatus
insert(UnitOrigin unitOrigin
, RepoTxn
& txn
);
89 * Instatiate a runtime Unit*.
91 std::unique_ptr
<Unit
> create(bool saveLineTable
= false) const;
93 template<class SerDe
> void serdeMetaData(SerDe
&);
96 * Run the verifier on this unit.
98 bool check(bool verbose
) const;
101 /////////////////////////////////////////////////////////////////////////////
105 * The MD5 hash of the Unit.
107 const MD5
& md5() const;
110 * Bytecode pointer and current emit position.
112 const unsigned char* bc() const;
113 Offset
bcPos() const;
114 Offset
offsetOf(const unsigned char* pc
) const;
117 * Set the bytecode pointer by allocating a copy of `bc' with size `bclen'.
119 * Not safe to call with m_bc as the argument because we free our current
120 * bytecode stream before allocating a copy of `bc'.
122 void setBc(const unsigned char* bc
, size_t bclen
);
125 /////////////////////////////////////////////////////////////////////////////
126 // Litstrs and Arrays.
129 * Look up a static string or array/arraytype by ID.
131 const StringData
* lookupLitstr(Id id
) const;
132 const ArrayData
* lookupArray(Id id
) const;
133 const RepoAuthType::Array
* lookupArrayType(Id id
) const;
135 Id
numArrays() const { return m_arrays
.size(); }
136 Id
numLitstrs() const { return m_litstrs
.size(); }
139 * Merge a literal string into either the global LitstrTable or the table for
142 Id
mergeLitstr(const StringData
* litstr
);
145 * Merge a literal string into the table for the Unit.
147 Id
mergeUnitLitstr(const StringData
* litstr
);
150 * Merge a scalar array into the Unit.
152 Id
mergeArray(const ArrayData
* a
);
155 * Clear and rebuild the array type table from the builder.
157 void repopulateArrayTypeTable(const ArrayTypeTable::Builder
&);
159 /////////////////////////////////////////////////////////////////////////////
163 * The Unit's pseudomain emitter.
165 FuncEmitter
* getMain() const;
168 * Const reference to all of the Unit's FuncEmitters.
170 auto const& fevec() const;
173 * Create the pseudomain emitter for the Unit.
175 * @requires: fevec().size() == 0
177 void initMain(int line1
, int line2
);
180 * Create a trivial (i.e., Int 1; RetC) pseudomain emitter for the Unit.
182 * @requires: fevec().size() == 0
184 void addTrivialPseudoMain();
187 * Create a new FuncEmitter and add it to the FE vector.
189 FuncEmitter
* newFuncEmitter(const StringData
* name
);
192 * Create a new FuncEmitter for the method given by `name' and `pce'.
194 * Does /not/ add it to the FE vector.
196 FuncEmitter
* newMethodEmitter(const StringData
* name
, PreClassEmitter
* pce
);
199 * Add `fe' to the FE vector.
201 void appendTopEmitter(std::unique_ptr
<FuncEmitter
>&& fe
);
204 * Create a new function for `fe'.
206 * This should only be called from fe->create(), and just constructs a new
207 * Func* and adds it to unit.m_funcTable if required.
209 Func
* newFunc(const FuncEmitter
* fe
, Unit
& unit
, const StringData
* name
,
210 Attr attrs
, int numParams
);
213 /////////////////////////////////////////////////////////////////////////////
217 * Number of PreClassEmitters in the Unit.
219 size_t numPreClasses() const;
222 * The PreClassEmitter for `preClassId'.
224 const PreClassEmitter
* pce(Id preClassId
) const;
225 PreClassEmitter
* pce(Id preClassId
);
228 * The id for the pre-class named clsName, or -1 if
229 * there is no such pre-class
231 Id
pceId(folly::StringPiece clsName
);
234 * Add a PreClassEmitter to the hoistability tracking data structures.
236 * @see: PreClass::Hoistable
238 void addPreClassEmitter(PreClassEmitter
* pce
);
241 * Create a new PreClassEmitter and add it to all the PCE data structures.
243 * @see: PreClass::Hoistable
245 PreClassEmitter
* newPreClassEmitter(const std::string
& name
,
246 PreClass::Hoistable hoistable
);
248 * Create a new PreClassEmitter without adding it to the hoistability
249 * tracking data structures.
250 * It should be added later with addPreClassEmitter.
252 PreClassEmitter
* newBarePreClassEmitter(const std::string
& name
,
253 PreClass::Hoistable hoistable
);
255 void addRecordEmitter(RecordEmitter
* re
);
256 RecordEmitter
* newRecordEmitter(const std::string
& name
);
258 * Create a new RecordEmitter without adding it to the hoistability
259 * tracking data structures.
260 * It should be added later with addRecordEmitter.
262 RecordEmitter
* newBareRecordEmitter(const std::string
& name
);
264 /////////////////////////////////////////////////////////////////////////////
268 * Number of RecordEmitters in the Unit.
270 size_t numRecords() const;
273 * The RecordEmitter for `recordId'.
275 const RecordEmitter
* re(Id recordId
) const;
276 RecordEmitter
* re(Id recordId
);
278 /////////////////////////////////////////////////////////////////////////////
282 * Const reference to all of the Unit's type aliases.
284 const std::vector
<TypeAlias
>& typeAliases() const;
287 * Add a new type alias to the Unit.
289 Id
addTypeAlias(const TypeAlias
& td
);
292 /////////////////////////////////////////////////////////////////////////////
296 * Return a copy of the SrcLocTable for the Unit, if it has one; otherwise,
297 * return an empty table.
299 SourceLocTable
createSourceLocTable() const;
302 * Does this Unit contain full source location information?
304 * Generally, UnitEmitters loaded from a production repo will have a
305 * LineTable only instead of a full SourceLocTable.
307 bool hasSourceLocInfo() const;
310 * Const reference to the Unit's LineTable.
312 const LineTable
& lineTable() const;
315 * Record source location information for the last chunk of bytecode added to
318 * Adjacent regions associated with the same source line will be collapsed as
321 void recordSourceLocation(const Location::Range
& sLoc
, Offset start
);
324 /////////////////////////////////////////////////////////////////////////////
327 // See unit.h for documentation of Unit merging.
330 * Append a PreClassEmitter to the UnitEmitter's list of mergeables.
332 void pushMergeableClass(PreClassEmitter
* e
);
335 * Add a Unit include to the UnitEmitter's list of mergeables.
337 * The `push' flavor first merges the litstr `unitName', and then appends the
338 * mergeable object reference to the list. The `insert' flavor inserts the
339 * mergeable (kind, id) at `ix' in the list.
341 void pushMergeableInclude(Unit::MergeKind kind
, const StringData
* unitName
);
342 void insertMergeableInclude(int ix
, Unit::MergeKind kind
, Id id
);
345 * Add a constant definition to the UnitEmitter's list of mergeables.
347 * The `push' flavor first merges the litstr `unitName', and then appends the
348 * mergeable object reference to the list. The `insert' flavor inserts the
349 * mergeable (kind, id) at `ix' in the list.
351 * The mergeable value is appended or inserted likewise.
353 void pushMergeableDef(Unit::MergeKind kind
, const StringData
* name
,
354 const TypedValue
& tv
);
355 void insertMergeableDef(int ix
, Unit::MergeKind kind
, Id id
,
356 const TypedValue
& tv
);
359 * Add a TypeAlias to the UnitEmitter's list of mergeables.
361 void pushMergeableTypeAlias(Unit::MergeKind kind
, const Id id
);
362 void insertMergeableTypeAlias(int ix
, Unit::MergeKind kind
, const Id id
);
364 /////////////////////////////////////////////////////////////////////////////
367 // These methods emit values to bc() at bcPos() (or pos, if given) and then
368 // update bcPos(), realloc-ing the bytecode region if necessary.
371 void emitByte(unsigned char n
, int64_t pos
= -1);
373 void emitInt16(uint16_t n
, int64_t pos
= -1);
374 void emitInt32(int n
, int64_t pos
= -1);
375 void emitInt64(int64_t n
, int64_t pos
= -1);
376 void emitDouble(double n
, int64_t pos
= -1);
378 void emitIVA(bool) = delete;
379 template<typename T
> void emitIVA(T n
);
382 /////////////////////////////////////////////////////////////////////////////
386 * Is this a Unit for a systemlib?
388 bool isASystemLib() const;
391 * Bytecode emit implementation.
394 void emitImpl(T n
, int64_t pos
);
397 /////////////////////////////////////////////////////////////////////////////
401 // Initial bytecode size.
402 static const size_t BCMaxInit
= 4096;
407 const StringData
* m_filepath
{nullptr};
409 bool m_mergeOnly
{false};
410 bool m_isHHFile
{false};
411 bool m_useStrictTypes
{false};
412 bool m_useStrictTypesForBuiltins
{false};
413 bool m_returnSeen
{false};
414 bool m_ICE
{false}; // internal compiler error
415 int m_preloadPriority
{0};
416 TypedValue m_mainReturn
;
417 UserAttributeMap m_metaData
;
418 UserAttributeMap m_fileAttributes
;
421 * name=>NativeFuncInfo for native funcs in this unit
423 const Native::FuncTable
& m_nativeFuncs
;
437 hphp_hash_map
<const StringData
*, Id
,
438 string_data_hash
, string_data_same
> m_litstr2id
;
439 std::vector
<const StringData
*> m_litstrs
;
442 * Scalar array tables.
444 hphp_hash_map
<const ArrayData
*, Id
> m_array2id
;
445 std::vector
<const ArrayData
*> m_arrays
;
448 * Unit local array type table.
450 ArrayTypeTable m_arrayTypeTable
;
455 std::vector
<TypeAlias
> m_typeAliases
;
458 * FuncEmitter tables.
460 std::vector
<std::unique_ptr
<FuncEmitter
> > m_fes
;
463 * PreClassEmitter table.
465 std::vector
<PreClassEmitter
*> m_pceVec
;
468 * RecordEmitter table.
470 std::vector
<RecordEmitter
*> m_reVec
;
473 * Hoistability tables.
475 bool m_allClassesHoistable
;
476 hphp_hash_set
<const StringData
*,
478 string_data_isame
> m_hoistablePreClassSet
;
479 std::list
<Id
> m_hoistablePceIdList
;
484 std::vector
<std::pair
<Unit::MergeKind
, Id
>> m_mergeableStmts
;
485 std::vector
<std::pair
<Id
, TypedValue
>> m_mergeableValues
;
488 * Source location tables.
490 * Each entry encodes an open-closed range of bytecode offsets.
492 * The m_sourceLocTab is keyed by the start of each half-open range. This is
493 * to allow appending new bytecode offsets that are part of the same range to
496 * The m_lineTable is keyed by the past-the-end offset. This is the
497 * format we'll want it in when we go to create a Unit.
499 std::vector
<std::pair
<Offset
,SourceLoc
>> m_sourceLocTab
;
500 LineTable m_lineTable
;
503 ///////////////////////////////////////////////////////////////////////////////
506 * Proxy for converting in-repo unit representations into UnitEmitters.
508 struct UnitRepoProxy
: public RepoProxy
{
510 friend struct UnitEmitter
;
512 explicit UnitRepoProxy(Repo
& repo
);
514 void createSchema(int repoId
, RepoTxn
& txn
); // throws(RepoExc)
515 std::unique_ptr
<Unit
> load(const std::string
& name
, const MD5
& md5
,
516 const Native::FuncTable
&);
517 std::unique_ptr
<UnitEmitter
> loadEmitter(const std::string
& name
,
519 const Native::FuncTable
&);
521 struct InsertUnitLineTableStmt
: public RepoProxy::Stmt
{
522 InsertUnitLineTableStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
523 void insert(RepoTxn
& txn
,
525 LineTable
& lineTable
); // throws(RepoExc)
527 struct GetUnitLineTableStmt
: public RepoProxy::Stmt
{
528 GetUnitLineTableStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
529 void get(int64_t unitSn
, LineTable
& lineTable
);
532 struct InsertUnitStmt
: public RepoProxy::Stmt
{
533 InsertUnitStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
534 void insert(const UnitEmitter
& ue
,
538 const unsigned char* bc
,
539 size_t bclen
); // throws(RepoExc)
541 struct GetUnitStmt
: public RepoProxy::Stmt
{
542 GetUnitStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
543 RepoStatus
get(UnitEmitter
& ue
, const MD5
& md5
);
545 struct InsertUnitLitstrStmt
: public RepoProxy::Stmt
{
546 InsertUnitLitstrStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
547 void insert(RepoTxn
& txn
, int64_t unitSn
, Id litstrId
,
548 const StringData
* litstr
); // throws(RepoExc)
550 struct GetUnitLitstrsStmt
: public RepoProxy::Stmt
{
551 GetUnitLitstrsStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
552 void get(UnitEmitter
& ue
); // throws(RepoExc)
554 struct InsertUnitArrayTypeTableStmt
: public RepoProxy::Stmt
{
555 InsertUnitArrayTypeTableStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
556 void insert(RepoTxn
& txn
, int64_t unitSn
,
557 const ArrayTypeTable
& att
); // throws(RepoExc)
559 struct GetUnitArrayTypeTableStmt
: public RepoProxy::Stmt
{
560 GetUnitArrayTypeTableStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
561 void get(UnitEmitter
& ue
); // throws(RepoExc)
563 struct InsertUnitArrayStmt
: public RepoProxy::Stmt
{
564 InsertUnitArrayStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
565 void insert(RepoTxn
& txn
, int64_t unitSn
, Id arrayId
,
566 const std::string
& array
); // throws(RepoExc)
568 struct GetUnitArraysStmt
: public RepoProxy::Stmt
{
569 GetUnitArraysStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
570 void get(UnitEmitter
& ue
); // throws(RepoExc)
572 struct InsertUnitMergeableStmt
: public RepoProxy::Stmt
{
573 InsertUnitMergeableStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
574 void insert(RepoTxn
& txn
, int64_t unitSn
,
575 int ix
, Unit::MergeKind kind
,
576 Id id
, TypedValue
* value
); // throws(RepoExc)
578 struct GetUnitMergeablesStmt
: public RepoProxy::Stmt
{
579 GetUnitMergeablesStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
580 void get(UnitEmitter
& ue
); // throws(RepoExc)
582 struct InsertUnitSourceLocStmt
: public RepoProxy::Stmt
{
583 InsertUnitSourceLocStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
584 void insert(RepoTxn
& txn
, int64_t unitSn
, Offset pastOffset
, int line0
,
585 int char0
, int line1
, int char1
); // throws(RepoExc)
587 struct GetSourceLocTabStmt
: public RepoProxy::Stmt
{
588 GetSourceLocTabStmt(Repo
& repo
, int repoId
) : Stmt(repo
, repoId
) {}
589 RepoStatus
get(int64_t unitSn
, SourceLocTable
& sourceLocTab
);
592 #define URP_IOP(o) URP_OP(Insert##o, insert##o)
593 #define URP_GOP(o) URP_OP(Get##o, get##o)
597 URP_IOP(UnitLineTable) \
598 URP_GOP(UnitLineTable) \
599 URP_IOP(UnitLitstr) \
600 URP_GOP(UnitLitstrs) \
601 URP_IOP(UnitArrayTypeTable) \
602 URP_GOP(UnitArrayTypeTable) \
604 URP_GOP(UnitArrays) \
605 URP_IOP(UnitMergeable) \
606 URP_GOP(UnitMergeables) \
607 URP_IOP(UnitSourceLoc) \
608 URP_GOP(SourceLocTab)
610 #define URP_OP(c, o) \
611 c##Stmt o[RepoIdCount];
616 RepoStatus
loadHelper(UnitEmitter
& ue
, const std::string
&, const MD5
&);
619 std::unique_ptr
<UnitEmitter
> createFatalUnit(
620 StringData
* filename
,
626 template<class SerDe
> void serdeLineTable(SerDe
&, LineTable
&);
628 ///////////////////////////////////////////////////////////////////////////////
631 #define incl_HPHP_VM_UNIT_EMITTER_INL_H_
632 #include "hphp/runtime/vm/unit-emitter-inl.h"
633 #undef incl_HPHP_VM_UNIT_EMITTER_INL_H_
635 #endif // incl_HPHP_VM_UNIT_EMITTER_H_