Basic JIT support for Records
[hiphop-php.git] / hphp / runtime / vm / unit-emitter.h
blob481e610f44fd58f2e46923a11e00746a107bd5d8
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <list>
21 #include <memory>
22 #include <string>
23 #include <utility>
24 #include <vector>
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"
42 namespace HPHP {
43 ///////////////////////////////////////////////////////////////////////////////
45 struct FuncEmitter;
46 struct PreClassEmitter;
47 struct RecordEmitter;
48 struct StringData;
50 namespace Native {
51 struct FuncTable;
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
65 * runtime Units.
67 struct UnitEmitter {
68 friend struct UnitRepoProxy;
70 /////////////////////////////////////////////////////////////////////////////
71 // Initialization and execution.
73 explicit UnitEmitter(const MD5& md5, const Native::FuncTable&);
74 UnitEmitter(UnitEmitter&&) = delete;
75 ~UnitEmitter();
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 /////////////////////////////////////////////////////////////////////////////
102 // Basic data.
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
140 * the Unit.
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 /////////////////////////////////////////////////////////////////////////////
160 // FuncEmitters.
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 /////////////////////////////////////////////////////////////////////////////
214 // PreClassEmitters.
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 /////////////////////////////////////////////////////////////////////////////
265 // RecordEmitters.
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 /////////////////////////////////////////////////////////////////////////////
279 // Type aliases.
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 /////////////////////////////////////////////////////////////////////////////
293 // Source locations.
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
316 * this UnitEmitter.
318 * Adjacent regions associated with the same source line will be collapsed as
319 * this is created.
321 void recordSourceLocation(const Location::Range& sLoc, Offset start);
324 /////////////////////////////////////////////////////////////////////////////
325 // Mergeables.
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 /////////////////////////////////////////////////////////////////////////////
365 // Bytecode emit.
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.
370 void emitOp(Op op);
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 /////////////////////////////////////////////////////////////////////////////
383 // Other methods.
386 * Is this a Unit for a systemlib?
388 bool isASystemLib() const;
389 private:
391 * Bytecode emit implementation.
393 template<class T>
394 void emitImpl(T n, int64_t pos);
397 /////////////////////////////////////////////////////////////////////////////
398 // Data members.
400 private:
401 // Initial bytecode size.
402 static const size_t BCMaxInit = 4096;
404 public:
405 int m_repoId{-1};
406 int64_t m_sn{-1};
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;
425 private:
426 MD5 m_md5;
428 unsigned char* m_bc;
429 size_t m_bclen;
430 size_t m_bcmax;
432 int m_nextFuncSn;
435 * Litstr tables.
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;
453 * Type alias table.
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*,
477 string_data_hash,
478 string_data_isame> m_hoistablePreClassSet;
479 std::list<Id> m_hoistablePceIdList;
482 * Mergeables tables.
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
494 * coalesce.
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 {
509 friend struct Unit;
510 friend struct UnitEmitter;
512 explicit UnitRepoProxy(Repo& repo);
513 ~UnitRepoProxy();
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,
518 const MD5& md5,
519 const Native::FuncTable&);
521 struct InsertUnitLineTableStmt : public RepoProxy::Stmt {
522 InsertUnitLineTableStmt(Repo& repo, int repoId) : Stmt(repo, repoId) {}
523 void insert(RepoTxn& txn,
524 int64_t unitSn,
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,
535 RepoTxn& txn,
536 int64_t& unitSn,
537 const MD5& md5,
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)
594 #define URP_OPS \
595 URP_IOP(Unit) \
596 URP_GOP(Unit) \
597 URP_IOP(UnitLineTable) \
598 URP_GOP(UnitLineTable) \
599 URP_IOP(UnitLitstr) \
600 URP_GOP(UnitLitstrs) \
601 URP_IOP(UnitArrayTypeTable) \
602 URP_GOP(UnitArrayTypeTable) \
603 URP_IOP(UnitArray) \
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];
612 URP_OPS
613 #undef URP_OP
615 private:
616 RepoStatus loadHelper(UnitEmitter& ue, const std::string&, const MD5&);
619 std::unique_ptr<UnitEmitter> createFatalUnit(
620 StringData* filename,
621 const MD5& md5,
622 FatalOp op,
623 StringData* err
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_