Fix bug involving inlining and bytecode control flow
[hiphop-php.git] / hphp / runtime / vm / jit / extra-data.h
blob39c23f5339692e6a8bf00a07eacdd6308ec6655f
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 <algorithm>
22 #include "hphp/runtime/ext/ext_generator.h"
24 #include "hphp/runtime/vm/jit/ir-opcode.h"
25 #include "hphp/runtime/vm/jit/types.h"
26 #include "hphp/runtime/vm/bytecode.h"
27 #include "hphp/runtime/vm/srckey.h"
28 #include "hphp/util/arena.h"
29 #include "hphp/util/ringbuffer.h"
31 namespace HPHP { namespace jit {
33 //////////////////////////////////////////////////////////////////////
36 * Some IRInstructions with compile-time-only constants may carry
37 * along extra data in the form of one of these structures.
39 * Note that this isn't really appropriate for compile-time constants
40 * that are actually representing user values (we want them to be
41 * visible to optimization passes, allocatable to registers, etc),
42 * just compile-time metadata.
44 * These types must:
46 * - Derive from IRExtraData (for overloading purposes)
47 * - Be arena-allocatable (no non-trivial destructors)
48 * - Either CopyConstructible, or implement a clone member
49 * function that takes an arena to clone to
51 * In addition, for extra data used with a cse-able instruction:
53 * - Implement an cseEquals() member that indicates equality for CSE
54 * purposes.
55 * - Implement a cseHash() method.
57 * Finally, optionally they may implement a show() method for use in
58 * debug printouts.
62 * Traits that returns the type of the extra C++ data structure for a
63 * given instruction, if it has one, along with some other information
64 * about the type.
66 template<Opcode op> struct OpHasExtraData { enum { value = 0 }; };
67 template<Opcode op> struct IRExtraDataType;
69 //////////////////////////////////////////////////////////////////////
71 struct IRExtraData {};
73 struct LdBindAddrData : IRExtraData {
74 explicit LdBindAddrData(SrcKey sk)
75 : sk(sk)
78 std::string show() const { return showShort(sk); }
80 SrcKey sk;
83 struct LdSSwitchData : IRExtraData {
84 struct Elm {
85 const StringData* str;
86 SrcKey dest;
89 explicit LdSSwitchData() = default;
90 LdSSwitchData(const LdSSwitchData&) = delete;
91 LdSSwitchData& operator=(const LdSSwitchData&) = delete;
93 LdSSwitchData* clone(Arena& arena) const {
94 LdSSwitchData* target = new (arena) LdSSwitchData;
95 target->numCases = numCases;
96 target->defaultSk = defaultSk;
97 target->cases = new (arena) Elm[numCases];
98 std::copy(cases, cases + numCases, const_cast<Elm*>(target->cases));
99 return target;
102 int64_t numCases;
103 const Elm* cases;
104 SrcKey defaultSk;
107 struct JmpSwitchData : IRExtraData {
108 JmpSwitchData* clone(Arena& arena) const {
109 JmpSwitchData* sd = new (arena) JmpSwitchData;
110 sd->base = base;
111 sd->bounded = bounded;
112 sd->cases = cases;
113 sd->defaultSk = defaultSk;
114 sd->targets = new (arena) SrcKey[cases];
115 std::copy(targets, targets + cases, const_cast<SrcKey*>(sd->targets));
116 return sd;
119 int64_t base; // base of switch case
120 bool bounded; // whether switch is bounded or not
121 int32_t cases; // number of cases
122 SrcKey defaultSk; // srckey of default case
123 SrcKey* targets; // srckeys for all targets
126 struct LocalId : IRExtraData {
127 explicit LocalId(uint32_t id)
128 : locId(id)
131 bool cseEquals(LocalId o) const { return locId == o.locId; }
132 size_t cseHash() const { return std::hash<uint32_t>()(locId); }
133 std::string show() const { return folly::to<std::string>(locId); }
135 uint32_t locId;
138 struct IterId : IRExtraData {
139 explicit IterId(uint32_t id)
140 : iterId(id)
143 bool cseEquals(IterId o) const { return iterId == o.iterId; }
144 size_t cseHash() const { return std::hash<uint32_t>()(iterId); }
145 std::string show() const { return folly::to<std::string>(iterId); }
147 uint32_t iterId;
150 struct IterData : IRExtraData {
151 explicit IterData(uint32_t iter, uint32_t key, uint32_t val)
152 : iterId(iter), keyId(key), valId(val)
154 std::string show() const {
155 if (keyId == -1) return folly::format("{}::{}", iterId, valId).str();
157 return folly::format("{}::{}::{}", iterId, keyId, valId).str();
160 uint32_t iterId;
161 uint32_t keyId;
162 uint32_t valId;
165 struct RDSHandleData : IRExtraData {
166 explicit RDSHandleData(RDS::Handle handle)
167 : handle(handle)
170 bool cseEquals(RDSHandleData o) const { return handle == o.handle; }
171 size_t cseHash() const { return std::hash<uint32_t>()(handle); }
172 std::string show() const {
173 return folly::to<std::string>(handle);
176 RDS::Handle handle;
179 struct ClassData : IRExtraData {
180 explicit ClassData(const Class* cls) : cls(cls) {}
181 std::string show() const {
182 return folly::to<std::string>(cls->name()->data());
184 const Class* cls;
187 struct FuncData : IRExtraData {
188 explicit FuncData(const Func* func) : func(func) {}
190 bool cseEquals(FuncData o) const { return func == o.func; }
191 size_t cseHash() const { return std::hash<const Func*>()(func); }
192 std::string show() const {
193 return folly::to<std::string>(func->fullName()->data());
196 const Func* func;
199 struct ClsMethodData : IRExtraData {
200 ClsMethodData(const StringData* cls, const StringData* method,
201 const NamedEntity* ne = nullptr)
202 : clsName(cls)
203 , methodName(method)
204 , namedEntity(ne)
207 std::string show() const {
208 return folly::format("{}::{}", *clsName, *methodName).str();
211 bool cseEquals(const ClsMethodData& b) const {
212 // Strings are static so we can use pointer equality
213 return clsName == b.clsName && methodName == b.methodName;
215 size_t cseHash() const {
216 return hash_int64_pair((uintptr_t)clsName, (uintptr_t)methodName);
219 const StringData* clsName;
220 const StringData* methodName;
221 const NamedEntity* namedEntity;
224 struct FPushCufData : IRExtraData {
225 FPushCufData(int32_t spOffset, uint32_t a, int32_t id)
226 : spOffset(spOffset)
227 , args(a)
228 , iterId(id)
231 bool cseEquals(FPushCufData o) const {
232 return iterId == o.iterId && args == o.args;
234 size_t cseHash() const {
235 return std::hash<uint32_t>()(iterId) ^ std::hash<uint32_t>()(args);
237 std::string show() const {
238 return folly::to<std::string>(spOffset, ',', iterId, ',', args);
241 int32_t spOffset;
242 uint32_t args;
243 uint32_t iterId;
247 * Information for REQ_RETRANSLATE stubs.
249 struct ReqRetranslateData : IRExtraData {
250 TransFlags trflags;
252 explicit ReqRetranslateData(TransFlags trflags)
253 : trflags(trflags)
256 std::string show() const {
257 return folly::to<std::string>(trflags.packed);
262 * Information for REQ_BIND_JMP stubs.
264 struct ReqBindJmpData : IRExtraData {
265 SrcKey dest;
266 TransFlags trflags;
268 explicit ReqBindJmpData(const SrcKey& dest,
269 TransFlags trflags = TransFlags{})
270 : dest(dest)
271 , trflags(trflags)
274 std::string show() const {
275 return folly::to<std::string>(dest.offset(), ',', trflags.packed);
280 * Compile-time metadata about an ActRec allocation.
282 struct ActRecInfo : IRExtraData {
283 int32_t spOffset;
284 const StringData* invName; // may be nullptr
285 int32_t numArgs;
287 bool isFromFPushCtor() const {
288 ActRec ar;
289 ar.m_numArgsAndFlags = numArgs;
290 return ar.isFromFPushCtor();
293 std::string show() const {
294 ActRec ar;
295 ar.m_numArgsAndFlags = numArgs;
296 return folly::to<std::string>(spOffset, ',',
297 ar.numArgs(),
298 ar.isFromFPushCtor() ? ",ctor" : "",
299 ar.resumed() ? ",res" : "",
300 ar.localsDecRefd() ? ",ldrd" : "",
301 invName ? " M" : "");
305 struct StackOffset : IRExtraData {
306 explicit StackOffset(int32_t offset) : offset(offset) {}
308 std::string show() const { return folly::to<std::string>(offset); }
310 bool cseEquals(StackOffset o) const { return offset == o.offset; }
311 size_t cseHash() const { return std::hash<int32_t>()(offset); }
313 int32_t offset;
316 struct PropOffset : IRExtraData {
317 explicit PropOffset(int32_t offset) : offsetBytes(offset) {}
319 std::string show() const { return folly::to<std::string>(offsetBytes); }
320 bool cseEquals(PropOffset o) const { return offsetBytes == o.offsetBytes; }
321 size_t cseHash() const { return std::hash<int32_t>()(offsetBytes); }
323 int32_t offsetBytes;
326 struct ProfileStrData : IRExtraData {
327 explicit ProfileStrData(const StringData* key)
328 : key(key)
331 std::string show() const { return key->data(); }
333 const StringData* key;
337 * Translation IDs.
339 struct TransIDData : IRExtraData {
340 explicit TransIDData(TransID transId) : transId(transId) {}
341 std::string show() const { return folly::to<std::string>(transId); }
342 TransID transId;
346 * Information needed to generate a REQ_RETRANSLATE_OPT service request.
348 struct ReqRetransOptData : IRExtraData {
349 explicit ReqRetransOptData(TransID transId, SrcKey sk)
350 : transId(transId), sk(sk) {}
351 std::string show() const {
352 return folly::to<std::string>(transId, ',', sk.offset());
354 TransID transId;
355 SrcKey sk;
359 * Offset to a TypedValue from some base pointer, in bytes. (E.g. to
360 * a object property slot.)
362 struct PropByteOffset : IRExtraData {
363 explicit PropByteOffset(size_t offsetBytes) : offsetBytes(offsetBytes) {}
364 std::string show() const { return folly::to<std::string>(offsetBytes); }
365 size_t offsetBytes;
369 * DefInlineFP is present when we need to create a frame for inlining. This
370 * instruction also carries some metadata used by IRBuilder to track state
371 * during an inlined call.
373 struct DefInlineFPData : IRExtraData {
374 std::string show() const {
375 return folly::to<std::string>(
376 target->fullName()->data(), "(),",
377 fromFPushCtor ? "ctor," : "",
378 retBCOff, ',',
379 retSPOff, ',',
380 spOffset
384 const Func* target;
385 bool fromFPushCtor;
386 SSATmp* ctx; // Ctx, Cls or Nullptr.
387 Offset retBCOff;
388 Offset retSPOff;
389 int32_t spOffset; // offset from caller SP to callee SP
392 struct CallArrayData : IRExtraData {
393 explicit CallArrayData(int32_t spOffset,
394 Offset pcOffset,
395 Offset after,
396 bool destroyLocals)
397 : spOffset(spOffset)
398 , pc(pcOffset)
399 , after(after)
400 , destroyLocals(destroyLocals)
403 std::string show() const {
404 return folly::to<std::string>(pc, ",", after,
405 destroyLocals ? ",destroyLocals" : "");
408 int32_t spOffset; // offset from StkPtr to bottom of call's ActRec+args
409 Offset pc; // XXX why isn't this available in the marker?
410 Offset after; // offset from unit m_bc (unlike m_soff in ActRec)
411 bool destroyLocals;
414 struct CallBuiltinData : IRExtraData {
415 explicit CallBuiltinData(int32_t spOffset,
416 const Func* callee,
417 bool destroyLocals)
418 : spOffset{spOffset}
419 , callee{callee}
420 , destroyLocals{destroyLocals}
423 std::string show() const {
424 return folly::to<std::string>(
425 spOffset, ',',
426 callee->fullName()->data(),
427 destroyLocals ? ",destroyLocals" : ""
431 int32_t spOffset; // offset from StkPtr to last passed arg
432 const Func* callee;
433 bool destroyLocals;
436 struct CallData : IRExtraData {
437 explicit CallData(int32_t spOffset,
438 uint32_t numParams,
439 Offset after,
440 const Func* callee,
441 bool destroy)
442 : spOffset(spOffset)
443 , numParams(numParams)
444 , after(after)
445 , callee(callee)
446 , destroyLocals(destroy)
449 std::string show() const {
450 return folly::to<std::string>(
451 spOffset, ',', numParams, ',', after,
452 callee
453 ? folly::format(",{}", callee->fullName()->data()).str()
454 : std::string{},
455 destroyLocals ? ",destroyLocals" : ""
459 int32_t spOffset; // offset from StkPtr to bottom of call's ActRec+args
460 uint32_t numParams;
461 Offset after; // m_soff style: offset from func->base()
462 const Func* callee; // nullptr if not statically known
463 bool destroyLocals;
466 struct RetCtrlData : IRExtraData {
467 explicit RetCtrlData(int32_t spOffset, bool suspendingResumed)
468 : spOffset(spOffset)
469 , suspendingResumed(suspendingResumed)
472 std::string show() const {
473 return folly::to<std::string>(
474 spOffset,
475 suspendingResumed ? ",suspendingResumed" : ""
479 // Adjustment we need to make to the stack pointer (for cross-tracelet ABI
480 // purposes) before returning.
481 int32_t spOffset;
483 // Indicates that the current generator frame is being suspended without
484 // decrefing locals. Used by refcount optimizer.
485 bool suspendingResumed;
489 * Name of a class constant.
491 struct ClsCnsName : IRExtraData {
492 explicit ClsCnsName(const StringData* cls, const StringData* cns)
493 : clsName(cls)
494 , cnsName(cns)
497 std::string show() const {
498 return folly::to<std::string>(clsName->data(), "::", cnsName->data());
501 const StringData* clsName;
502 const StringData* cnsName;
506 * The name of a static local in a function.
508 struct StaticLocName : IRExtraData {
509 StaticLocName(const Func* func, const StringData* name)
510 : func(func)
511 , name(name)
514 std::string show() const {
515 return folly::to<std::string>(
516 func->fullName()->data(), "$", name->data()
520 const Func* func;
521 const StringData* name;
524 struct LdFuncCachedData : IRExtraData {
525 explicit LdFuncCachedData(const StringData* name)
526 : name(name)
529 std::string show() const {
530 return folly::to<std::string>(name->data());
533 size_t cseHash() const { return name->hash(); }
534 bool cseEquals(const LdFuncCachedData& o) const {
535 return name == o.name;
538 const StringData* name;
541 struct LdObjMethodData : IRExtraData {
542 explicit LdObjMethodData(int32_t offset,
543 const StringData* method,
544 bool fatal)
545 : offset(offset)
546 , method(method)
547 , fatal(fatal)
550 std::string show() const {
551 return folly::to<std::string>(offset, ',', method->data(), ',',
552 fatal ? "fatal" : "warn");
555 int32_t offset;
556 const StringData* method;
557 bool fatal;
560 struct LdFuncCachedUData : IRExtraData {
561 explicit LdFuncCachedUData(const StringData* name,
562 const StringData* fallback)
563 : name(name)
564 , fallback(fallback)
567 std::string show() const {
568 return folly::to<std::string>(name->data(), ',', fallback->data());
571 size_t cseHash() const {
572 return hash_int64_pair(name->hash(), fallback->hash());
574 bool cseEquals(const LdFuncCachedUData& o) const {
575 return name == o.name && fallback == o.fallback;
578 const StringData* name;
579 const StringData* fallback;
583 * The name of a class, and the expected Class* at runtime.
585 struct CheckDefinedClsData : IRExtraData {
586 CheckDefinedClsData(const StringData* clsName, const Class* cls)
587 : clsName(clsName)
588 , cls(cls)
591 std::string show() const {
592 return folly::to<std::string>(clsName->data());
595 const StringData* clsName;
596 const Class* cls;
600 * Offset and stack deltas for InterpOne.
602 struct InterpOneData : IRExtraData {
603 struct LocalType {
604 explicit LocalType(uint32_t id = 0, Type type = Type::Bottom)
605 : id(id)
606 , type(type)
609 uint32_t id;
610 Type type;
613 explicit InterpOneData(int32_t spOffset)
614 : spOffset(spOffset)
615 , nChangedLocals(0)
616 , changedLocals(nullptr)
617 , smashesAllLocals(false)
620 // Delta from the StkPtr src to the top of the stack.
621 int32_t spOffset;
623 // Offset of the instruction to interpret, in the Unit indicated by
624 // the current Marker.
625 Offset bcOff;
627 // The number of stack cells consumed and produced by the
628 // instruction, respectively. Includes ActRecs.
629 int64_t cellsPopped;
630 int64_t cellsPushed;
632 // Opcode, in case we need to fix the stack differently. Some byte-
633 // code instructions modify things below the top of the stack.
634 Op opcode;
636 uint32_t nChangedLocals;
637 LocalType* changedLocals;
639 bool smashesAllLocals;
641 InterpOneData* clone(Arena& arena) const {
642 auto* id = new (arena) InterpOneData(spOffset);
643 id->bcOff = bcOff;
644 id->cellsPopped = cellsPopped;
645 id->cellsPushed = cellsPushed;
646 id->opcode = opcode;
647 id->nChangedLocals = nChangedLocals;
648 id->changedLocals = new (arena) LocalType[nChangedLocals];
649 id->smashesAllLocals = smashesAllLocals;
650 std::copy(changedLocals, changedLocals + nChangedLocals, id->changedLocals);
651 return id;
654 std::string show() const {
655 auto ret = folly::sformat(
656 "{}: spOff:{}, bcOff:{}, popped:{}, pushed:{}",
657 opcodeToName(opcode),
658 spOffset,
659 bcOff,
660 cellsPopped,
661 cellsPushed
663 assert(!smashesAllLocals || !nChangedLocals);
664 if (smashesAllLocals) ret += ", smashes all locals";
665 if (nChangedLocals) {
666 for (auto i = 0; i < nChangedLocals; ++i) {
667 ret += folly::sformat(", Local {} -> {}",
668 changedLocals[i].id,
669 changedLocals[i].type);
673 return ret;
677 struct CoerceStkData : IRExtraData {
678 explicit CoerceStkData(int64_t off, const Func* f, int64_t arg_num)
679 : offset(off), callee(f), argNum(arg_num) {}
681 std::string show() const {
682 return folly::format(
683 "{},{},{}",
684 offset,
685 callee->name()->data(),
686 argNum
687 ).str();
690 int32_t offset;
691 const Func* callee;
692 int32_t argNum;
695 struct CoerceData : IRExtraData {
696 explicit CoerceData(const Func* f, int64_t arg_num)
697 : callee(f), argNum(arg_num) {}
699 std::string show() const {
700 return folly::format(
701 "{},{}",
702 callee->name()->data(),
703 argNum
704 ).str();
707 const Func* callee;
708 int64_t argNum;
711 struct RBTraceData : IRExtraData {
712 RBTraceData(Trace::RingBufferType t, SrcKey sk)
713 : type(t)
714 , sk(sk)
715 , msg(nullptr)
718 RBTraceData(Trace::RingBufferType t, const StringData* msg)
719 : type(t)
720 , sk()
721 , msg(msg)
723 assert(msg->isStatic());
726 std::string show() const {
727 auto const data = msg ? msg->data() : showShort(sk);
728 return folly::format("{}: {}", ringbufferName(type), data).str();
731 Trace::RingBufferType type;
732 SrcKey sk;
733 const StringData* msg;
736 struct ClassKindData : IRExtraData {
737 explicit ClassKindData(ClassKind kind): kind(uint32_t(kind)) {}
739 std::string show() const {
740 switch (static_cast<ClassKind>(kind)) {
741 case ClassKind::Class: return "cls";
742 case ClassKind::Interface: return "interface";
743 case ClassKind::Trait: return "trait";
744 case ClassKind::Enum: return "enum";
746 not_reached();
749 uint32_t kind; // ... allows for direct usage in native_call
752 struct NewStructData : IRExtraData {
753 std::string show() const;
754 int32_t offset;
755 uint32_t numKeys;
756 StringData** keys;
759 struct PackedArrayData : IRExtraData {
760 explicit PackedArrayData(uint32_t size) : size(size) {}
761 std::string show() const { return folly::format("{}", size).str(); }
762 uint32_t size;
765 struct InitPackedArrayLoopData : IRExtraData {
766 explicit InitPackedArrayLoopData(int32_t offset, uint32_t size)
767 : offset(offset)
768 , size(size)
771 std::string show() const {
772 return folly::format("{},{}", offset, size).str();
775 int32_t offset;
776 uint32_t size;
779 struct IndexData : IRExtraData {
780 explicit IndexData(uint32_t index) : index(index) {}
781 uint32_t index;
782 std::string show() const { return folly::format("{}", index).str(); }
785 struct ClsNeqData : IRExtraData {
786 explicit ClsNeqData(Class* testClass) : testClass(testClass) {}
788 std::string show() const {
789 return testClass->name()->data();
792 bool cseEquals(ClsNeqData o) const { return testClass == o.testClass; }
793 size_t cseHash() const { return std::hash<Class*>()(testClass); }
795 Class* testClass; // class we're checking equality with
798 struct MInstrAttrData : IRExtraData {
799 explicit MInstrAttrData(MInstrAttr mia) : mia(mia) {}
800 std::string show() const {
801 using U = std::underlying_type<MInstrAttr>::type;
802 return folly::to<std::string>(static_cast<U>(mia));
804 MInstrAttr mia;
807 struct SetOpData : IRExtraData {
808 explicit SetOpData(SetOpOp op) : op(op) {}
809 std::string show() const { return subopToName(op); }
810 SetOpOp op;
813 struct IncDecData : IRExtraData {
814 explicit IncDecData(IncDecOp op) : op(op) {}
815 std::string show() const { return subopToName(op); }
816 IncDecOp op;
819 struct ResumeOffset : IRExtraData {
820 explicit ResumeOffset(Offset off) : off(off) {}
821 std::string show() const { return folly::to<std::string>(off); }
822 Offset off;
825 struct GeneratorState : IRExtraData {
826 explicit GeneratorState(BaseGenerator::State state) : state(state) {}
827 std::string show() const {
828 using U = std::underlying_type<BaseGenerator::State>::type;
829 return folly::to<std::string>(static_cast<U>(state));
831 BaseGenerator::State state;
834 struct ContEnterData : IRExtraData {
835 explicit ContEnterData(int32_t spOffset, Offset returnBCOffset)
836 : spOffset(spOffset)
837 , returnBCOffset(returnBCOffset)
840 std::string show() const {
841 return folly::to<std::string>(spOffset, ',', returnBCOffset);
844 int32_t spOffset;
845 Offset returnBCOffset;
848 //////////////////////////////////////////////////////////////////////
850 #define X(op, data) \
851 template<> struct IRExtraDataType<op> { typedef data type; }; \
852 template<> struct OpHasExtraData<op> { enum { value = 1 }; }; \
853 static_assert(boost::has_trivial_destructor<data>::value, \
854 "IR extra data type must be trivially destructible")
856 X(LdBindAddr, LdBindAddrData);
857 X(JmpSwitchDest, JmpSwitchData);
858 X(LdSSwitchDestFast, LdSSwitchData);
859 X(LdSSwitchDestSlow, LdSSwitchData);
860 X(GuardLoc, LocalId);
861 X(HintLocInner, LocalId);
862 X(CheckLoc, LocalId);
863 X(AssertLoc, LocalId);
864 X(LdLocAddr, LocalId);
865 X(LdLoc, LocalId);
866 X(LdLocPseudoMain, LocalId);
867 X(DecRefLoc, LocalId);
868 X(StLoc, LocalId);
869 X(StLocPseudoMain, LocalId);
870 X(StLocNT, LocalId);
871 X(IterFree, IterId);
872 X(MIterFree, IterId);
873 X(CIterFree, IterId);
874 X(DecodeCufIter, IterId);
875 X(IterInit, IterData);
876 X(IterInitK, IterData);
877 X(IterNext, IterData);
878 X(IterNextK, IterData);
879 X(WIterInit, IterData);
880 X(WIterInitK, IterData);
881 X(WIterNext, IterData);
882 X(WIterNextK, IterData);
883 X(MIterInit, IterData);
884 X(MIterInitK, IterData);
885 X(MIterNext, IterData);
886 X(MIterNextK, IterData);
887 X(ConstructInstance, ClassData);
888 X(CheckInitProps, ClassData);
889 X(InitProps, ClassData);
890 X(CheckInitSProps, ClassData);
891 X(InitSProps, ClassData);
892 X(NewInstanceRaw, ClassData);
893 X(InitObjProps, ClassData);
894 X(CufIterSpillFrame, FPushCufData);
895 X(SpillFrame, ActRecInfo);
896 X(GuardStk, StackOffset);
897 X(HintStkInner, StackOffset);
898 X(CheckStk, StackOffset);
899 X(CastStk, StackOffset);
900 X(StStk, StackOffset);
901 X(CoerceStk, CoerceStkData);
902 X(CoerceCellToInt, CoerceData);
903 X(CoerceCellToDbl, CoerceData);
904 X(CoerceCellToBool, CoerceData);
905 X(CoerceStrToInt, CoerceData);
906 X(CoerceStrToDbl, CoerceData);
907 X(AssertStk, StackOffset);
908 X(ReDefSP, StackOffset);
909 X(DefSP, StackOffset);
910 X(ResetSP, StackOffset);
911 X(LdStk, StackOffset);
912 X(LdStkAddr, StackOffset);
913 X(DecRefStk, StackOffset);
914 X(DefInlineFP, DefInlineFPData);
915 X(ReqRetranslate, ReqRetranslateData);
916 X(ReqBindJmp, ReqBindJmpData);
917 X(ReqRetranslateOpt, ReqRetransOptData);
918 X(CheckCold, TransIDData);
919 X(IncProfCounter, TransIDData);
920 X(Call, CallData);
921 X(CallBuiltin, CallBuiltinData);
922 X(CallArray, CallArrayData);
923 X(RetCtrl, RetCtrlData);
924 X(LdArrFuncCtx, StackOffset);
925 X(LdArrFPushCuf, StackOffset);
926 X(LdStrFPushCuf, StackOffset);
927 X(LookupClsCns, ClsCnsName);
928 X(LookupClsMethod, StackOffset);
929 X(LookupClsMethodCache, ClsMethodData);
930 X(LdClsMethodCacheFunc, ClsMethodData);
931 X(LdClsMethodCacheCls, ClsMethodData);
932 X(LdClsMethodFCacheFunc, ClsMethodData);
933 X(LookupClsMethodFCache, ClsMethodData);
934 X(GetCtxFwdCallDyn, ClsMethodData);
935 X(LdStaticLocCached, StaticLocName);
936 X(LdFuncCached, LdFuncCachedData);
937 X(LdFuncCachedSafe, LdFuncCachedData);
938 X(LdFuncCachedU, LdFuncCachedUData);
939 X(LdObjMethod, LdObjMethodData);
940 X(InterpOne, InterpOneData);
941 X(InterpOneCF, InterpOneData);
942 X(StClosureFunc, FuncData);
943 X(StClosureArg, PropByteOffset);
944 X(RBTrace, RBTraceData);
945 X(OODeclExists, ClassKindData);
946 X(NewStructArray, NewStructData);
947 X(AllocPackedArray, PackedArrayData);
948 X(InitPackedArrayLoop, InitPackedArrayLoopData);
949 X(InitPackedArray, IndexData);
950 X(ProfilePackedArray, RDSHandleData);
951 X(ProfileStructArray, RDSHandleData);
952 X(ProfileStr, ProfileStrData);
953 X(LdRDSAddr, RDSHandleData);
954 X(ClsNeq, ClsNeqData);
955 X(BaseG, MInstrAttrData);
956 X(PropX, MInstrAttrData);
957 X(PropDX, MInstrAttrData);
958 X(ElemX, MInstrAttrData);
959 X(ElemDX, MInstrAttrData);
960 X(ElemUX, MInstrAttrData);
961 X(SetOpProp, SetOpData);
962 X(IncDecProp, IncDecData);
963 X(SetOpElem, SetOpData);
964 X(IncDecElem, IncDecData);
965 X(StAsyncArResume, ResumeOffset);
966 X(StContArResume, ResumeOffset);
967 X(StContArState, GeneratorState);
968 X(ContEnter, ContEnterData);
969 X(LdARFuncPtr, StackOffset);
970 X(EndCatch, StackOffset);
971 X(AdjustSP, StackOffset);
972 X(DbgTrashStk, StackOffset);
973 X(DbgTrashFrame, StackOffset);
974 X(LdPropAddr, PropOffset);
976 #undef X
978 //////////////////////////////////////////////////////////////////////
980 template<bool hasExtra, Opcode opc, class T> struct AssertExtraTypes {
981 static void doassert() {
982 assert(!"called extra on an opcode without extra data");
984 static void doassert_same() {
985 assert(!"called extra on an opcode without extra data");
989 template<Opcode opc, class T> struct AssertExtraTypes<true,opc,T> {
990 typedef typename IRExtraDataType<opc>::type ExtraType;
992 static void doassert() {
993 if (!std::is_base_of<T,ExtraType>::value) {
994 assert(!"extra<T> was called with an extra data "
995 "type that doesn't match the opcode type");
998 static void doassert_same() {
999 if (!std::is_same<T,ExtraType>::value) {
1000 assert(!"extra<T> was called with an extra data type that "
1001 "doesn't exactly match the opcode type");
1006 // Asserts that Opcode opc has extradata and it is of type T, or a
1007 // type derived from T.
1008 template<class T> void assert_opcode_extra(Opcode opc) {
1009 #define O(opcode, dstinfo, srcinfo, flags) \
1010 case opcode: \
1011 AssertExtraTypes< \
1012 OpHasExtraData<opcode>::value,opcode,T \
1013 >::doassert(); \
1014 break;
1015 switch (opc) { IR_OPCODES default: not_reached(); }
1016 #undef O
1019 template<class T> void assert_opcode_extra_same(Opcode opc) {
1020 #define O(opcode, dstinfo, srcinfo, flags) \
1021 case opcode: \
1022 AssertExtraTypes< \
1023 OpHasExtraData<opcode>::value,opcode,T \
1024 >::doassert_same(); \
1025 break;
1026 switch (opc) { IR_OPCODES default: not_reached(); }
1027 #undef O
1030 size_t cseHashExtra(Opcode opc, const IRExtraData* data);
1031 bool cseEqualsExtra(Opcode opc, const IRExtraData* a, const IRExtraData* b);
1032 IRExtraData* cloneExtra(Opcode opc, IRExtraData* data, Arena& a);
1033 std::string showExtra(Opcode opc, const IRExtraData* data);
1035 //////////////////////////////////////////////////////////////////////
1039 #endif