Use cached classname in the class type constant to optimize type_structure(cls,cns...
[hiphop-php.git] / hphp / runtime / vm / jit / extra-data.h
blob1ff549ff0c0018e4ce03fbbf9ad76fc78c88ca25
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_EXTRADATA_H_
18 #define incl_HPHP_VM_EXTRADATA_H_
20 #include "hphp/runtime/base/collections.h"
21 #include "hphp/runtime/base/typed-value.h"
22 #include "hphp/runtime/vm/bytecode.h"
23 #include "hphp/runtime/vm/srckey.h"
25 #include "hphp/runtime/vm/jit/types.h"
26 #include "hphp/runtime/vm/jit/ir-opcode.h"
27 #include "hphp/runtime/vm/jit/stack-offsets.h"
29 #include "hphp/runtime/ext/generator/ext_generator.h"
31 #include "hphp/util/arena.h"
32 #include "hphp/util/ringbuffer.h"
33 #include "hphp/util/safe-cast.h"
35 #include <folly/Conv.h>
36 #include <folly/Hash.h>
37 #include <folly/Optional.h>
38 #include <folly/gen/Base.h>
39 #include <folly/gen/String.h>
41 #include <algorithm>
42 #include <string>
44 namespace HPHP { namespace jit {
46 //////////////////////////////////////////////////////////////////////
49 * Some IRInstructions with compile-time-only constants may carry along extra
50 * data in the form of one of these structures.
52 * Note that this isn't really appropriate for compile-time constants that are
53 * actually representing user values (we want them to be visible to
54 * optimization passes, allocatable to registers, etc), just compile-time
55 * metadata.
57 * These types must:
59 * - Derive from IRExtraData (for overloading purposes).
60 * - Be arena-allocatable (no non-trivial destructors).
61 * - Either CopyConstructible, or implement a clone member function that
62 * takes an arena to clone to.
64 * In addition, extra data belonging to IRInstructions that may be hashed in
65 * IRInstrTables must:
67 * - Implement an equals() member that indicates equality.
68 * - Implement a hash() method.
70 * Finally, optionally they may implement a show() method for use in debug
71 * printouts.
75 * Traits that returns the type of the extra C++ data structure for a
76 * given instruction, if it has one, along with some other information
77 * about the type.
79 template<Opcode op> struct OpHasExtraData { enum { value = 0 }; };
80 template<Opcode op> struct IRExtraDataType;
82 //////////////////////////////////////////////////////////////////////
84 struct IRExtraData {};
86 //////////////////////////////////////////////////////////////////////
89 * Shared IRExtraData classes.
91 * These subtypes represent common parameters (e.g., statically known Func,
92 * local variable ID, stack offset, etc.) that are useful for a variety of HHIR
93 * instructions.
95 * These are kept separate from the one-off IRExtraDatas to make it easier to
96 * find existing common parameters.
100 * Offset in bytes from a base pointer---e.g., to a object property from an
101 * ObjectData*.
103 struct ByteOffsetData : IRExtraData {
104 explicit ByteOffsetData(ptrdiff_t offset) : offsetBytes(offset) {}
106 std::string show() const { return folly::to<std::string>(offsetBytes); }
108 bool equals(ByteOffsetData o) const { return offsetBytes == o.offsetBytes; }
109 size_t hash() const { return std::hash<ptrdiff_t>()(offsetBytes); }
111 ptrdiff_t offsetBytes;
115 * Class pointer.
117 * Required to be non-null.
119 struct ClassData : IRExtraData {
120 explicit ClassData(const Class* cls)
121 : cls(cls)
123 assertx(cls != nullptr);
126 std::string show() const {
127 return folly::to<std::string>(cls->name()->data());
130 bool equals(const ClassData& o) const {
131 return cls == o.cls;
134 size_t hash() const {
135 return pointer_hash<Class>()(cls);
138 const Class* cls;
142 * Class pointer, suppress flag, is or as operation flag and range into the
143 * stack (for type structures) needed for resolve type struct instruction
145 * Class pointer could be null.
147 struct ResolveTypeStructData : IRExtraData {
148 explicit ResolveTypeStructData(
149 const Class* cls,
150 bool suppress,
151 IRSPRelOffset offset,
152 uint32_t size,
153 bool isOrAsOp
155 : cls(cls)
156 , suppress(suppress)
157 , offset(offset)
158 , size(size)
159 , isOrAsOp(isOrAsOp)
162 std::string show() const {
163 return folly::sformat("{},{},{},{},{}",
164 cls ? cls->name()->data() : "nullptr",
165 suppress ? "suppress" : "no-suppress",
166 offset.offset,
167 size,
168 isOrAsOp);
171 bool equals(const ResolveTypeStructData& o) const {
172 return cls == o.cls && suppress == o.suppress &&
173 offset == o.offset && size == o.size && isOrAsOp == o.isOrAsOp;
176 size_t hash() const {
177 return (pointer_hash<Class>()(cls)
178 + std::hash<int32_t>()(offset.offset)
179 + std::hash<uint32_t>()(size))
180 ^ ((int64_t)(suppress ? -1 : 0) << 32 | (isOrAsOp ? -1 : 0));
183 const Class* cls;
184 bool suppress;
185 IRSPRelOffset offset;
186 uint32_t size;
187 bool isOrAsOp;
191 * ExtendsClass.
193 struct ExtendsClassData : IRExtraData {
194 explicit ExtendsClassData(const Class* cls, bool strictLikely = false)
195 : cls(cls), strictLikely(strictLikely)
197 assertx(cls != nullptr);
200 std::string show() const {
201 return folly::sformat("{}{}",
202 cls->name(), strictLikely ? ":strictLikely" : "");
205 bool equals(const ExtendsClassData& o) const {
206 return cls == o.cls && strictLikely == o.strictLikely;
209 size_t hash() const {
210 return pointer_hash<Class>()(cls) ^ (strictLikely ? -1 : 0);
213 const Class* cls;
214 bool strictLikely;
218 * Class with method name.
220 struct ClsMethodData : IRExtraData {
221 ClsMethodData(const StringData* cls, const StringData* method,
222 const NamedEntity* ne = nullptr)
223 : clsName(cls)
224 , methodName(method)
225 , namedEntity(ne)
228 std::string show() const {
229 return folly::format("{}::{}", clsName, methodName).str();
232 bool equals(const ClsMethodData& o) const {
233 // The strings are static so we can use pointer equality.
234 return clsName == o.clsName && methodName == o.methodName;
236 size_t hash() const {
237 return hash_int64_pair((intptr_t)clsName, (intptr_t)methodName);
240 const StringData* clsName;
241 const StringData* methodName;
242 const NamedEntity* namedEntity;
245 struct IfaceMethodData : IRExtraData {
246 IfaceMethodData(Slot vtableIdx, Slot methodIdx)
247 : vtableIdx(vtableIdx)
248 , methodIdx(methodIdx)
251 std::string show() const {
252 return folly::sformat("{}, {}", vtableIdx, methodIdx);
255 bool equals(const IfaceMethodData& o) const {
256 return vtableIdx == o.vtableIdx && methodIdx == o.methodIdx;
259 size_t hash() const {
260 return hash_int64((int64_t)vtableIdx << 32 | methodIdx);
263 Slot vtableIdx;
264 Slot methodIdx;
268 * Func
270 struct FuncData : IRExtraData {
271 explicit FuncData(const Func* f)
272 : func(f)
275 std::string show() const {
276 return folly::format("{}", func->fullName()).str();
279 const Func* func;
283 * Func with argument index.
285 struct FuncArgData : IRExtraData {
286 explicit FuncArgData(const Func* f, int64_t arg)
287 : func(f)
288 , argNum(arg)
291 std::string show() const {
292 return folly::format("{},{}", func->name(), argNum).str();
295 const Func* func;
296 int64_t argNum;
300 * Local variable ID.
302 struct LocalId : IRExtraData {
303 explicit LocalId(uint32_t id) : locId(id) {}
305 std::string show() const { return folly::to<std::string>(locId); }
307 bool equals(LocalId o) const { return locId == o.locId; }
308 size_t hash() const { return std::hash<uint32_t>()(locId); }
310 uint32_t locId;
313 struct ClsRefSlotData : IRExtraData {
314 explicit ClsRefSlotData(uint32_t slot) : slot{slot} {}
316 std::string show() const { return folly::to<std::string>(slot); }
318 bool equals(ClsRefSlotData o) const { return slot == o.slot; }
319 size_t hash() const { return std::hash<uint32_t>()(slot); }
321 uint32_t slot;
325 * Index into, e.g., an array.
327 struct IndexData : IRExtraData {
328 explicit IndexData(uint32_t index) : index(index) {}
330 std::string show() const { return folly::format("{}", index).str(); }
332 uint32_t index;
336 * Iterator ID.
338 struct IterId : IRExtraData {
339 explicit IterId(uint32_t id)
340 : iterId(id)
343 std::string show() const { return folly::to<std::string>(iterId); }
345 bool equals(IterId o) const { return iterId == o.iterId; }
346 size_t hash() const { return std::hash<uint32_t>()(iterId); }
348 uint32_t iterId;
352 * Iter instruction data.
354 * `iterId' is the iterator ID; `keyId' and `valId' are the IDs of the iterator
355 * locals $key => $value. For keyless iterators, we still use this class, with
356 * `keyId` set to -1u.
358 struct IterData : IRExtraData {
359 IterData(uint32_t iter, uint32_t key, uint32_t val)
360 : iterId(iter)
361 , keyId(key)
362 , valId(val)
365 std::string show() const {
366 if (keyId == -1) return folly::format("{}::{}", iterId, valId).str();
367 return folly::format("{}::{}::{}", iterId, keyId, valId).str();
370 uint32_t iterId;
371 uint32_t keyId;
372 uint32_t valId;
375 struct IterInitData : public IterData {
376 IterInitData(uint32_t iter, uint32_t key,
377 uint32_t val, bool stack)
378 : IterData{iter, key, val}
379 , fromStack{stack}
381 bool fromStack;
385 * RDS handle.
387 struct RDSHandleData : IRExtraData {
388 explicit RDSHandleData(rds::Handle handle) : handle(handle) {}
390 std::string show() const { return folly::to<std::string>(handle); }
392 bool equals(RDSHandleData o) const { return handle == o.handle; }
393 size_t hash() const { return std::hash<uint32_t>()(handle); }
395 rds::Handle handle;
399 * Array access profile.
401 struct ArrayAccessProfileData : RDSHandleData {
402 ArrayAccessProfileData(rds::Handle handle, bool cowCheck)
403 : RDSHandleData(handle), cowCheck(cowCheck) {}
405 std::string show() const {
406 return folly::to<std::string>(handle, ",", cowCheck);
409 bool equals(ArrayAccessProfileData o) const {
410 return handle == o.handle && cowCheck == o.cowCheck;
412 size_t hash() const {
413 return folly::hash::hash_combine(std::hash<uint32_t>()(handle),
414 std::hash<bool>()(cowCheck));
417 bool cowCheck;
422 * Translation ID.
424 * Used with profiling-related instructions.
426 struct TransIDData : IRExtraData {
427 explicit TransIDData(TransID transId) : transId(transId) {}
429 std::string show() const { return folly::to<std::string>(transId); }
431 TransID transId;
435 * FP-relative offset.
437 struct FPRelOffsetData : IRExtraData {
438 explicit FPRelOffsetData(FPRelOffset offset) : offset(offset) {}
440 std::string show() const {
441 return folly::to<std::string>("FPRelOff ", offset.offset);
444 bool equals(FPRelOffsetData o) const { return offset == o.offset; }
445 size_t hash() const { return std::hash<int32_t>()(offset.offset); }
447 FPRelOffset offset;
451 * Stack pointer offset.
453 struct FPInvOffsetData : IRExtraData {
454 explicit FPInvOffsetData(FPInvOffset offset) : offset(offset) {}
456 std::string show() const {
457 return folly::to<std::string>("FPInvOff ", offset.offset);
460 bool equals(FPInvOffsetData o) const { return offset == o.offset; }
461 size_t hash() const { return std::hash<int32_t>()(offset.offset); }
463 FPInvOffset offset;
467 * Stack offset.
469 struct IRSPRelOffsetData : IRExtraData {
470 explicit IRSPRelOffsetData(IRSPRelOffset offset) : offset(offset) {}
472 std::string show() const {
473 return folly::to<std::string>("IRSPOff ", offset.offset);
476 bool equals(IRSPRelOffsetData o) const { return offset == o.offset; }
477 size_t hash() const { return std::hash<int32_t>()(offset.offset); }
479 IRSPRelOffset offset;
482 ///////////////////////////////////////////////////////////////////////////////
485 * One-off IRExtraData classes.
487 * These are used for only one or two instructions and are in no particular
488 * order. Add new IRExtraData types here.
491 struct IsAsyncData : IRExtraData {
492 explicit IsAsyncData(bool isAsync) : isAsync(isAsync) {}
494 std::string show() const { return folly::to<std::string>(isAsync); }
495 bool equals(IsAsyncData d) const { return isAsync == d.isAsync; }
496 size_t hash() const { return std::hash<int32_t>()(isAsync); }
498 bool isAsync;
501 struct LdBindAddrData : IRExtraData {
502 explicit LdBindAddrData(SrcKey sk, FPInvOffset bcSPOff)
503 : sk(sk)
504 , bcSPOff(bcSPOff)
507 std::string show() const { return showShort(sk); }
509 SrcKey sk;
510 FPInvOffset bcSPOff;
513 struct LdSSwitchData : IRExtraData {
514 struct Elm {
515 const StringData* str;
516 SrcKey dest;
519 explicit LdSSwitchData() = default;
520 LdSSwitchData(const LdSSwitchData&) = delete;
521 LdSSwitchData& operator=(const LdSSwitchData&) = delete;
523 LdSSwitchData* clone(Arena& arena) const {
524 LdSSwitchData* target = new (arena) LdSSwitchData;
525 target->numCases = numCases;
526 target->defaultSk = defaultSk;
527 target->cases = new (arena) Elm[numCases];
528 target->bcSPOff = bcSPOff;
529 std::copy(cases, cases + numCases, const_cast<Elm*>(target->cases));
530 return target;
533 std::string show() const {
534 return folly::to<std::string>(bcSPOff.offset);
537 int64_t numCases;
538 const Elm* cases;
539 SrcKey defaultSk;
540 FPInvOffset bcSPOff;
543 struct ProfileSwitchData : IRExtraData {
544 ProfileSwitchData(rds::Handle handle, int32_t cases, int64_t base)
545 : handle(handle)
546 , cases(cases)
547 , base(base)
550 std::string show() const {
551 return folly::sformat("handle {}, {} cases, base {}", handle, cases, base);
554 rds::Handle handle;
555 int32_t cases;
556 int64_t base;
559 struct JmpSwitchData : IRExtraData {
560 JmpSwitchData* clone(Arena& arena) const {
561 JmpSwitchData* sd = new (arena) JmpSwitchData;
562 sd->cases = cases;
563 sd->targets = new (arena) SrcKey[cases];
564 sd->spOffBCFromFP = spOffBCFromFP;
565 sd->spOffBCFromIRSP = spOffBCFromIRSP;
566 std::copy(targets, targets + cases, const_cast<SrcKey*>(sd->targets));
567 return sd;
570 std::string show() const {
571 return folly::sformat("{} cases", cases);
574 int32_t cases; // number of cases
575 SrcKey* targets; // srckeys for all targets
576 FPInvOffset spOffBCFromFP;
577 IRSPRelOffset spOffBCFromIRSP;
580 struct LdTVAuxData : IRExtraData {
581 explicit LdTVAuxData(int32_t v = -1) : valid(v) {}
583 std::string show() const {
584 return folly::sformat("{:x}", valid);
587 int32_t valid;
590 struct ReqBindJmpData : IRExtraData {
591 explicit ReqBindJmpData(const SrcKey& target,
592 FPInvOffset invSPOff,
593 IRSPRelOffset irSPOff,
594 TransFlags trflags)
595 : target(target)
596 , invSPOff(invSPOff)
597 , irSPOff(irSPOff)
598 , trflags(trflags)
601 std::string show() const {
602 return folly::sformat(
603 "{}, FPInv {}, IRSP {}, Flags {}",
604 target.offset(), invSPOff.offset, irSPOff.offset, trflags.packed
608 SrcKey target;
609 FPInvOffset invSPOff;
610 IRSPRelOffset irSPOff;
611 TransFlags trflags;
614 struct ReqRetranslateData : IRExtraData {
615 explicit ReqRetranslateData(IRSPRelOffset irSPOff,
616 TransFlags trflags)
617 : irSPOff(irSPOff)
618 , trflags{trflags}
621 std::string show() const {
622 return folly::to<std::string>(irSPOff.offset, ',', trflags.packed);
625 IRSPRelOffset irSPOff;
626 TransFlags trflags;
630 * Compile-time metadata about an ActRec allocation.
632 struct ActRecInfo : IRExtraData {
633 explicit ActRecInfo(IRSPRelOffset spOffset, uint32_t numArgs)
634 : spOffset(spOffset)
635 , numArgs(numArgs)
638 std::string show() const {
639 return folly::to<std::string>(spOffset.offset, ',', numArgs);
642 IRSPRelOffset spOffset;
643 uint32_t numArgs;
647 * DefInlineFP is present when we need to create a frame for inlining. This
648 * instruction also carries some metadata used by IRBuilder to track state
649 * during an inlined call.
651 struct DefInlineFPData : IRExtraData {
652 std::string show() const {
653 return folly::to<std::string>(
654 target->fullName()->data(), "(),",
655 callBCOff, ',',
656 retSPOff.offset, ',',
657 spOffset.offset
661 const Func* target;
662 SSATmp* ctx; // Ctx, Cls or Nullptr.
663 Offset callBCOff;
664 FPInvOffset retSPOff;
665 IRSPRelOffset spOffset; // offset from caller SP to bottom of callee's ActRec
666 uint32_t numNonDefault;
667 bool asyncEagerReturn;
670 struct SyncReturnBCData : IRExtraData {
671 SyncReturnBCData(Offset callBCOff, IRSPRelOffset spOff)
672 : callBCOffset(callBCOff)
673 , spOffset(spOff)
675 std::string show() const {
676 return folly::to<std::string>(callBCOffset, ",", spOffset.offset);
679 Offset callBCOffset;
680 IRSPRelOffset spOffset;
683 struct CallUnpackData : IRExtraData {
684 explicit CallUnpackData(IRSPRelOffset spOffset,
685 uint32_t numParams,
686 uint32_t numOut,
687 Offset callOffset,
688 const Func* callee)
689 : spOffset(spOffset)
690 , numParams(numParams)
691 , numOut(numOut)
692 , callOffset(callOffset)
693 , callee(callee)
695 assertx(numParams > 0);
698 std::string show() const {
699 return folly::to<std::string>(
700 callOffset, ",",
701 callee
702 ? folly::sformat(",{}", callee->fullName())
703 : std::string{});
706 IRSPRelOffset spOffset; // offset from StkPtr to bottom of call's ActRec+args
707 uint32_t numParams;
708 uint32_t numOut;
709 Offset callOffset; // offset from unit m_bc (unlike m_callOff in ActRec)
710 const Func* callee; // nullptr if not statically known
713 struct CallBuiltinData : IRExtraData {
714 explicit CallBuiltinData(IRSPRelOffset spOffset,
715 const Func* callee,
716 int32_t numNonDefault)
717 : spOffset(spOffset)
718 , callee{callee}
719 , numNonDefault{numNonDefault}
722 std::string show() const {
723 return folly::to<std::string>(
724 spOffset.offset, ',',
725 callee->fullName()->data()
729 IRSPRelOffset spOffset; // offset from StkPtr to last passed arg
730 const Func* callee;
731 int32_t numNonDefault;
734 struct CallData : IRExtraData {
735 explicit CallData(IRSPRelOffset spOffset,
736 uint32_t numParams,
737 uint32_t numOut,
738 Offset callOffset,
739 const Func* callee,
740 bool asyncEagerReturn)
741 : spOffset(spOffset)
742 , numParams(numParams)
743 , numOut(numOut)
744 , callOffset(callOffset)
745 , callee(callee)
746 , asyncEagerReturn(asyncEagerReturn)
749 std::string show() const {
750 return folly::to<std::string>(
751 spOffset.offset, ',', numParams, ',', callOffset,
752 callee
753 ? folly::format(",{}", callee->fullName()).str()
754 : std::string{},
755 asyncEagerReturn ? ",asyncEagerReturn" : ""
759 IRSPRelOffset spOffset; // offset from StkPtr to bottom of call's ActRec+args
760 uint32_t numParams;
761 uint32_t numOut; // number of values returned via stack from the callee
762 Offset callOffset; // m_callOff style: offset from func->base()
763 const Func* callee; // nullptr if not statically known
764 bool asyncEagerReturn;
767 struct RetCtrlData : IRExtraData {
768 explicit RetCtrlData(IRSPRelOffset offset, bool suspendingResumed,
769 folly::Optional<AuxUnion> aux = folly::none)
770 : offset(offset)
771 , suspendingResumed(suspendingResumed)
772 , aux(aux)
775 std::string show() const {
776 return folly::to<std::string>(
777 offset.offset,
778 suspendingResumed ? ",suspendingResumed" : ""
782 // Adjustment we need to make to the stack pointer (for cross-tracelet ABI
783 // purposes) before returning.
784 IRSPRelOffset offset;
786 // Indicates that the current resumable frame is being suspended without
787 // decrefing locals. Used by refcount optimizer.
788 bool suspendingResumed;
790 // Optional TV aux value to attach to the function's return value.
791 folly::Optional<AuxUnion> aux;
795 * Name of a class constant in a known class
797 struct ClsCnsName : IRExtraData {
798 explicit ClsCnsName(const StringData* cls, const StringData* cns)
799 : clsName(cls)
800 , cnsName(cns)
803 std::string show() const {
804 return folly::to<std::string>(clsName->data(), "::", cnsName->data());
807 const StringData* clsName;
808 const StringData* cnsName;
812 * Name of a class constant in an unknown class.
814 struct LdSubClsCnsData : IRExtraData {
815 explicit LdSubClsCnsData(const StringData* cns, Slot s)
816 : cnsName(cns)
817 , slot(s)
820 std::string show() const {
821 return folly::sformat("<cls>::{}({})", cnsName, slot);
824 const StringData* cnsName;
825 Slot slot;
829 * Name and handle of profiled class constant
831 struct ProfileSubClsCnsData : IRExtraData {
832 explicit ProfileSubClsCnsData(const StringData* cns, rds::Handle h)
833 : cnsName(cns)
834 , handle(h)
837 std::string show() const {
838 return folly::to<std::string>("<cls>::", cnsName->data());
841 const StringData* cnsName;
842 rds::Handle handle;
845 struct FuncNameData : IRExtraData {
846 explicit FuncNameData(const StringData* name)
847 : name(name)
850 std::string show() const {
851 return folly::to<std::string>(name->data());
854 size_t hash() const { return name->hash(); }
855 bool equals(const FuncNameData& o) const {
856 return name == o.name;
859 const StringData* name;
863 * Offset and stack deltas for InterpOne.
865 struct InterpOneData : IRExtraData {
866 struct LocalType {
867 explicit LocalType(uint32_t id = 0, Type type = TBottom)
868 : id(id)
869 , type(type)
872 uint32_t id;
873 Type type;
876 struct ClsRefSlot {
877 explicit ClsRefSlot(uint32_t id = 0, bool write = false)
878 : id{id}
879 , write{write}
882 uint32_t id;
883 bool write;
886 explicit InterpOneData(IRSPRelOffset spOffset)
887 : spOffset(spOffset)
888 , nChangedLocals(0)
889 , changedLocals(nullptr)
890 , nChangedClsRefSlots(0)
891 , changedClsRefSlots(nullptr)
892 , smashesAllLocals(false)
895 // Offset of the BC stack top relative to the current IR stack pointer.
896 IRSPRelOffset spOffset;
898 // Offset of the instruction to interpret, in the Unit indicated by the
899 // current Marker.
900 Offset bcOff;
902 // The number of eval stack cells consumed and produced by the instruction,
903 // respectively. Includes ActRecs.
904 int64_t cellsPopped;
905 int64_t cellsPushed;
907 // Opcode, in case we need to fix the stack differently. Some bytecode
908 // instructions modify things below the top of the stack.
909 Op opcode;
911 uint32_t nChangedLocals;
912 LocalType* changedLocals;
914 uint32_t nChangedClsRefSlots;
915 ClsRefSlot* changedClsRefSlots;
917 bool smashesAllLocals;
919 InterpOneData* clone(Arena& arena) const {
920 auto* id = new (arena) InterpOneData(spOffset);
921 id->bcOff = bcOff;
922 id->cellsPopped = cellsPopped;
923 id->cellsPushed = cellsPushed;
924 id->opcode = opcode;
925 id->nChangedLocals = nChangedLocals;
926 id->changedLocals = new (arena) LocalType[nChangedLocals];
927 id->nChangedClsRefSlots = nChangedClsRefSlots;
928 id->changedClsRefSlots = new (arena) ClsRefSlot[nChangedClsRefSlots];
929 id->smashesAllLocals = smashesAllLocals;
930 std::copy(changedLocals, changedLocals + nChangedLocals, id->changedLocals);
931 std::copy(changedClsRefSlots, changedClsRefSlots + nChangedClsRefSlots,
932 id->changedClsRefSlots);
933 return id;
936 std::string show() const {
937 auto ret = folly::sformat(
938 "{}: spOff:{}, bcOff:{}, popped:{}, pushed:{}",
939 opcodeToName(opcode),
940 spOffset.offset,
941 bcOff,
942 cellsPopped,
943 cellsPushed
945 assertx(!smashesAllLocals || !nChangedLocals);
946 if (smashesAllLocals) ret += ", smashes all locals";
947 if (nChangedLocals) {
948 for (auto i = 0; i < nChangedLocals; ++i) {
949 ret += folly::sformat(", Local {} -> {}",
950 changedLocals[i].id,
951 changedLocals[i].type);
954 if (nChangedClsRefSlots) {
955 for (auto i = 0; i < nChangedClsRefSlots; ++i) {
956 ret += folly::sformat(", Slot {}{}",
957 changedClsRefSlots[i].id,
958 changedClsRefSlots[i].write ? "W" : "R");
962 return ret;
966 struct CoerceStkData : IRExtraData {
967 explicit CoerceStkData(IRSPRelOffset off, const Func* f, int64_t arg_num)
968 : offset(off), callee(f), argNum(arg_num) {}
970 std::string show() const {
971 return folly::sformat(
972 "IRSP {},{},{}",
973 offset.offset,
974 callee->name(),
975 argNum
979 IRSPRelOffset offset;
980 const Func* callee;
981 int32_t argNum;
984 struct CoerceMemData : IRExtraData {
985 explicit CoerceMemData(const Func* f, int64_t arg_num)
986 : callee(f), argNum(arg_num) {}
988 std::string show() const {
989 return folly::sformat("{},{}", callee->name(), argNum);
992 const Func* callee;
993 int32_t argNum;
996 struct RBEntryData : IRExtraData {
997 RBEntryData(Trace::RingBufferType t, SrcKey sk)
998 : type(t)
999 , sk(sk)
1002 std::string show() const {
1003 return folly::sformat("{}: {}", ringbufferName(type), showShort(sk));
1006 Trace::RingBufferType type;
1007 SrcKey sk;
1010 struct RBMsgData : IRExtraData {
1011 RBMsgData(Trace::RingBufferType t, const StringData* msg)
1012 : type(t)
1013 , msg(msg)
1015 assertx(msg->isStatic());
1018 std::string show() const {
1019 return folly::sformat("{}: {}", ringbufferName(type), msg->data());
1022 Trace::RingBufferType type;
1023 const StringData* msg;
1026 struct ClassKindData : IRExtraData {
1027 explicit ClassKindData(ClassKind kind): kind(uint32_t(kind)) {}
1029 std::string show() const {
1030 switch (static_cast<ClassKind>(kind)) {
1031 case ClassKind::Class: return "cls";
1032 case ClassKind::Interface: return "interface";
1033 case ClassKind::Trait: return "trait";
1034 case ClassKind::Enum: return "enum";
1036 not_reached();
1039 uint32_t kind; // ... allows for direct usage in native_call
1042 struct NewStructData : IRExtraData {
1043 std::string show() const;
1044 IRSPRelOffset offset;
1045 uint32_t numKeys;
1046 StringData** keys;
1049 struct PackedArrayData : IRExtraData {
1050 explicit PackedArrayData(uint32_t size) : size(size) {}
1051 std::string show() const { return folly::format("{}", size).str(); }
1052 uint32_t size;
1055 struct InitPackedArrayLoopData : IRExtraData {
1056 explicit InitPackedArrayLoopData(IRSPRelOffset offset, uint32_t size)
1057 : offset(offset)
1058 , size(size)
1061 std::string show() const {
1062 return folly::format("{},{}", offset.offset, size).str();
1065 IRSPRelOffset offset;
1066 uint32_t size;
1069 struct CreateAAWHData : IRExtraData {
1070 explicit CreateAAWHData(uint32_t first, uint32_t count)
1071 : first(first)
1072 , count(count)
1075 std::string show() const {
1076 return folly::format("{},{}", first, count).str();
1079 uint32_t first;
1080 uint32_t count;
1083 struct CountWHNotDoneData : IRExtraData {
1084 explicit CountWHNotDoneData(uint32_t first, uint32_t count)
1085 : first(first)
1086 , count(count)
1089 std::string show() const {
1090 return folly::format("{},{}", first, count).str();
1093 uint32_t first;
1094 uint32_t count;
1097 struct NewKeysetArrayData : IRExtraData {
1098 explicit NewKeysetArrayData(IRSPRelOffset offset, uint32_t size)
1099 : offset(offset)
1100 , size(size)
1103 std::string show() const {
1104 return folly::format("{},{}", offset.offset, size).str();
1107 IRSPRelOffset offset;
1108 uint32_t size;
1111 struct MemoValueStaticData : IRExtraData {
1112 explicit MemoValueStaticData(const Func* func,
1113 folly::Optional<bool> asyncEager,
1114 bool loadAux)
1115 : func{func}
1116 , asyncEager{asyncEager}
1117 , loadAux{loadAux} {}
1118 std::string show() const {
1119 return folly::sformat(
1120 "{},{},{}",
1121 func->fullName()->toCppString(),
1122 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1123 loadAux
1126 const Func* func;
1127 folly::Optional<bool> asyncEager;
1128 bool loadAux;
1131 struct MemoValueInstanceData : IRExtraData {
1132 explicit MemoValueInstanceData(Slot slot,
1133 const Func* func,
1134 folly::Optional<bool> asyncEager,
1135 bool loadAux)
1136 : slot{slot}
1137 , func{func}
1138 , asyncEager{asyncEager}
1139 , loadAux{loadAux} {}
1140 std::string show() const {
1141 return folly::sformat(
1142 "{},{},{},{}",
1143 slot,
1144 func->fullName(),
1145 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1146 loadAux
1149 Slot slot;
1150 const Func* func;
1151 folly::Optional<bool> asyncEager;
1152 bool loadAux;
1155 struct MemoCacheStaticData : IRExtraData {
1156 MemoCacheStaticData(const Func* func,
1157 LocalRange keys,
1158 const bool* types,
1159 folly::Optional<bool> asyncEager,
1160 bool loadAux)
1161 : func{func}
1162 , keys{keys}
1163 , types{types}
1164 , asyncEager{asyncEager}
1165 , loadAux{loadAux} {}
1167 MemoCacheStaticData* clone(Arena& arena) const {
1168 auto p =
1169 new (arena) MemoCacheStaticData(func, keys, types, asyncEager, loadAux);
1170 auto tmp = new (arena) bool[keys.count];
1171 std::copy(types, types + keys.count, tmp);
1172 p->types = tmp;
1173 p->stackOffset = stackOffset;
1174 return p;
1177 std::string show() const {
1178 std::string ret;
1179 if (stackOffset) {
1180 ret += folly::sformat(
1181 "{},IRSPOff {}", func->fullName(), stackOffset->offset
1183 } else {
1184 ret += folly::sformat("{},{}", func->fullName(), HPHP::show(keys));
1187 if (keys.count > 0) {
1188 ret += ",<";
1189 for (auto i = 0; i < keys.count; ++i) {
1190 if (i > 0) ret += ",";
1191 ret += folly::sformat("{}", types[i] ? "string" : "int");
1193 ret += ">";
1195 return ret;
1198 const Func* func;
1199 LocalRange keys;
1200 const bool* types;
1201 folly::Optional<bool> asyncEager;
1202 bool loadAux;
1203 // Should only be present if the frame is given by a StkPtr
1204 folly::Optional<IRSPRelOffset> stackOffset;
1207 struct MemoCacheInstanceData : IRExtraData {
1208 MemoCacheInstanceData(Slot slot,
1209 LocalRange keys,
1210 const bool* types,
1211 const Func* func,
1212 bool shared,
1213 folly::Optional<bool> asyncEager,
1214 bool loadAux)
1215 : slot{slot}
1216 , keys{keys}
1217 , types{types}
1218 , func{func}
1219 , shared{shared}
1220 , asyncEager{asyncEager}
1221 , loadAux{loadAux} {}
1223 MemoCacheInstanceData* clone(Arena& arena) const {
1224 auto p = new (arena) MemoCacheInstanceData(
1225 slot, keys, types, func, shared, asyncEager, loadAux
1227 auto tmp = new (arena) bool[keys.count];
1228 std::copy(types, types + keys.count, tmp);
1229 p->types = tmp;
1230 p->stackOffset = stackOffset;
1231 return p;
1234 std::string show() const {
1235 return folly::sformat(
1236 "{},{},{},<{}>,{}",
1237 slot,
1238 func->fullName(),
1239 stackOffset
1240 ? folly::sformat("IRSPOff {}", stackOffset->offset)
1241 : HPHP::show(keys),
1242 [&]{
1243 using namespace folly::gen;
1244 return range<uint32_t>(0, keys.count)
1245 | map([this] (uint32_t i) { return types[i] ? "string" : "int"; })
1246 | unsplit<std::string>(",");
1247 }(),
1248 shared ? "shared" : "non-shared"
1252 Slot slot;
1253 LocalRange keys;
1254 const bool* types;
1255 const Func* func;
1256 bool shared;
1257 folly::Optional<bool> asyncEager;
1258 bool loadAux;
1259 // Should only be present if the frame is given by a StkPtr
1260 folly::Optional<IRSPRelOffset> stackOffset;
1263 struct MOpModeData : IRExtraData {
1264 explicit MOpModeData(MOpMode mode) : mode{mode} {}
1266 std::string show() const { return subopToName(mode); }
1268 MOpMode mode;
1271 struct SetOpData : IRExtraData {
1272 explicit SetOpData(SetOpOp op) : op(op) {}
1273 std::string show() const { return subopToName(op); }
1274 SetOpOp op;
1277 struct DecRefData : IRExtraData {
1278 explicit DecRefData(int locId = -1) : locId(locId) {}
1279 std::string show() const {
1280 return locId != -1 ? folly::to<std::string>("Loc", locId) : "-";
1282 int locId; // If a known local, this has its id; -1 otherwise.
1285 struct IncDecData : IRExtraData {
1286 explicit IncDecData(IncDecOp op) : op(op) {}
1287 std::string show() const { return subopToName(op); }
1288 IncDecOp op;
1291 struct ResumeOffset : IRExtraData {
1292 explicit ResumeOffset(Offset off) : off(off) {}
1293 std::string show() const { return folly::to<std::string>(off); }
1294 Offset off;
1297 struct GeneratorState : IRExtraData {
1298 explicit GeneratorState(BaseGenerator::State state) : state(state) {}
1299 std::string show() const {
1300 using U = std::underlying_type<BaseGenerator::State>::type;
1301 return folly::to<std::string>(static_cast<U>(state));
1303 BaseGenerator::State state;
1306 struct ContEnterData : IRExtraData {
1307 explicit ContEnterData(IRSPRelOffset spOffset, Offset callBCOffset,
1308 bool isAsync)
1309 : spOffset(spOffset)
1310 , callBCOffset(callBCOffset)
1311 , isAsync(isAsync)
1314 std::string show() const {
1315 return folly::to<std::string>(spOffset.offset, ',', callBCOffset,
1316 isAsync ? ",async" : "");
1319 IRSPRelOffset spOffset;
1320 Offset callBCOffset;
1321 bool isAsync;
1324 struct NewColData : IRExtraData {
1325 explicit NewColData(CollectionType itype)
1326 : type(itype)
1329 std::string show() const {
1330 return collections::typeToString(type)->toCppString();
1333 CollectionType type;
1336 struct LocalIdRange : IRExtraData {
1337 LocalIdRange(uint32_t start, uint32_t end)
1338 : start(start)
1339 , end(end)
1342 std::string show() const {
1343 return folly::format("[{}, {})", start, end).str();
1346 uint32_t start, end;
1349 struct FuncEntryData : IRExtraData {
1350 FuncEntryData(const Func* func, uint32_t argc)
1351 : func(func)
1352 , argc(argc)
1355 std::string show() const {
1356 return folly::format(
1357 "{}({} args)",
1358 func->fullName(),
1359 argc
1360 ).str();
1363 const Func* func;
1364 uint32_t argc;
1367 struct CheckRefsData : IRExtraData {
1368 CheckRefsData(unsigned firstBit, uint64_t mask, uint64_t vals)
1369 : firstBit(safe_cast<int>(firstBit))
1370 , mask(mask)
1371 , vals(vals)
1374 std::string show() const {
1375 return folly::format("{},{},{}", firstBit, mask, vals).str();
1378 int firstBit;
1379 uint64_t mask;
1380 uint64_t vals;
1383 struct LookupClsMethodData : IRExtraData {
1384 explicit LookupClsMethodData(IRSPRelOffset offset, bool forward, bool dynamic)
1385 : calleeAROffset(offset), forward(forward), dynamic(dynamic) {}
1387 std::string show() const {
1388 return folly::to<std::string>("IRSPOff ", calleeAROffset.offset,
1389 forward ? " forwarded" : "",
1390 dynamic ? " dynamic" : "");
1393 // offset from caller SP to bottom of callee's ActRec
1394 IRSPRelOffset calleeAROffset;
1395 bool forward;
1396 bool dynamic;
1400 struct ProfileCallTargetData : IRExtraData {
1401 ProfileCallTargetData(IRSPRelOffset bcSPOff, rds::Handle handle)
1402 : bcSPOff(bcSPOff)
1403 , handle(handle)
1406 std::string show() const {
1407 return folly::to<std::string>(bcSPOff.offset, ",", handle);
1410 IRSPRelOffset bcSPOff;
1411 rds::Handle handle;
1414 struct FuncGuardData : IRExtraData {
1415 FuncGuardData(const Func* func, TCA* prologueAddrPtr)
1416 : func(func)
1417 , prologueAddrPtr(prologueAddrPtr)
1420 std::string show() const {
1421 return folly::sformat("{}=>{}",
1422 func->fullName(), prologueAddrPtr
1426 const Func* func;
1427 TCA* prologueAddrPtr;
1430 struct BeginInliningData : IRExtraData {
1431 BeginInliningData(IRSPRelOffset offset, const Func* func, int cost)
1432 : offset(offset)
1433 , func(func)
1434 , cost(cost)
1437 std::string show() const {
1438 return folly::to<std::string>("IRSPOff ", offset.offset,
1439 " FUNC ", func->fullName()->data());
1442 IRSPRelOffset offset;
1443 const Func* func;
1444 int cost;
1447 struct ParamData : IRExtraData {
1448 explicit ParamData(int32_t paramId) : paramId(paramId) {}
1450 std::string show() const {
1451 return folly::to<std::string>(paramId);
1454 int32_t paramId;
1457 struct RaiseHackArrNoticeData : IRExtraData {
1458 explicit RaiseHackArrNoticeData(AnnotType type)
1459 : type{type} {}
1461 std::string show() const {
1462 if (type == AnnotType::VArray) return "varray";
1463 if (type == AnnotType::DArray) return "darray";
1464 if (type == AnnotType::VArrOrDArr) return "varray_or_darray";
1465 return "array";
1468 AnnotType type;
1471 struct RaiseHackArrParamNoticeData : RaiseHackArrNoticeData {
1472 RaiseHackArrParamNoticeData(AnnotType type, int32_t id, bool isReturn)
1473 : RaiseHackArrNoticeData{type}
1474 , id{id}
1475 , isReturn{isReturn} {}
1477 std::string show() const {
1478 auto const typeStr = RaiseHackArrNoticeData::show();
1479 return folly::to<std::string>(
1480 typeStr, ",",
1481 id, ",",
1482 isReturn ? "true" : "false"
1486 int32_t id;
1487 bool isReturn;
1490 struct RaiseArrayIndexNoticeData : IRExtraData {
1491 explicit RaiseArrayIndexNoticeData(bool isInOut) : isInOut(isInOut) {}
1493 std::string show() const {
1494 if (isInOut) return "inout";
1495 return "none";
1498 bool isInOut;
1501 struct RaiseArrayKeyNoticeData : IRExtraData {
1502 explicit RaiseArrayKeyNoticeData(bool isInOut) : isInOut(isInOut) {}
1504 std::string show() const {
1505 if (isInOut) return "inout";
1506 return "none";
1509 bool isInOut;
1512 struct AssertReason : IRExtraData {
1513 explicit AssertReason(Reason r) : reason{r.file, r.line} {}
1515 std::string show() const {
1516 return jit::show(reason);
1519 Reason reason;
1522 #define ASSERT_REASON AssertReason{Reason{__FILE__, __LINE__}}
1524 struct EndCatchData : IRSPRelOffsetData {
1525 enum CatchMode {
1526 UnwindOnly,
1527 SwitchMode,
1528 BuiltinSwitchMode,
1529 SideExit
1532 explicit EndCatchData(IRSPRelOffset offset, CatchMode mode) :
1533 IRSPRelOffsetData{offset}, mode{mode} {}
1535 std::string show() const {
1536 return folly::to<std::string>(
1537 IRSPRelOffsetData::show(), ",",
1538 mode == UnwindOnly ? "UnwindOnly" :
1539 mode == SwitchMode ? "SwitchMode" :
1540 mode == BuiltinSwitchMode ?
1541 "BuiltinSwitchMode" : "SideExit");
1544 CatchMode mode;
1547 //////////////////////////////////////////////////////////////////////
1549 #define X(op, data) \
1550 template<> struct IRExtraDataType<op> { typedef data type; }; \
1551 template<> struct OpHasExtraData<op> { enum { value = 1 }; }; \
1552 static_assert(boost::has_trivial_destructor<data>::value, \
1553 "IR extra data type must be trivially destructible")
1555 X(LdBindAddr, LdBindAddrData);
1556 X(ProfileSwitchDest, ProfileSwitchData);
1557 X(JmpSwitchDest, JmpSwitchData);
1558 X(LdSSwitchDestFast, LdSSwitchData);
1559 X(LdSSwitchDestSlow, LdSSwitchData);
1560 X(HintLocInner, LocalId);
1561 X(CheckLoc, LocalId);
1562 X(AssertLoc, LocalId);
1563 X(LdLocAddr, LocalId);
1564 X(LdLoc, LocalId);
1565 X(LdLocPseudoMain, LocalId);
1566 X(StLoc, LocalId);
1567 X(StLocPseudoMain, LocalId);
1568 X(StLocRange, LocalIdRange);
1569 X(LdClsRefCls, ClsRefSlotData);
1570 X(LdClsRefTS, ClsRefSlotData);
1571 X(StClsRefCls, ClsRefSlotData);
1572 X(StClsRefTS, ClsRefSlotData);
1573 X(KillClsRefCls, ClsRefSlotData);
1574 X(KillClsRefTS, ClsRefSlotData);
1575 X(IterFree, IterId);
1576 X(IterInit, IterInitData);
1577 X(IterInitK, IterInitData);
1578 X(IterNext, IterData);
1579 X(IterNextK, IterData);
1580 X(LIterInit, IterInitData);
1581 X(LIterInitK, IterInitData);
1582 X(LIterNext, IterData);
1583 X(LIterNextK, IterData);
1584 X(ConstructInstance, ClassData);
1585 X(ConstructClosure, ClassData);
1586 X(InitProps, ClassData);
1587 X(InitSProps, ClassData);
1588 X(NewInstanceRaw, ClassData);
1589 X(InitObjProps, ClassData);
1590 X(InitObjMemoSlots, ClassData);
1591 X(InstanceOfIfaceVtable, ClassData);
1592 X(ResolveTypeStruct, ResolveTypeStructData);
1593 X(ExtendsClass, ExtendsClassData);
1594 X(SpillFrame, ActRecInfo);
1595 X(CheckStk, IRSPRelOffsetData);
1596 X(HintStkInner, IRSPRelOffsetData);
1597 X(StStk, IRSPRelOffsetData);
1598 X(StOutValue, IndexData);
1599 X(CoerceStk, CoerceStkData);
1600 X(CoerceMem, CoerceMemData);
1601 X(CoerceCellToInt, FuncArgData);
1602 X(CoerceCellToDbl, FuncArgData);
1603 X(CoerceCellToBool, FuncArgData);
1604 X(CoerceStrToInt, FuncArgData);
1605 X(CoerceStrToDbl, FuncArgData);
1606 X(AssertStk, IRSPRelOffsetData);
1607 X(DefSP, FPInvOffsetData);
1608 X(LdStk, IRSPRelOffsetData);
1609 X(LdStkAddr, IRSPRelOffsetData);
1610 X(DefInlineFP, DefInlineFPData);
1611 X(BeginInlining, BeginInliningData);
1612 X(SyncReturnBC, SyncReturnBCData);
1613 X(InlineReturn, FPRelOffsetData);
1614 X(InlineSuspend, FPRelOffsetData);
1615 X(InlineReturnNoFrame, FPRelOffsetData);
1616 X(ReqRetranslate, ReqRetranslateData);
1617 X(ReqBindJmp, ReqBindJmpData);
1618 X(ReqRetranslateOpt, IRSPRelOffsetData);
1619 X(CheckCold, TransIDData);
1620 X(IncProfCounter, TransIDData);
1621 X(Call, CallData);
1622 X(CallBuiltin, CallBuiltinData);
1623 X(CallUnpack, CallUnpackData);
1624 X(RetCtrl, RetCtrlData);
1625 X(AsyncFuncRet, IRSPRelOffsetData);
1626 X(AsyncFuncRetSlow, IRSPRelOffsetData);
1627 X(AsyncSwitchFast, IRSPRelOffsetData);
1628 X(LdArrFuncCtx, IRSPRelOffsetData);
1629 X(LdFunc, IRSPRelOffsetData);
1630 X(LookupClsMethod, LookupClsMethodData);
1631 X(LookupClsMethodCache, ClsMethodData);
1632 X(LdClsMethodCacheFunc, ClsMethodData);
1633 X(LdClsMethodCacheCls, ClsMethodData);
1634 X(LdClsMethodFCacheFunc, ClsMethodData);
1635 X(LookupClsMethodFCache, ClsMethodData);
1636 X(LdIfaceMethod, IfaceMethodData);
1637 X(LdClsCns, ClsCnsName);
1638 X(InitClsCns, ClsCnsName);
1639 X(LdSubClsCns, LdSubClsCnsData);
1640 X(LdSubClsCnsClsName, LdSubClsCnsData);
1641 X(CheckSubClsCns, LdSubClsCnsData);
1642 X(ProfileSubClsCns, ProfileSubClsCnsData);
1643 X(LdFuncCached, FuncNameData);
1644 X(LookupFuncCached, FuncNameData);
1645 X(LdObjMethod, FuncNameData);
1646 X(RaiseMissingArg, FuncArgData);
1647 X(RaiseTooManyArg, FuncArgData);
1648 X(ThrowParamRefMismatch, ParamData);
1649 X(ThrowParamRefMismatchRange, CheckRefsData);
1650 X(RaiseArrayIndexNotice, RaiseArrayIndexNoticeData);
1651 X(RaiseArrayKeyNotice, RaiseArrayKeyNoticeData);
1652 X(CheckClsReifiedGenericMismatch,
1653 ClassData);
1654 X(CheckFunReifiedGenericMismatch,
1655 FuncData);
1656 X(IsFunReifiedGenericsMatched, FuncData);
1657 X(InterpOne, InterpOneData);
1658 X(InterpOneCF, InterpOneData);
1659 X(StClosureArg, ByteOffsetData);
1660 X(RBTraceEntry, RBEntryData);
1661 X(RBTraceMsg, RBMsgData);
1662 X(OODeclExists, ClassKindData);
1663 X(NewStructArray, NewStructData);
1664 X(NewStructDArray, NewStructData);
1665 X(NewStructDict, NewStructData);
1666 X(NewRecord, NewStructData);
1667 X(AllocPackedArray, PackedArrayData);
1668 X(AllocVArray, PackedArrayData);
1669 X(AllocVecArray, PackedArrayData);
1670 X(NewKeysetArray, NewKeysetArrayData);
1671 X(InitPackedLayoutArrayLoop, InitPackedArrayLoopData);
1672 X(InitPackedLayoutArray, IndexData);
1673 X(CreateAAWH, CreateAAWHData);
1674 X(CountWHNotDone, CountWHNotDoneData);
1675 X(CheckMixedArrayOffset, IndexData);
1676 X(CheckDictOffset, IndexData);
1677 X(CheckKeysetOffset, IndexData);
1678 X(ElemMixedArrayK, IndexData);
1679 X(MixedArrayGetK, IndexData);
1680 X(DictGetK, IndexData);
1681 X(KeysetGetK, IndexData);
1682 X(ElemDictK, IndexData);
1683 X(ElemKeysetK, IndexData);
1684 X(ProfileArrayKind, RDSHandleData);
1685 X(ProfileMixedArrayOffset, ArrayAccessProfileData);
1686 X(ProfileDictOffset, ArrayAccessProfileData);
1687 X(ProfileKeysetOffset, ArrayAccessProfileData);
1688 X(ProfileType, RDSHandleData);
1689 X(ProfileFunc, ProfileCallTargetData);
1690 X(ProfileMethod, ProfileCallTargetData);
1691 X(LdRDSAddr, RDSHandleData);
1692 X(CheckRDSInitialized, RDSHandleData);
1693 X(MarkRDSInitialized, RDSHandleData);
1694 X(LdInitRDSAddr, RDSHandleData);
1695 X(BaseG, MOpModeData);
1696 X(PropX, MOpModeData);
1697 X(PropDX, MOpModeData);
1698 X(ElemX, MOpModeData);
1699 X(ElemDX, MOpModeData);
1700 X(ElemUX, MOpModeData);
1701 X(ElemArrayX, MOpModeData);
1702 X(ElemDictX, MOpModeData);
1703 X(ElemKeysetX, MOpModeData);
1704 X(CGetProp, MOpModeData);
1705 X(CGetElem, MOpModeData);
1706 X(ArrayGet, MOpModeData);
1707 X(MemoGetStaticValue, MemoValueStaticData);
1708 X(MemoSetStaticValue, MemoValueStaticData);
1709 X(MemoGetStaticCache, MemoCacheStaticData);
1710 X(MemoSetStaticCache, MemoCacheStaticData);
1711 X(MemoGetLSBValue, MemoValueStaticData);
1712 X(MemoSetLSBValue, MemoValueStaticData);
1713 X(MemoGetLSBCache, MemoCacheStaticData);
1714 X(MemoSetLSBCache, MemoCacheStaticData);
1715 X(MemoGetInstanceValue, MemoValueInstanceData);
1716 X(MemoSetInstanceValue, MemoValueInstanceData);
1717 X(MemoGetInstanceCache, MemoCacheInstanceData);
1718 X(MemoSetInstanceCache, MemoCacheInstanceData);
1719 X(SetOpProp, SetOpData);
1720 X(SetOpCell, SetOpData);
1721 X(SetOpCellVerify, SetOpData);
1722 X(IncDecProp, IncDecData);
1723 X(SetOpElem, SetOpData);
1724 X(IncDecElem, IncDecData);
1725 X(StArResumeAddr, ResumeOffset);
1726 X(StContArState, GeneratorState);
1727 X(ContEnter, ContEnterData);
1728 X(DbgAssertARFunc, IRSPRelOffsetData);
1729 X(AssertARFunc, IRSPRelOffsetData);
1730 X(LdARFuncPtr, IRSPRelOffsetData);
1731 X(LdARIsDynamic, IRSPRelOffsetData);
1732 X(LdARCtx, IRSPRelOffsetData);
1733 X(EagerSyncVMRegs, IRSPRelOffsetData);
1734 X(JmpSSwitchDest, IRSPRelOffsetData);
1735 X(DbgTrashStk, IRSPRelOffsetData);
1736 X(DbgTrashFrame, IRSPRelOffsetData);
1737 X(DbgTraceCall, IRSPRelOffsetData);
1738 X(LdPropAddr, ByteOffsetData);
1739 X(LdInitPropAddr, ByteOffsetData);
1740 X(NewCol, NewColData);
1741 X(NewColFromArray, NewColData);
1742 X(InitExtraArgs, FuncEntryData);
1743 X(CheckSurpriseFlagsEnter, FuncEntryData);
1744 X(CheckSurpriseAndStack, FuncEntryData);
1745 X(ContPreNext, IsAsyncData);
1746 X(ContStartedCheck, IsAsyncData);
1747 X(ContValid, IsAsyncData);
1748 X(LdContResumeAddr, IsAsyncData);
1749 X(LdContActRec, IsAsyncData);
1750 X(DecRef, DecRefData);
1751 X(DecRefNZ, DecRefData);
1752 X(LdTVAux, LdTVAuxData);
1753 X(CheckRefs, CheckRefsData);
1754 X(FuncGuard, FuncGuardData);
1755 X(RaiseHackArrParamNotice, RaiseHackArrParamNoticeData);
1756 X(RaiseHackArrPropNotice, RaiseHackArrNoticeData);
1757 X(DbgAssertRefCount, AssertReason);
1758 X(Unreachable, AssertReason);
1759 X(EndBlock, AssertReason);
1760 X(VerifyRetCallable, ParamData);
1761 X(VerifyRetCls, ParamData);
1762 X(VerifyRetFail, ParamData);
1763 X(VerifyRetFailHard, ParamData);
1764 X(VerifyReifiedLocalType, ParamData);
1765 X(EndCatch, EndCatchData);
1767 #undef X
1769 //////////////////////////////////////////////////////////////////////
1771 template<bool hasExtra, Opcode opc, class T> struct AssertExtraTypes {
1772 static void doassertx() {
1773 assertx(!"called extra on an opcode without extra data");
1775 static void doassert_same() {
1776 assertx(!"called extra on an opcode without extra data");
1780 template<Opcode opc, class T> struct AssertExtraTypes<true,opc,T> {
1781 typedef typename IRExtraDataType<opc>::type ExtraType;
1783 static void doassertx() {
1784 if (!std::is_base_of<T,ExtraType>::value) {
1785 assertx(!"extra<T> was called with an extra data "
1786 "type that doesn't match the opcode type");
1789 static void doassert_same() {
1790 if (!std::is_same<T,ExtraType>::value) {
1791 fprintf(stderr, "opcode = %s\n", opcodeName(opc)); \
1792 assertx(!"extra<T> was called with an extra data type that "
1793 "doesn't exactly match the opcode type");
1798 // Asserts that Opcode opc has extradata and it is of type T, or a
1799 // type derived from T.
1800 template<class T> void assert_opcode_extra(Opcode opc) {
1801 #define O(opcode, dstinfo, srcinfo, flags) \
1802 case opcode: \
1803 AssertExtraTypes< \
1804 OpHasExtraData<opcode>::value,opcode,T \
1805 >::doassertx(); \
1806 break;
1807 switch (opc) { IR_OPCODES default: not_reached(); }
1808 #undef O
1811 template<class T> void assert_opcode_extra_same(Opcode opc) {
1812 #define O(opcode, dstinfo, srcinfo, flags) \
1813 case opcode: \
1814 AssertExtraTypes< \
1815 OpHasExtraData<opcode>::value,opcode,T \
1816 >::doassert_same(); \
1817 break;
1818 switch (opc) { IR_OPCODES default: not_reached(); }
1819 #undef O
1822 size_t hashExtra(Opcode opc, const IRExtraData* data);
1823 bool equalsExtra(Opcode opc, const IRExtraData* a, const IRExtraData* b);
1824 IRExtraData* cloneExtra(Opcode opc, IRExtraData* data, Arena& a);
1825 std::string showExtra(Opcode opc, const IRExtraData* data);
1827 //////////////////////////////////////////////////////////////////////
1831 #endif