2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_VM_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/Optional.h>
41 namespace HPHP
{ namespace jit
{
43 //////////////////////////////////////////////////////////////////////
46 * Some IRInstructions with compile-time-only constants may carry along extra
47 * data in the form of one of these structures.
49 * Note that this isn't really appropriate for compile-time constants that are
50 * actually representing user values (we want them to be visible to
51 * optimization passes, allocatable to registers, etc), just compile-time
56 * - Derive from IRExtraData (for overloading purposes).
57 * - Be arena-allocatable (no non-trivial destructors).
58 * - Either CopyConstructible, or implement a clone member function that
59 * takes an arena to clone to.
61 * In addition, extra data belonging to IRInstructions that may be hashed in
64 * - Implement an equals() member that indicates equality.
65 * - Implement a hash() method.
67 * Finally, optionally they may implement a show() method for use in debug
72 * Traits that returns the type of the extra C++ data structure for a
73 * given instruction, if it has one, along with some other information
76 template<Opcode op
> struct OpHasExtraData
{ enum { value
= 0 }; };
77 template<Opcode op
> struct IRExtraDataType
;
79 //////////////////////////////////////////////////////////////////////
81 struct IRExtraData
{};
83 //////////////////////////////////////////////////////////////////////
86 * Shared IRExtraData classes.
88 * These subtypes represent common parameters (e.g., statically known Func,
89 * local variable ID, stack offset, etc.) that are useful for a variety of HHIR
92 * These are kept separate from the one-off IRExtraDatas to make it easier to
93 * find existing common parameters.
97 * Offset in bytes from a base pointer---e.g., to a object property from an
100 struct ByteOffsetData
: IRExtraData
{
101 explicit ByteOffsetData(ptrdiff_t offset
) : offsetBytes(offset
) {}
103 std::string
show() const { return folly::to
<std::string
>(offsetBytes
); }
105 bool equals(ByteOffsetData o
) const { return offsetBytes
== o
.offsetBytes
; }
106 size_t hash() const { return std::hash
<ptrdiff_t>()(offsetBytes
); }
108 ptrdiff_t offsetBytes
;
114 * Required to be non-null.
116 struct ClassData
: IRExtraData
{
117 explicit ClassData(const Class
* cls
)
120 assert(cls
!= nullptr);
123 std::string
show() const {
124 return folly::to
<std::string
>(cls
->name()->data());
127 bool equals(const ClassData
& o
) const {
131 size_t hash() const {
132 return hash_int64(reinterpret_cast<intptr_t>(cls
));
141 struct ExtendsClassData
: IRExtraData
{
142 explicit ExtendsClassData(const Class
* cls
, bool strictLikely
= false)
143 : cls(cls
), strictLikely(strictLikely
)
145 assert(cls
!= nullptr);
148 std::string
show() const {
149 return folly::sformat("{}{}",
150 cls
->name(), strictLikely
? ":strictLikely" : "");
153 bool equals(const ExtendsClassData
& o
) const {
154 return cls
== o
.cls
&& strictLikely
== o
.strictLikely
;
157 size_t hash() const {
158 return pointer_hash
<Class
>()(cls
);
166 * Class with method name.
168 struct ClsMethodData
: IRExtraData
{
169 ClsMethodData(const StringData
* cls
, const StringData
* method
,
170 const NamedEntity
* ne
= nullptr)
176 std::string
show() const {
177 return folly::format("{}::{}", clsName
, methodName
).str();
180 bool equals(const ClsMethodData
& o
) const {
181 // The strings are static so we can use pointer equality.
182 return clsName
== o
.clsName
&& methodName
== o
.methodName
;
184 size_t hash() const {
185 return hash_int64_pair((intptr_t)clsName
, (intptr_t)methodName
);
188 const StringData
* clsName
;
189 const StringData
* methodName
;
190 const NamedEntity
* namedEntity
;
193 struct IfaceMethodData
: IRExtraData
{
194 IfaceMethodData(Slot vtableIdx
, Slot methodIdx
)
195 : vtableIdx(vtableIdx
)
196 , methodIdx(methodIdx
)
199 std::string
show() const {
200 return folly::sformat("{}, {}", vtableIdx
, methodIdx
);
203 bool equals(const IfaceMethodData
& o
) const {
204 return vtableIdx
== o
.vtableIdx
&& methodIdx
== o
.methodIdx
;
207 size_t hash() const {
208 return hash_int64((int64_t)vtableIdx
<< 32 | methodIdx
);
216 * Func with argument index.
218 struct FuncArgData
: IRExtraData
{
219 explicit FuncArgData(const Func
* f
, int64_t arg
)
224 std::string
show() const {
225 return folly::format("{},{}", func
->name(), argNum
).str();
235 struct LocalId
: IRExtraData
{
236 explicit LocalId(uint32_t id
) : locId(id
) {}
238 std::string
show() const { return folly::to
<std::string
>(locId
); }
240 bool equals(LocalId o
) const { return locId
== o
.locId
; }
241 size_t hash() const { return std::hash
<uint32_t>()(locId
); }
246 struct ClsRefSlotData
: IRExtraData
{
247 explicit ClsRefSlotData(uint32_t slot
) : slot
{slot
} {}
249 std::string
show() const { return folly::to
<std::string
>(slot
); }
251 bool equals(ClsRefSlotData o
) const { return slot
== o
.slot
; }
252 size_t hash() const { return std::hash
<uint32_t>()(slot
); }
258 * Index into, e.g., an array.
260 struct IndexData
: IRExtraData
{
261 explicit IndexData(uint32_t index
) : index(index
) {}
263 std::string
show() const { return folly::format("{}", index
).str(); }
271 struct IterId
: IRExtraData
{
272 explicit IterId(uint32_t id
)
276 std::string
show() const { return folly::to
<std::string
>(iterId
); }
278 bool equals(IterId o
) const { return iterId
== o
.iterId
; }
279 size_t hash() const { return std::hash
<uint32_t>()(iterId
); }
285 * Iter instruction data.
287 * `iterId' is the iterator ID; `keyId' and `valId' are the IDs of the iterator
288 * locals $key => $value. For keyless iterators, we still use this class, with
289 * `keyId` set to -1u.
291 struct IterData
: IRExtraData
{
292 explicit IterData(uint32_t iter
, uint32_t key
, uint32_t val
)
298 std::string
show() const {
299 if (keyId
== -1) return folly::format("{}::{}", iterId
, valId
).str();
300 return folly::format("{}::{}::{}", iterId
, keyId
, valId
).str();
311 struct RDSHandleData
: IRExtraData
{
312 explicit RDSHandleData(rds::Handle handle
) : handle(handle
) {}
314 std::string
show() const { return folly::to
<std::string
>(handle
); }
316 bool equals(RDSHandleData o
) const { return handle
== o
.handle
; }
317 size_t hash() const { return std::hash
<uint32_t>()(handle
); }
325 * Used with profiling-related instructions.
327 struct TransIDData
: IRExtraData
{
328 explicit TransIDData(TransID transId
) : transId(transId
) {}
330 std::string
show() const { return folly::to
<std::string
>(transId
); }
336 * FP-relative offset.
338 struct FPRelOffsetData
: IRExtraData
{
339 explicit FPRelOffsetData(FPRelOffset offset
) : offset(offset
) {}
341 std::string
show() const {
342 return folly::to
<std::string
>("FPRelOff ", offset
.offset
);
345 bool equals(FPRelOffsetData o
) const { return offset
== o
.offset
; }
346 size_t hash() const { return std::hash
<int32_t>()(offset
.offset
); }
352 * Stack pointer offset.
354 struct FPInvOffsetData
: IRExtraData
{
355 explicit FPInvOffsetData(FPInvOffset offset
) : offset(offset
) {}
357 std::string
show() const {
358 return folly::to
<std::string
>("FPInvOff ", offset
.offset
);
361 bool equals(FPInvOffsetData o
) const { return offset
== o
.offset
; }
362 size_t hash() const { return std::hash
<int32_t>()(offset
.offset
); }
370 struct IRSPRelOffsetData
: IRExtraData
{
371 explicit IRSPRelOffsetData(IRSPRelOffset offset
) : offset(offset
) {}
373 std::string
show() const {
374 return folly::to
<std::string
>("IRSPOff ", offset
.offset
);
377 bool equals(IRSPRelOffsetData o
) const { return offset
== o
.offset
; }
378 size_t hash() const { return std::hash
<int32_t>()(offset
.offset
); }
380 IRSPRelOffset offset
;
383 ///////////////////////////////////////////////////////////////////////////////
386 * One-off IRExtraData classes.
388 * These are used for only one or two instructions and are in no particular
389 * order. Add new IRExtraData types here.
392 struct IsAsyncData
: IRExtraData
{
393 explicit IsAsyncData(bool isAsync
) : isAsync(isAsync
) {}
395 std::string
show() const { return folly::to
<std::string
>(isAsync
); }
396 bool equals(IsAsyncData d
) const { return isAsync
== d
.isAsync
; }
397 size_t hash() const { return std::hash
<int32_t>()(isAsync
); }
402 struct LdBindAddrData
: IRExtraData
{
403 explicit LdBindAddrData(SrcKey sk
, FPInvOffset bcSPOff
)
408 std::string
show() const { return showShort(sk
); }
414 struct LdSSwitchData
: IRExtraData
{
416 const StringData
* str
;
420 explicit LdSSwitchData() = default;
421 LdSSwitchData(const LdSSwitchData
&) = delete;
422 LdSSwitchData
& operator=(const LdSSwitchData
&) = delete;
424 LdSSwitchData
* clone(Arena
& arena
) const {
425 LdSSwitchData
* target
= new (arena
) LdSSwitchData
;
426 target
->numCases
= numCases
;
427 target
->defaultSk
= defaultSk
;
428 target
->cases
= new (arena
) Elm
[numCases
];
429 target
->bcSPOff
= bcSPOff
;
430 std::copy(cases
, cases
+ numCases
, const_cast<Elm
*>(target
->cases
));
434 std::string
show() const {
435 return folly::to
<std::string
>(bcSPOff
.offset
);
444 struct ProfileSwitchData
: IRExtraData
{
445 ProfileSwitchData(rds::Handle handle
, int32_t cases
, int64_t base
)
451 std::string
show() const {
452 return folly::sformat("handle {}, {} cases, base {}", handle
, cases
, base
);
460 struct JmpSwitchData
: IRExtraData
{
461 JmpSwitchData
* clone(Arena
& arena
) const {
462 JmpSwitchData
* sd
= new (arena
) JmpSwitchData
;
464 sd
->targets
= new (arena
) SrcKey
[cases
];
465 sd
->spOffBCFromFP
= spOffBCFromFP
;
466 sd
->spOffBCFromIRSP
= spOffBCFromIRSP
;
467 std::copy(targets
, targets
+ cases
, const_cast<SrcKey
*>(sd
->targets
));
471 std::string
show() const {
472 return folly::sformat("{} cases", cases
);
475 int32_t cases
; // number of cases
476 SrcKey
* targets
; // srckeys for all targets
477 FPInvOffset spOffBCFromFP
;
478 IRSPRelOffset spOffBCFromIRSP
;
481 struct LdTVAuxData
: IRExtraData
{
482 explicit LdTVAuxData(int32_t v
= -1) : valid(v
) {}
484 std::string
show() const {
485 return folly::sformat("{:x}", valid
);
491 struct ReqBindJmpData
: IRExtraData
{
492 explicit ReqBindJmpData(const SrcKey
& target
,
493 FPInvOffset invSPOff
,
494 IRSPRelOffset irSPOff
,
502 std::string
show() const {
503 return folly::sformat(
504 "{}, FPInv {}, IRSP {}, Flags {}",
505 target
.offset(), invSPOff
.offset
, irSPOff
.offset
, trflags
.packed
510 FPInvOffset invSPOff
;
511 IRSPRelOffset irSPOff
;
515 struct ReqRetranslateData
: IRExtraData
{
516 explicit ReqRetranslateData(IRSPRelOffset irSPOff
,
522 std::string
show() const {
523 return folly::to
<std::string
>(irSPOff
.offset
, ',', trflags
.packed
);
526 IRSPRelOffset irSPOff
;
531 * Compile-time metadata about an ActRec allocation.
533 struct ActRecInfo
: IRExtraData
{
534 IRSPRelOffset spOffset
;
537 std::string
show() const {
538 return folly::to
<std::string
>(spOffset
.offset
, ',', numArgs
);
543 * DefInlineFP is present when we need to create a frame for inlining. This
544 * instruction also carries some metadata used by IRBuilder to track state
545 * during an inlined call.
547 struct DefInlineFPData
: IRExtraData
{
548 std::string
show() const {
549 return folly::to
<std::string
>(
550 target
->fullName()->data(), "(),",
552 retSPOff
.offset
, ',',
558 SSATmp
* ctx
; // Ctx, Cls or Nullptr.
560 FPInvOffset retSPOff
;
561 IRSPRelOffset spOffset
; // offset from caller SP to bottom of callee's ActRec
562 uint32_t numNonDefault
;
565 struct SyncReturnBCData
: IRExtraData
{
566 SyncReturnBCData(Offset bcOff
, IRSPRelOffset spOff
)
570 std::string
show() const {
571 return folly::to
<std::string
>(bcOffset
, ",", spOffset
.offset
);
575 IRSPRelOffset spOffset
;
578 struct CallArrayData
: IRExtraData
{
579 explicit CallArrayData(IRSPRelOffset spOffset
,
587 , numParams(numParams
)
591 , writeLocals(writeLocals
)
592 , readLocals(readLocals
)
595 std::string
show() const {
596 return folly::to
<std::string
>(
600 ? folly::sformat(",{}", callee
->fullName())
602 writeLocals
? ",writeLocals" : "",
603 readLocals
? ",readLocals" : "");
606 IRSPRelOffset spOffset
; // offset from StkPtr to bottom of call's ActRec+args
608 Offset pc
; // XXX why isn't this available in the marker?
609 Offset after
; // offset from unit m_bc (unlike m_soff in ActRec)
610 const Func
* callee
; // nullptr if not statically known
615 struct CallBuiltinData
: IRExtraData
{
616 explicit CallBuiltinData(IRSPRelOffset spOffset
,
618 int32_t numNonDefault
,
624 , numNonDefault
{numNonDefault
}
625 , writeLocals
{writeLocals
}
626 , readLocals
{readLocals
}
627 , needsCallerFrame
{needsFrame
}
630 std::string
show() const {
631 return folly::to
<std::string
>(
632 spOffset
.offset
, ',',
633 callee
->fullName()->data(),
634 writeLocals
? ",writeLocals" : "",
635 readLocals
? ",readLocals" : "",
636 needsCallerFrame
? ",needsCallerFrame" : ""
640 IRSPRelOffset spOffset
; // offset from StkPtr to last passed arg
642 int32_t numNonDefault
;
645 bool needsCallerFrame
;
648 struct CallData
: IRExtraData
{
649 explicit CallData(IRSPRelOffset spOffset
,
658 , numParams(numParams
)
661 , writeLocals(writeLocals
)
662 , readLocals(readLocals
)
663 , needsCallerFrame(needsFrame
)
664 , fcallAwait(fcallAwait
)
667 std::string
show() const {
668 return folly::to
<std::string
>(
669 spOffset
.offset
, ',', numParams
, ',', after
,
671 ? folly::format(",{}", callee
->fullName()).str()
673 writeLocals
? ",writeLocals" : "",
674 readLocals
? ",readLocals" : "",
675 needsCallerFrame
? ",needsCallerFrame" : "",
676 fcallAwait
? ",fcallAwait" : ""
680 IRSPRelOffset spOffset
; // offset from StkPtr to bottom of call's ActRec+args
682 Offset after
; // m_soff style: offset from func->base()
683 const Func
* callee
; // nullptr if not statically known
686 bool needsCallerFrame
;
690 struct RetCtrlData
: IRExtraData
{
691 explicit RetCtrlData(IRSPRelOffset offset
, bool suspendingResumed
,
692 folly::Optional
<AuxUnion
> aux
= folly::none
)
694 , suspendingResumed(suspendingResumed
)
698 std::string
show() const {
699 return folly::to
<std::string
>(
701 suspendingResumed
? ",suspendingResumed" : ""
705 // Adjustment we need to make to the stack pointer (for cross-tracelet ABI
706 // purposes) before returning.
707 IRSPRelOffset offset
;
709 // Indicates that the current resumable frame is being suspended without
710 // decrefing locals. Used by refcount optimizer.
711 bool suspendingResumed
;
713 // Optional TV aux value to attach to the function's return value.
714 folly::Optional
<AuxUnion
> aux
;
718 * Name of a class constant in a known class
720 struct ClsCnsName
: IRExtraData
{
721 explicit ClsCnsName(const StringData
* cls
, const StringData
* cns
)
726 std::string
show() const {
727 return folly::to
<std::string
>(clsName
->data(), "::", cnsName
->data());
730 const StringData
* clsName
;
731 const StringData
* cnsName
;
735 * Name of a class constant in an unknown class.
737 struct LdSubClsCnsData
: IRExtraData
{
738 explicit LdSubClsCnsData(const StringData
* cns
, Slot s
)
743 std::string
show() const {
744 return folly::sformat("<cls>::{}({})", cnsName
, slot
);
747 const StringData
* cnsName
;
752 * Name and handle of profiled class constant
754 struct ProfileSubClsCnsData
: IRExtraData
{
755 explicit ProfileSubClsCnsData(const StringData
* cns
, rds::Handle h
)
760 std::string
show() const {
761 return folly::to
<std::string
>("<cls>::", cnsName
->data());
764 const StringData
* cnsName
;
769 * The name of a static local in a function.
771 struct StaticLocName
: IRExtraData
{
772 StaticLocName(const Func
* func
, const StringData
* name
)
777 std::string
show() const {
778 return folly::to
<std::string
>(
779 func
->fullName()->data(), "$", name
->data()
783 bool equals(const StaticLocName
& o
) const {
784 return func
== o
.func
&& name
== o
.name
;
786 size_t hash() const {
787 return hash_int64_pair((intptr_t)func
, (intptr_t)name
);
790 const StringData
* name
;
793 struct LdFuncCachedData
: IRExtraData
{
794 explicit LdFuncCachedData(const StringData
* name
)
798 std::string
show() const {
799 return folly::to
<std::string
>(name
->data());
802 size_t hash() const { return name
->hash(); }
803 bool equals(const LdFuncCachedData
& o
) const {
804 return name
== o
.name
;
807 const StringData
* name
;
810 struct LdObjMethodData
: IRExtraData
{
811 explicit LdObjMethodData(IRSPRelOffset offset
,
812 const StringData
* method
,
819 std::string
show() const {
820 return folly::to
<std::string
>(offset
.offset
, ',', method
->data(), ',',
821 fatal
? "fatal" : "warn");
824 IRSPRelOffset offset
;
825 const StringData
* method
;
829 struct LdFuncCachedUData
: IRExtraData
{
830 explicit LdFuncCachedUData(const StringData
* name
,
831 const StringData
* fallback
)
836 std::string
show() const {
837 return folly::to
<std::string
>(name
->data(), ',', fallback
->data());
840 size_t hash() const {
841 return hash_int64_pair((uint32_t)name
->hash(), (uint32_t)fallback
->hash());
843 bool equals(const LdFuncCachedUData
& o
) const {
844 return name
== o
.name
&& fallback
== o
.fallback
;
847 const StringData
* name
;
848 const StringData
* fallback
;
852 * Offset and stack deltas for InterpOne.
854 struct InterpOneData
: IRExtraData
{
856 explicit LocalType(uint32_t id
= 0, Type type
= TBottom
)
866 explicit ClsRefSlot(uint32_t id
= 0, bool write
= false)
875 explicit InterpOneData(IRSPRelOffset spOffset
)
878 , changedLocals(nullptr)
879 , nChangedClsRefSlots(0)
880 , changedClsRefSlots(nullptr)
881 , smashesAllLocals(false)
884 // Offset of the BC stack top relative to the current IR stack pointer.
885 IRSPRelOffset spOffset
;
887 // Offset of the instruction to interpret, in the Unit indicated by the
891 // The number of eval stack cells consumed and produced by the instruction,
892 // respectively. Includes ActRecs.
896 // Opcode, in case we need to fix the stack differently. Some bytecode
897 // instructions modify things below the top of the stack.
900 uint32_t nChangedLocals
;
901 LocalType
* changedLocals
;
903 uint32_t nChangedClsRefSlots
;
904 ClsRefSlot
* changedClsRefSlots
;
906 bool smashesAllLocals
;
908 InterpOneData
* clone(Arena
& arena
) const {
909 auto* id
= new (arena
) InterpOneData(spOffset
);
911 id
->cellsPopped
= cellsPopped
;
912 id
->cellsPushed
= cellsPushed
;
914 id
->nChangedLocals
= nChangedLocals
;
915 id
->changedLocals
= new (arena
) LocalType
[nChangedLocals
];
916 id
->nChangedClsRefSlots
= nChangedClsRefSlots
;
917 id
->changedClsRefSlots
= new (arena
) ClsRefSlot
[nChangedClsRefSlots
];
918 id
->smashesAllLocals
= smashesAllLocals
;
919 std::copy(changedLocals
, changedLocals
+ nChangedLocals
, id
->changedLocals
);
920 std::copy(changedClsRefSlots
, changedClsRefSlots
+ nChangedClsRefSlots
,
921 id
->changedClsRefSlots
);
925 std::string
show() const {
926 auto ret
= folly::sformat(
927 "{}: spOff:{}, bcOff:{}, popped:{}, pushed:{}",
928 opcodeToName(opcode
),
934 assertx(!smashesAllLocals
|| !nChangedLocals
);
935 if (smashesAllLocals
) ret
+= ", smashes all locals";
936 if (nChangedLocals
) {
937 for (auto i
= 0; i
< nChangedLocals
; ++i
) {
938 ret
+= folly::sformat(", Local {} -> {}",
940 changedLocals
[i
].type
);
943 if (nChangedClsRefSlots
) {
944 for (auto i
= 0; i
< nChangedClsRefSlots
; ++i
) {
945 ret
+= folly::sformat(", Slot {}{}",
946 changedClsRefSlots
[i
].id
,
947 changedClsRefSlots
[i
].write
? "W" : "R");
955 struct CoerceStkData
: IRExtraData
{
956 explicit CoerceStkData(IRSPRelOffset off
, const Func
* f
, int64_t arg_num
)
957 : offset(off
), callee(f
), argNum(arg_num
) {}
959 std::string
show() const {
960 return folly::sformat(
968 IRSPRelOffset offset
;
973 struct CoerceMemData
: IRExtraData
{
974 explicit CoerceMemData(const Func
* f
, int64_t arg_num
)
975 : callee(f
), argNum(arg_num
) {}
977 std::string
show() const {
978 return folly::sformat("{},{}", callee
->name(), argNum
);
985 struct RBEntryData
: IRExtraData
{
986 RBEntryData(Trace::RingBufferType t
, SrcKey sk
)
991 std::string
show() const {
992 return folly::sformat("{}: {}", ringbufferName(type
), showShort(sk
));
995 Trace::RingBufferType type
;
999 struct RBMsgData
: IRExtraData
{
1000 RBMsgData(Trace::RingBufferType t
, const StringData
* msg
)
1004 assertx(msg
->isStatic());
1007 std::string
show() const {
1008 return folly::sformat("{}: {}", ringbufferName(type
), msg
->data());
1011 Trace::RingBufferType type
;
1012 const StringData
* msg
;
1015 struct ClassKindData
: IRExtraData
{
1016 explicit ClassKindData(ClassKind kind
): kind(uint32_t(kind
)) {}
1018 std::string
show() const {
1019 switch (static_cast<ClassKind
>(kind
)) {
1020 case ClassKind::Class
: return "cls";
1021 case ClassKind::Interface
: return "interface";
1022 case ClassKind::Trait
: return "trait";
1023 case ClassKind::Enum
: return "enum";
1028 uint32_t kind
; // ... allows for direct usage in native_call
1031 struct NewStructData
: IRExtraData
{
1032 std::string
show() const;
1033 IRSPRelOffset offset
;
1038 struct PackedArrayData
: IRExtraData
{
1039 explicit PackedArrayData(uint32_t size
) : size(size
) {}
1040 std::string
show() const { return folly::format("{}", size
).str(); }
1044 struct InitPackedArrayLoopData
: IRExtraData
{
1045 explicit InitPackedArrayLoopData(IRSPRelOffset offset
, uint32_t size
)
1050 std::string
show() const {
1051 return folly::format("{},{}", offset
.offset
, size
).str();
1054 IRSPRelOffset offset
;
1058 struct CreateAAWHData
: IRExtraData
{
1059 explicit CreateAAWHData(uint32_t first
, uint32_t count
)
1064 std::string
show() const {
1065 return folly::format("{},{}", first
, count
).str();
1072 struct CountWHNotDoneData
: IRExtraData
{
1073 explicit CountWHNotDoneData(uint32_t first
, uint32_t count
)
1078 std::string
show() const {
1079 return folly::format("{},{}", first
, count
).str();
1086 struct NewKeysetArrayData
: IRExtraData
{
1087 explicit NewKeysetArrayData(IRSPRelOffset offset
, uint32_t size
)
1092 std::string
show() const {
1093 return folly::format("{},{}", offset
.offset
, size
).str();
1096 IRSPRelOffset offset
;
1100 struct MemoData
: IRExtraData
{
1101 explicit MemoData(LocalRange locals
)
1104 std::string
show() const { return HPHP::show(locals
); }
1109 struct MOpModeData
: IRExtraData
{
1110 explicit MOpModeData(MOpMode mode
) : mode
{mode
} {}
1112 std::string
show() const { return subopToName(mode
); }
1117 struct SetOpData
: IRExtraData
{
1118 explicit SetOpData(SetOpOp op
) : op(op
) {}
1119 std::string
show() const { return subopToName(op
); }
1123 struct DecRefData
: IRExtraData
{
1124 explicit DecRefData(int locId
= -1) : locId(locId
) {}
1125 std::string
show() const {
1126 return locId
!= -1 ? folly::to
<std::string
>("Loc", locId
) : "-";
1128 int locId
; // If a known local, this has its id; -1 otherwise.
1131 struct IncDecData
: IRExtraData
{
1132 explicit IncDecData(IncDecOp op
) : op(op
) {}
1133 std::string
show() const { return subopToName(op
); }
1137 struct ResumeOffset
: IRExtraData
{
1138 explicit ResumeOffset(Offset off
) : off(off
) {}
1139 std::string
show() const { return folly::to
<std::string
>(off
); }
1143 struct GeneratorState
: IRExtraData
{
1144 explicit GeneratorState(BaseGenerator::State state
) : state(state
) {}
1145 std::string
show() const {
1146 using U
= std::underlying_type
<BaseGenerator::State
>::type
;
1147 return folly::to
<std::string
>(static_cast<U
>(state
));
1149 BaseGenerator::State state
;
1152 struct ContEnterData
: IRExtraData
{
1153 explicit ContEnterData(IRSPRelOffset spOffset
, Offset returnBCOffset
,
1155 : spOffset(spOffset
)
1156 , returnBCOffset(returnBCOffset
)
1160 std::string
show() const {
1161 return folly::to
<std::string
>(spOffset
.offset
, ',', returnBCOffset
,
1162 isAsync
? ",async" : "");
1165 IRSPRelOffset spOffset
;
1166 Offset returnBCOffset
;
1170 struct NewColData
: IRExtraData
{
1171 explicit NewColData(CollectionType itype
)
1175 std::string
show() const {
1176 return collections::typeToString(type
)->toCppString();
1179 CollectionType type
;
1182 struct LocalIdRange
: IRExtraData
{
1183 LocalIdRange(uint32_t start
, uint32_t end
)
1188 std::string
show() const {
1189 return folly::format("[{}, {})", start
, end
).str();
1192 uint32_t start
, end
;
1195 struct FuncEntryData
: IRExtraData
{
1196 FuncEntryData(const Func
* func
, uint32_t argc
)
1201 std::string
show() const {
1202 return folly::format(
1213 struct CheckRefsData
: IRExtraData
{
1214 CheckRefsData(unsigned firstBit
, uint64_t mask
, uint64_t vals
)
1215 : firstBit(safe_cast
<int>(firstBit
))
1220 std::string
show() const {
1221 return folly::format("{},{},{}", firstBit
, mask
, vals
).str();
1229 struct LookupClsMethodData
: IRExtraData
{
1230 explicit LookupClsMethodData(IRSPRelOffset offset
, bool forward
) :
1231 calleeAROffset(offset
), forward(forward
) {}
1233 std::string
show() const {
1234 return folly::to
<std::string
>("IRSPOff ", calleeAROffset
.offset
,
1235 forward
? " forwarded" : "");
1238 // offset from caller SP to bottom of callee's ActRec
1239 IRSPRelOffset calleeAROffset
;
1244 struct ProfileMethodData
: IRExtraData
{
1245 ProfileMethodData(IRSPRelOffset bcSPOff
, rds::Handle handle
)
1250 std::string
show() const { return folly::to
<std::string
>(handle
); }
1252 IRSPRelOffset bcSPOff
;
1256 struct FuncGuardData
: IRExtraData
{
1257 FuncGuardData(const Func
* func
, TCA
* prologueAddrPtr
)
1259 , prologueAddrPtr(prologueAddrPtr
)
1262 std::string
show() const {
1263 return folly::sformat("{}=>{}",
1264 func
->fullName(), prologueAddrPtr
1269 TCA
* prologueAddrPtr
;
1272 struct BeginInliningData
: IRExtraData
{
1273 BeginInliningData(IRSPRelOffset offset
, const Func
* func
, int cost
)
1279 std::string
show() const {
1280 return folly::to
<std::string
>("IRSPOff ", offset
.offset
,
1281 " FUNC ", func
->fullName()->data());
1284 IRSPRelOffset offset
;
1289 struct RaiseParamRefMismatchData
: IRExtraData
{
1290 explicit RaiseParamRefMismatchData(uint32_t paramId
)
1294 std::string
show() const {
1295 return folly::to
<std::string
>(paramId
);
1301 struct RaiseHackArrParamNoticeData
: IRExtraData
{
1302 explicit RaiseHackArrParamNoticeData(AnnotType type
)
1305 std::string
show() const {
1306 if (type
== AnnotType::VArray
) return "varray";
1307 if (type
== AnnotType::DArray
) return "darray";
1308 if (type
== AnnotType::VArrOrDArr
) return "varray_or_darray";
1315 struct AssertReason
: IRExtraData
{
1316 explicit AssertReason(Reason r
) : reason
{r
.file
, r
.line
} {}
1318 std::string
show() const {
1319 return jit::show(reason
);
1324 #define ASSERT_REASON AssertReason{Reason{__FILE__, __LINE__}}
1326 //////////////////////////////////////////////////////////////////////
1328 #define X(op, data) \
1329 template<> struct IRExtraDataType<op> { typedef data type; }; \
1330 template<> struct OpHasExtraData<op> { enum { value = 1 }; }; \
1331 static_assert(boost::has_trivial_destructor<data>::value, \
1332 "IR extra data type must be trivially destructible")
1334 X(LdBindAddr
, LdBindAddrData
);
1335 X(ProfileSwitchDest
, ProfileSwitchData
);
1336 X(JmpSwitchDest
, JmpSwitchData
);
1337 X(LdSSwitchDestFast
, LdSSwitchData
);
1338 X(LdSSwitchDestSlow
, LdSSwitchData
);
1339 X(HintLocInner
, LocalId
);
1340 X(CheckLoc
, LocalId
);
1341 X(AssertLoc
, LocalId
);
1342 X(LdLocAddr
, LocalId
);
1344 X(LdLocPseudoMain
, LocalId
);
1346 X(StLocPseudoMain
, LocalId
);
1347 X(StLocRange
, LocalIdRange
);
1348 X(LdClsRef
, ClsRefSlotData
);
1349 X(StClsRef
, ClsRefSlotData
);
1350 X(KillClsRef
, ClsRefSlotData
);
1351 X(IterFree
, IterId
);
1352 X(MIterFree
, IterId
);
1353 X(DecodeCufIter
, IterId
);
1354 X(StCufIterFunc
, IterId
);
1355 X(StCufIterCtx
, IterId
);
1356 X(StCufIterInvName
, IterId
);
1357 X(StCufIterDynamic
, IterId
);
1358 X(LdCufIterFunc
, IterId
);
1359 X(LdCufIterCtx
, IterId
);
1360 X(LdCufIterInvName
, IterId
);
1361 X(LdCufIterDynamic
, IterId
);
1362 X(KillCufIter
, IterId
);
1363 X(IterInit
, IterData
);
1364 X(IterInitK
, IterData
);
1365 X(IterNext
, IterData
);
1366 X(IterNextK
, IterData
);
1367 X(WIterInit
, IterData
);
1368 X(WIterInitK
, IterData
);
1369 X(WIterNext
, IterData
);
1370 X(WIterNextK
, IterData
);
1371 X(MIterInit
, IterData
);
1372 X(MIterInitK
, IterData
);
1373 X(MIterNext
, IterData
);
1374 X(MIterNextK
, IterData
);
1375 X(ConstructInstance
, ClassData
);
1376 X(CheckInitProps
, ClassData
);
1377 X(InitProps
, ClassData
);
1378 X(CheckInitSProps
, ClassData
);
1379 X(InitSProps
, ClassData
);
1380 X(NewInstanceRaw
, ClassData
);
1381 X(InitObjProps
, ClassData
);
1382 X(InstanceOfIfaceVtable
, ClassData
);
1383 X(ExtendsClass
, ExtendsClassData
);
1384 X(SpillFrame
, ActRecInfo
);
1385 X(CheckStk
, IRSPRelOffsetData
);
1386 X(HintStkInner
, IRSPRelOffsetData
);
1387 X(StStk
, IRSPRelOffsetData
);
1388 X(CastStk
, IRSPRelOffsetData
);
1389 X(CoerceStk
, CoerceStkData
);
1390 X(CoerceMem
, CoerceMemData
);
1391 X(CoerceCellToInt
, FuncArgData
);
1392 X(CoerceCellToDbl
, FuncArgData
);
1393 X(CoerceCellToBool
, FuncArgData
);
1394 X(CoerceStrToInt
, FuncArgData
);
1395 X(CoerceStrToDbl
, FuncArgData
);
1396 X(AssertStk
, IRSPRelOffsetData
);
1397 X(DefSP
, FPInvOffsetData
);
1398 X(LdStk
, IRSPRelOffsetData
);
1399 X(LdStkAddr
, IRSPRelOffsetData
);
1400 X(DefInlineFP
, DefInlineFPData
);
1401 X(BeginInlining
, BeginInliningData
);
1402 X(SyncReturnBC
, SyncReturnBCData
);
1403 X(InlineReturn
, FPRelOffsetData
);
1404 X(InlineReturnNoFrame
, FPRelOffsetData
);
1405 X(ReqRetranslate
, ReqRetranslateData
);
1406 X(ReqBindJmp
, ReqBindJmpData
);
1407 X(ReqRetranslateOpt
, IRSPRelOffsetData
);
1408 X(CheckCold
, TransIDData
);
1409 X(IncProfCounter
, TransIDData
);
1411 X(CallBuiltin
, CallBuiltinData
);
1412 X(CallArray
, CallArrayData
);
1413 X(RetCtrl
, RetCtrlData
);
1414 X(AsyncFuncRet
, IRSPRelOffsetData
);
1415 X(AsyncFuncRetSlow
, IRSPRelOffsetData
);
1416 X(AsyncSwitchFast
, IRSPRelOffsetData
);
1417 X(LdArrFuncCtx
, IRSPRelOffsetData
);
1418 X(LdArrFPushCuf
, IRSPRelOffsetData
);
1419 X(LdStrFPushCuf
, IRSPRelOffsetData
);
1420 X(LdFunc
, IRSPRelOffsetData
);
1421 X(LookupClsMethod
, LookupClsMethodData
);
1422 X(LookupClsMethodCache
, ClsMethodData
);
1423 X(LdClsMethodCacheFunc
, ClsMethodData
);
1424 X(LdClsMethodCacheCls
, ClsMethodData
);
1425 X(LdClsMethodFCacheFunc
, ClsMethodData
);
1426 X(LookupClsMethodFCache
, ClsMethodData
);
1427 X(LdIfaceMethod
, IfaceMethodData
);
1428 X(LdClosureStaticLoc
, StaticLocName
);
1429 X(LdStaticLoc
, StaticLocName
);
1430 X(CheckStaticLoc
, StaticLocName
);
1431 X(InitStaticLoc
, StaticLocName
);
1432 X(LdClsCns
, ClsCnsName
);
1433 X(InitClsCns
, ClsCnsName
);
1434 X(LdSubClsCns
, LdSubClsCnsData
);
1435 X(CheckSubClsCns
, LdSubClsCnsData
);
1436 X(ProfileSubClsCns
, ProfileSubClsCnsData
);
1437 X(LdFuncCached
, LdFuncCachedData
);
1438 X(LdFuncCachedSafe
, LdFuncCachedData
);
1439 X(LdFuncCachedU
, LdFuncCachedUData
);
1440 X(LdObjMethod
, LdObjMethodData
);
1441 X(RaiseMissingArg
, FuncArgData
);
1442 X(RaiseParamRefMismatch
, RaiseParamRefMismatchData
);
1443 X(InterpOne
, InterpOneData
);
1444 X(InterpOneCF
, InterpOneData
);
1445 X(StClosureArg
, ByteOffsetData
);
1446 X(RBTraceEntry
, RBEntryData
);
1447 X(RBTraceMsg
, RBMsgData
);
1448 X(OODeclExists
, ClassKindData
);
1449 X(NewStructArray
, NewStructData
);
1450 X(NewStructDArray
, NewStructData
);
1451 X(AllocPackedArray
, PackedArrayData
);
1452 X(AllocVArray
, PackedArrayData
);
1453 X(AllocVecArray
, PackedArrayData
);
1454 X(NewKeysetArray
, NewKeysetArrayData
);
1455 X(InitPackedLayoutArrayLoop
, InitPackedArrayLoopData
);
1456 X(InitPackedLayoutArray
, IndexData
);
1457 X(CreateAAWH
, CreateAAWHData
);
1458 X(CountWHNotDone
, CountWHNotDoneData
);
1459 X(CheckMixedArrayOffset
, IndexData
);
1460 X(CheckDictOffset
, IndexData
);
1461 X(CheckKeysetOffset
, IndexData
);
1462 X(ElemMixedArrayK
, IndexData
);
1463 X(MixedArrayGetK
, IndexData
);
1464 X(DictGetK
, IndexData
);
1465 X(KeysetGetK
, IndexData
);
1466 X(ElemDictK
, IndexData
);
1467 X(ElemKeysetK
, IndexData
);
1468 X(ProfileArrayKind
, RDSHandleData
);
1469 X(ProfileMixedArrayOffset
, RDSHandleData
);
1470 X(ProfileDictOffset
, RDSHandleData
);
1471 X(ProfileKeysetOffset
, RDSHandleData
);
1472 X(ProfileType
, RDSHandleData
);
1473 X(ProfileMethod
, ProfileMethodData
);
1474 X(LdRDSAddr
, RDSHandleData
);
1475 X(BaseG
, MOpModeData
);
1476 X(PropX
, MOpModeData
);
1477 X(PropDX
, MOpModeData
);
1478 X(ElemX
, MOpModeData
);
1479 X(ElemDX
, MOpModeData
);
1480 X(ElemUX
, MOpModeData
);
1481 X(CGetProp
, MOpModeData
);
1482 X(CGetElem
, MOpModeData
);
1483 X(MemoGet
, MemoData
);
1484 X(MemoSet
, MemoData
);
1485 X(SetOpProp
, SetOpData
);
1486 X(SetOpCell
, SetOpData
);
1487 X(IncDecProp
, IncDecData
);
1488 X(SetOpElem
, SetOpData
);
1489 X(IncDecElem
, IncDecData
);
1490 X(StArResumeAddr
, ResumeOffset
);
1491 X(StContArState
, GeneratorState
);
1492 X(ContEnter
, ContEnterData
);
1493 X(DbgAssertARFunc
, IRSPRelOffsetData
);
1494 X(LdARFuncPtr
, IRSPRelOffsetData
);
1495 X(LdARCtx
, IRSPRelOffsetData
);
1496 X(EndCatch
, IRSPRelOffsetData
);
1497 X(EagerSyncVMRegs
, IRSPRelOffsetData
);
1498 X(JmpSSwitchDest
, IRSPRelOffsetData
);
1499 X(DbgTrashStk
, IRSPRelOffsetData
);
1500 X(DbgTrashFrame
, IRSPRelOffsetData
);
1501 X(DbgTraceCall
, IRSPRelOffsetData
);
1502 X(LdPropAddr
, ByteOffsetData
);
1503 X(NewCol
, NewColData
);
1504 X(NewColFromArray
, NewColData
);
1505 X(InitExtraArgs
, FuncEntryData
);
1506 X(CheckSurpriseFlagsEnter
, FuncEntryData
);
1507 X(CheckSurpriseAndStack
, FuncEntryData
);
1508 X(ContPreNext
, IsAsyncData
);
1509 X(ContStartedCheck
, IsAsyncData
);
1510 X(ContValid
, IsAsyncData
);
1511 X(LdContResumeAddr
, IsAsyncData
);
1512 X(LdContActRec
, IsAsyncData
);
1513 X(DecRef
, DecRefData
);
1514 X(LdTVAux
, LdTVAuxData
);
1515 X(CheckRefs
, CheckRefsData
);
1516 X(FuncGuard
, FuncGuardData
);
1517 X(RaiseHackArrParamNotice
, RaiseHackArrParamNoticeData
);
1518 X(DbgAssertRefCount
, AssertReason
);
1519 X(Unreachable
, AssertReason
);
1520 X(EndBlock
, AssertReason
);
1524 //////////////////////////////////////////////////////////////////////
1526 template<bool hasExtra
, Opcode opc
, class T
> struct AssertExtraTypes
{
1527 static void doassertx() {
1528 assertx(!"called extra on an opcode without extra data");
1530 static void doassert_same() {
1531 assertx(!"called extra on an opcode without extra data");
1535 template<Opcode opc
, class T
> struct AssertExtraTypes
<true,opc
,T
> {
1536 typedef typename IRExtraDataType
<opc
>::type ExtraType
;
1538 static void doassertx() {
1539 if (!std::is_base_of
<T
,ExtraType
>::value
) {
1540 assertx(!"extra<T> was called with an extra data "
1541 "type that doesn't match the opcode type");
1544 static void doassert_same() {
1545 if (!std::is_same
<T
,ExtraType
>::value
) {
1546 fprintf(stderr
, "opcode = %s\n", opcodeName(opc
)); \
1547 assertx(!"extra<T> was called with an extra data type that "
1548 "doesn't exactly match the opcode type");
1553 // Asserts that Opcode opc has extradata and it is of type T, or a
1554 // type derived from T.
1555 template<class T
> void assert_opcode_extra(Opcode opc
) {
1556 #define O(opcode, dstinfo, srcinfo, flags) \
1559 OpHasExtraData<opcode>::value,opcode,T \
1562 switch (opc
) { IR_OPCODES
default: not_reached(); }
1566 template<class T
> void assert_opcode_extra_same(Opcode opc
) {
1567 #define O(opcode, dstinfo, srcinfo, flags) \
1570 OpHasExtraData<opcode>::value,opcode,T \
1571 >::doassert_same(); \
1573 switch (opc
) { IR_OPCODES
default: not_reached(); }
1577 size_t hashExtra(Opcode opc
, const IRExtraData
* data
);
1578 bool equalsExtra(Opcode opc
, const IRExtraData
* a
, const IRExtraData
* b
);
1579 IRExtraData
* cloneExtra(Opcode opc
, IRExtraData
* data
, Arena
& a
);
1580 std::string
showExtra(Opcode opc
, const IRExtraData
* data
);
1582 //////////////////////////////////////////////////////////////////////