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 +----------------------------------------------------------------------+
19 #include "hphp/runtime/base/collections.h"
20 #include "hphp/runtime/base/typed-value.h"
21 #include "hphp/runtime/vm/bytecode.h"
22 #include "hphp/runtime/vm/iter.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>
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
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.
63 * - Implement an equals() member that indicates equality.
64 * - Implement a stableHash() method that is invariant across process
67 * In addition, extra data belonging to IRInstructions that may be hashed in
70 * - Implement a hash() method.
72 * Finally, optionally they may implement a show() method for use in debug
77 * Traits that returns the type of the extra C++ data structure for a
78 * given instruction, if it has one, along with some other information
81 template<Opcode op
> struct OpHasExtraData
{ enum { value
= 0 }; };
82 template<Opcode op
> struct IRExtraDataType
;
84 //////////////////////////////////////////////////////////////////////
86 struct IRExtraData
{};
88 //////////////////////////////////////////////////////////////////////
91 * Shared IRExtraData classes.
93 * These subtypes represent common parameters (e.g., statically known Func,
94 * local variable ID, stack offset, etc.) that are useful for a variety of HHIR
97 * These are kept separate from the one-off IRExtraDatas to make it easier to
98 * find existing common parameters.
104 * Required to be non-null.
106 struct ClassData
: IRExtraData
{
107 explicit ClassData(const Class
* cls
)
110 assertx(cls
!= nullptr);
113 std::string
show() const {
114 return folly::to
<std::string
>(cls
->name()->data());
117 bool equals(const ClassData
& o
) const {
121 size_t hash() const {
122 return pointer_hash
<Class
>()(cls
);
125 size_t stableHash() const {
126 return cls
->stableHash();
132 struct OptClassData
: IRExtraData
{
133 explicit OptClassData(const Class
* cls
)
137 std::string
show() const {
138 return folly::to
<std::string
>(cls
? cls
->name()->data() : "{null}");
141 bool equals(const OptClassData
& o
) const {
145 size_t hash() const {
146 return pointer_hash
<Class
>()(cls
);
149 size_t stableHash() const {
150 return (cls
? cls
->stableHash() : 0);
157 * Class pointer, suppress flag, is or as operation flag and range into the
158 * stack (for type structures) needed for resolve type struct instruction
160 * Class pointer could be null.
162 struct ResolveTypeStructData
: IRExtraData
{
163 explicit ResolveTypeStructData(
166 IRSPRelOffset offset
,
177 std::string
show() const {
178 return folly::sformat("{},{},{},{},{}",
179 cls
? cls
->name()->data() : "nullptr",
180 suppress
? "suppress" : "no-suppress",
186 bool equals(const ResolveTypeStructData
& o
) const {
187 return cls
== o
.cls
&& suppress
== o
.suppress
&&
188 offset
== o
.offset
&& size
== o
.size
&& isOrAsOp
== o
.isOrAsOp
;
191 size_t hash() const {
192 return (pointer_hash
<Class
>()(cls
)
193 + std::hash
<int32_t>()(offset
.offset
)
194 + std::hash
<uint32_t>()(size
))
195 ^ ((int64_t)(suppress
? -1 : 0) << 32 | (isOrAsOp
? -1 : 0));
198 size_t stableHash() const {
199 return folly::hash::hash_combine(
200 cls
? cls
->stableHash() : 0,
201 std::hash
<int32_t>()(offset
.offset
),
202 std::hash
<uint32_t>()(size
),
203 std::hash
<uint8_t>()(suppress
<< 1 | isOrAsOp
)
209 IRSPRelOffset offset
;
217 struct ExtendsClassData
: IRExtraData
{
218 explicit ExtendsClassData(const Class
* cls
, bool strictLikely
= false)
219 : cls(cls
), strictLikely(strictLikely
)
221 assertx(cls
!= nullptr);
224 std::string
show() const {
225 return folly::sformat("{}{}",
226 cls
->name(), strictLikely
? ":strictLikely" : "");
229 bool equals(const ExtendsClassData
& o
) const {
230 return cls
== o
.cls
&& strictLikely
== o
.strictLikely
;
233 size_t hash() const {
234 return pointer_hash
<Class
>()(cls
) ^ (strictLikely
? -1 : 0);
237 size_t stableHash() const {
238 return cls
->stableHash() ^ (strictLikely
? -1 : 0);
246 * InstanceOfIfaceVtable.
248 struct InstanceOfIfaceVtableData
: IRExtraData
{
249 InstanceOfIfaceVtableData(const Class
* cls
, bool canOptimize
)
250 : cls(cls
), canOptimize(canOptimize
)
252 assertx(cls
!= nullptr);
255 std::string
show() const {
256 return folly::sformat("{}{}",
257 cls
->name(), canOptimize
? ":canOptimize" : "");
260 bool equals(const InstanceOfIfaceVtableData
& o
) const {
261 return cls
== o
.cls
&& canOptimize
== o
.canOptimize
;
264 size_t hash() const {
265 return pointer_hash
<Class
>()(cls
) ^ (canOptimize
? -1 : 0);
268 size_t stableHash() const {
269 return cls
->stableHash() ^ (canOptimize
? -1 : 0);
277 * Class with method name.
279 struct ClsMethodData
: IRExtraData
{
280 ClsMethodData(const StringData
* cls
, const StringData
* method
,
281 const NamedEntity
* ne
, const Class
* context
)
288 std::string
show() const {
289 return folly::sformat(
293 context
? context
->name()->data() : "{no context}");
296 bool equals(const ClsMethodData
& o
) const {
297 // The strings are static so we can use pointer equality.
299 clsName
== o
.clsName
&&
300 methodName
== o
.methodName
&&
301 context
== o
.context
;
303 size_t hash() const {
304 return folly::hash::hash_combine(
305 std::hash
<const StringData
*>()(clsName
),
306 std::hash
<const StringData
*>()(methodName
),
307 std::hash
<const Class
*>()(context
)
311 size_t stableHash() const {
312 return folly::hash::hash_combine(
313 clsName
->hashStatic(),
314 methodName
->hashStatic(),
315 context
? context
->stableHash() : 0
319 const StringData
* clsName
;
320 const StringData
* methodName
;
321 const NamedEntity
* namedEntity
;
322 const Class
* context
;
325 struct IfaceMethodData
: IRExtraData
{
326 IfaceMethodData(Slot vtableIdx
, Slot methodIdx
)
327 : vtableIdx(vtableIdx
)
328 , methodIdx(methodIdx
)
331 std::string
show() const {
332 return folly::sformat("{}, {}", vtableIdx
, methodIdx
);
335 bool equals(const IfaceMethodData
& o
) const {
336 return vtableIdx
== o
.vtableIdx
&& methodIdx
== o
.methodIdx
;
339 size_t hash() const {
340 return hash_int64((int64_t)vtableIdx
<< 32 | methodIdx
);
343 size_t stableHash() const {
344 return hash_int64((int64_t)vtableIdx
<< 32 | methodIdx
);
354 struct FuncData
: IRExtraData
{
355 explicit FuncData(const Func
* f
)
359 std::string
show() const {
360 return folly::format("{}", func
->fullName()).str();
363 bool equals(const FuncData
& f
) const {
364 return func
== f
.func
;
367 size_t stableHash() const {
368 return func
->stableHash();
375 * Func with argument index.
377 struct FuncArgData
: IRExtraData
{
378 explicit FuncArgData(const Func
* f
, int64_t arg
)
383 std::string
show() const {
384 return folly::format("{},{}", func
->name(), argNum
).str();
387 bool equals(const FuncArgData
& o
) const {
388 return func
== o
.func
&& argNum
== o
.argNum
;
391 size_t stableHash() const {
392 return folly::hash::hash_combine(
394 std::hash
<int64_t>()(argNum
)
403 * Func with argument index and expected type.
405 struct FuncArgTypeData
: IRExtraData
{
406 explicit FuncArgTypeData(const Func
* f
, int64_t arg
, const StringData
* t
)
412 std::string
show() const {
413 return folly::format("{},{},{}", func
->name(), argNum
, type
).str();
416 bool equals(const FuncArgTypeData
& o
) const {
417 return func
== o
.func
&& argNum
== o
.argNum
&& type
== o
.type
;
420 size_t stableHash() const {
421 return folly::hash::hash_combine(
423 std::hash
<int64_t>()(argNum
),
430 const StringData
* type
;
433 struct LdClsTypeCnsData
: IRExtraData
{
434 explicit LdClsTypeCnsData(bool no_throw
) : noThrow(no_throw
) {}
436 std::string
show() const { return folly::to
<std::string
>(noThrow
); }
438 bool equals(LdClsTypeCnsData o
) const { return noThrow
== o
.noThrow
; }
439 size_t hash() const { return noThrow
? 1 : 0; }
440 size_t stableHash() const { return noThrow
? 1 : 0; }
448 struct LocalId
: IRExtraData
{
449 explicit LocalId(uint32_t id
) : locId(id
) {}
451 std::string
show() const { return folly::to
<std::string
>(locId
); }
453 bool equals(LocalId o
) const { return locId
== o
.locId
; }
454 size_t hash() const { return std::hash
<uint32_t>()(locId
); }
455 size_t stableHash() const { return std::hash
<uint32_t>()(locId
); }
461 * Index into, e.g., an array.
463 struct IndexData
: IRExtraData
{
464 explicit IndexData(uint32_t index
) : index(index
) {}
466 std::string
show() const { return folly::format("{}", index
).str(); }
467 size_t hash() const { return std::hash
<uint32_t>()(index
); }
468 size_t stableHash() const { return std::hash
<uint32_t>()(index
); }
470 bool equals(const IndexData
& o
) const {
471 return index
== o
.index
;
478 * An index and a key used to initialized a dict-ish array element.
480 struct KeyedIndexData
: IRExtraData
{
481 explicit KeyedIndexData(uint32_t index
, const StringData
* key
)
486 std::string
show() const;
488 size_t stableHash() const {
489 return folly::hash::hash_combine(
490 std::hash
<uint32_t>()(index
),
495 bool equals(const KeyedIndexData
& o
) const {
496 return index
== o
.index
&& key
== o
.key
;
500 const StringData
* key
;
504 * Used to optimize array accesses. Does not change semantics, but changes how
505 * we do the lookup - e.g. we scan small static arrays for static string keys.
507 * NOTE: Currently, we only use this hint in DictIdx. We may want
508 * to use it for ArrayExists / etc.
510 struct SizeHintData
: IRExtraData
{
516 SizeHintData() : hint(SizeHint::Default
) {}
517 explicit SizeHintData(SizeHint hint
) : hint(hint
) {}
519 std::string
show() const {
521 case SizeHint::Default
: return "Default";
522 case SizeHint::SmallStatic
: return "SmallStatic";
527 size_t hash() const {
531 size_t stableHash() const {
532 return std::hash
<SizeHint
>()(hint
);
535 bool equals(const SizeHintData
& o
) const {
536 return hint
== o
.hint
;
545 struct IterId
: IRExtraData
{
546 explicit IterId(uint32_t id
)
550 std::string
show() const { return folly::to
<std::string
>(iterId
); }
552 bool equals(IterId o
) const { return iterId
== o
.iterId
; }
553 size_t hash() const { return std::hash
<uint32_t>()(iterId
); }
554 size_t stableHash() const { return std::hash
<uint32_t>()(iterId
); }
560 * Iter instruction data, used for both key-value and value-only iterators.
561 * Check args.hasKey() to distinguish between the two.
563 struct IterData
: IRExtraData
{
564 explicit IterData(IterArgs args
) : args(args
) {}
566 std::string
show() const {
567 return HPHP::show(args
, [&](int32_t id
) {
568 return folly::to
<std::string
>(id
);
572 size_t stableHash() const {
573 return folly::hash::hash_combine(
574 std::hash
<int32_t>()(args
.iterId
),
575 std::hash
<int32_t>()(args
.keyId
),
576 std::hash
<int32_t>()(args
.valId
),
577 std::hash
<IterArgs::Flags
>()(args
.flags
)
581 bool equals(const IterData
& o
) const {
582 return args
== o
.args
;
588 struct IterTypeData
: IRExtraData
{
589 IterTypeData(uint32_t iterId
, IterSpecialization type
, ArrayLayout layout
)
594 always_assert(type
.specialized
);
597 std::string
show() const {
598 auto const type_str
= HPHP::show(type
);
599 auto const layout_str
= layout
.describe();
600 return folly::format("{}::{}::{}", iterId
, type_str
, layout_str
).str();
603 size_t stableHash() const {
604 return folly::hash::hash_combine(
605 std::hash
<uint32_t>()(iterId
),
606 std::hash
<uint8_t>()(type
.as_byte
),
607 std::hash
<uint16_t>()(layout
.toUint16())
611 bool equals(const IterTypeData
& o
) const {
612 return iterId
== o
.iterId
&& type
.as_byte
== o
.type
.as_byte
&&
617 IterSpecialization type
;
621 struct IterOffsetData
: IRExtraData
{
622 IterOffsetData(int16_t offset
) : offset(offset
) {}
624 std::string
show() const { return folly::to
<std::string
>(offset
); }
626 size_t stableHash() const { return std::hash
<int16_t>()(offset
); }
628 bool equals(const IterOffsetData
& o
) const { return offset
== o
.offset
; }
636 struct RDSHandleData
: IRExtraData
{
637 explicit RDSHandleData(rds::Handle handle
) : handle(handle
) {}
639 std::string
show() const { return folly::to
<std::string
>(handle
); }
641 bool equals(RDSHandleData o
) const { return handle
== o
.handle
; }
642 size_t hash() const { return std::hash
<uint32_t>()(handle
); }
644 size_t stableHash() const {
645 auto const sym
= rds::reverseLink(handle
);
647 return rds::symbol_stable_hash(*sym
);
654 * Array access profile.
656 struct ArrayAccessProfileData
: RDSHandleData
{
657 ArrayAccessProfileData(rds::Handle handle
, bool cowCheck
)
658 : RDSHandleData(handle
), cowCheck(cowCheck
) {}
660 std::string
show() const {
661 return folly::to
<std::string
>(handle
, ",", cowCheck
);
664 bool equals(ArrayAccessProfileData o
) const {
665 return handle
== o
.handle
&& cowCheck
== o
.cowCheck
;
667 size_t hash() const {
668 return folly::hash::hash_combine(std::hash
<uint32_t>()(handle
),
669 std::hash
<bool>()(cowCheck
));
672 size_t stableHash() const {
673 return folly::hash::hash_combine(RDSHandleData::stableHash(),
674 std::hash
<bool>()(cowCheck
));
683 * Used with profiling-related instructions.
685 struct TransIDData
: IRExtraData
{
686 explicit TransIDData(TransID transId
) : transId(transId
) {}
688 std::string
show() const { return folly::to
<std::string
>(transId
); }
690 size_t stableHash() const {
691 return std::hash
<TransID
>()(transId
);
694 bool equals(const TransIDData
& o
) const {
695 return transId
== o
.transId
;
701 struct DefFPData
: IRExtraData
{
702 explicit DefFPData(folly::Optional
<IRSPRelOffset
> offset
) : offset(offset
) {}
704 std::string
show() const {
705 if (!offset
) return "IRSPOff unknown";
706 return folly::to
<std::string
>("IRSPOff ", offset
->offset
);
709 bool equals(DefFPData o
) const { return offset
== o
.offset
; }
710 size_t stableHash() const {
711 return offset
? std::hash
<int32_t>()(offset
->offset
) : 0;
714 // Frame position on the stack, if it lives there and the position is known.
715 folly::Optional
<IRSPRelOffset
> offset
;
719 * Stack pointer offset.
721 struct DefStackData
: IRExtraData
{
722 explicit DefStackData(SBInvOffset irSPOff
, SBInvOffset bcSPOff
)
727 std::string
show() const {
728 return folly::sformat("irSPOff={}, bcSPOff={}",
729 irSPOff
.offset
, bcSPOff
.offset
);
732 bool equals(DefStackData o
) const {
733 return irSPOff
== o
.irSPOff
&& bcSPOff
== o
.bcSPOff
;
735 size_t hash() const {
736 return folly::hash::hash_combine(
737 std::hash
<int32_t>()(irSPOff
.offset
),
738 std::hash
<int32_t>()(bcSPOff
.offset
)
742 size_t stableHash() const {
743 return folly::hash::hash_combine(
744 std::hash
<int32_t>()(irSPOff
.offset
),
745 std::hash
<int32_t>()(bcSPOff
.offset
)
749 SBInvOffset irSPOff
; // offset from stack base to vmsp()
750 SBInvOffset bcSPOff
; // offset from stack base to top of the stack
756 struct IRSPRelOffsetData
: IRExtraData
{
757 explicit IRSPRelOffsetData(IRSPRelOffset offset
) : offset(offset
) {}
759 std::string
show() const {
760 return folly::to
<std::string
>("IRSPOff ", offset
.offset
);
763 bool equals(IRSPRelOffsetData o
) const { return offset
== o
.offset
; }
764 size_t hash() const { return std::hash
<int32_t>()(offset
.offset
); }
766 size_t stableHash() const { return std::hash
<int32_t>()(offset
.offset
); }
768 IRSPRelOffset offset
;
771 ///////////////////////////////////////////////////////////////////////////////
774 * One-off IRExtraData classes.
776 * These are used for only one or two instructions and are in no particular
777 * order. Add new IRExtraData types here.
780 struct IsAsyncData
: IRExtraData
{
781 explicit IsAsyncData(bool isAsync
) : isAsync(isAsync
) {}
783 std::string
show() const { return folly::to
<std::string
>(isAsync
); }
784 bool equals(IsAsyncData d
) const { return isAsync
== d
.isAsync
; }
785 size_t hash() const { return std::hash
<int32_t>()(isAsync
); }
787 size_t stableHash() const { return std::hash
<int32_t>()(isAsync
); }
792 struct LdBindAddrData
: IRExtraData
{
793 explicit LdBindAddrData(SrcKey sk
, SBInvOffset bcSPOff
)
798 std::string
show() const { return showShort(sk
); }
800 size_t stableHash() const {
801 return folly::hash::hash_combine(
802 SrcKey::StableHasher()(sk
),
803 std::hash
<int32_t>()(bcSPOff
.offset
)
807 bool equals(const LdBindAddrData
& o
) const {
808 return sk
== o
.sk
&& bcSPOff
== o
.bcSPOff
;
815 struct LdSSwitchData
: IRExtraData
{
817 const StringData
* str
;
821 explicit LdSSwitchData() = default;
822 LdSSwitchData(const LdSSwitchData
&) = delete;
823 LdSSwitchData
& operator=(const LdSSwitchData
&) = delete;
825 LdSSwitchData
* clone(Arena
& arena
) const {
826 LdSSwitchData
* target
= new (arena
) LdSSwitchData
;
827 target
->numCases
= numCases
;
828 target
->defaultSk
= defaultSk
;
829 target
->cases
= new (arena
) Elm
[numCases
];
830 target
->bcSPOff
= bcSPOff
;
831 std::copy(cases
, cases
+ numCases
, const_cast<Elm
*>(target
->cases
));
835 std::string
show() const {
836 return folly::to
<std::string
>(bcSPOff
.offset
);
839 size_t stableHash() const {
840 return folly::hash::hash_combine(
841 std::hash
<int64_t>()(numCases
),
842 SrcKey::StableHasher()(defaultSk
),
843 std::hash
<int32_t>()(bcSPOff
.offset
)
847 bool equals(const LdSSwitchData
& o
) const {
848 if (numCases
!= o
.numCases
) return false;
849 if (defaultSk
!= o
.defaultSk
) return false;
850 if (bcSPOff
!= o
.bcSPOff
) return false;
851 for (int64_t i
= 0; i
< numCases
; i
++) {
852 if (cases
[i
].dest
!= o
.cases
[i
].dest
) return false;
853 if (cases
[i
].str
!= o
.cases
[i
].str
) return false;
864 struct ProfileSwitchData
: IRExtraData
{
865 ProfileSwitchData(rds::Handle handle
, int32_t cases
, int64_t base
)
871 std::string
show() const {
872 return folly::sformat("handle {}, {} cases, base {}", handle
, cases
, base
);
875 size_t stableHash() const {
876 auto const sym
= rds::reverseLink(handle
);
877 return folly::hash::hash_combine(
878 sym
? rds::symbol_stable_hash(*sym
) : 0,
879 std::hash
<int32_t>()(cases
),
880 std::hash
<int64_t>()(base
)
884 bool equals(const ProfileSwitchData
& o
) const {
885 return handle
== o
.handle
&& cases
== o
.cases
&& base
== o
.base
;
893 struct JmpSwitchData
: IRExtraData
{
894 JmpSwitchData
* clone(Arena
& arena
) const {
895 JmpSwitchData
* sd
= new (arena
) JmpSwitchData
;
897 sd
->targets
= new (arena
) SrcKey
[cases
];
898 sd
->spOffBCFromStackBase
= spOffBCFromStackBase
;
899 sd
->spOffBCFromIRSP
= spOffBCFromIRSP
;
900 std::copy(targets
, targets
+ cases
, const_cast<SrcKey
*>(sd
->targets
));
904 std::string
show() const {
905 return folly::sformat("{} cases", cases
);
908 size_t stableHash() const {
909 return folly::hash::hash_combine(
910 std::hash
<int32_t>()(cases
),
911 std::hash
<int32_t>()(spOffBCFromStackBase
.offset
),
912 std::hash
<int32_t>()(spOffBCFromIRSP
.offset
)
916 bool equals(const JmpSwitchData
& o
) const {
917 if (cases
!= o
.cases
) return false;
918 if (spOffBCFromStackBase
!= o
.spOffBCFromStackBase
) return false;
919 if (spOffBCFromIRSP
!= o
.spOffBCFromIRSP
) return false;
920 for (int64_t i
= 0; i
< cases
; i
++) {
921 if (targets
[i
] != o
.targets
[i
]) return false;
926 int32_t cases
; // number of cases
927 SrcKey
* targets
; // srckeys for all targets
928 SBInvOffset spOffBCFromStackBase
;
929 IRSPRelOffset spOffBCFromIRSP
;
932 struct LdTVAuxData
: IRExtraData
{
933 explicit LdTVAuxData(int32_t v
= -1) : valid(v
) {}
935 std::string
show() const {
936 return folly::sformat("{:x}", valid
);
939 size_t stableHash() const {
940 return std::hash
<int32_t>()(valid
);
943 bool equals(const LdTVAuxData
& o
) const {
944 return valid
== o
.valid
;
950 struct ReqBindJmpData
: IRExtraData
{
951 explicit ReqBindJmpData(const SrcKey
& target
,
952 SBInvOffset invSPOff
,
953 IRSPRelOffset irSPOff
)
959 std::string
show() const {
960 return folly::sformat(
961 "{}, SBInv {}, IRSP {}",
962 target
.offset(), invSPOff
.offset
, irSPOff
.offset
966 size_t stableHash() const {
967 return folly::hash::hash_combine(
968 SrcKey::StableHasher()(target
),
969 std::hash
<int32_t>()(invSPOff
.offset
),
970 std::hash
<int32_t>()(irSPOff
.offset
)
974 bool equals(const ReqBindJmpData
& o
) const {
975 return target
== o
.target
&& invSPOff
== o
.invSPOff
&& irSPOff
== o
.irSPOff
;
979 SBInvOffset invSPOff
;
980 IRSPRelOffset irSPOff
;
984 * InlineCall is present when we need to create a frame for inlining. This
985 * instruction also carries some metadata used by IRBuilder to track state
986 * during an inlined call.
988 struct InlineCallData
: IRExtraData
{
989 std::string
show() const {
990 return folly::to
<std::string
>(
995 size_t stableHash() const {
996 // For now we are ignoring `syncVmpc`, but this could be fixed by storing
997 // an SK rather than a raw PC.
998 return std::hash
<int32_t>()(spOffset
.offset
);
1001 bool equals(const InlineCallData
& o
) const {
1002 return spOffset
== o
.spOffset
&& syncVmpc
== o
.syncVmpc
;
1005 IRSPRelOffset spOffset
; // offset from caller SP to bottom of callee's ActRec
1006 PC syncVmpc
{nullptr};
1009 struct StFrameMetaData
: IRExtraData
{
1010 std::string
show() const {
1011 return folly::to
<std::string
>(
1017 size_t stableHash() const {
1018 return folly::hash::hash_combine(
1019 std::hash
<Offset
>()(callBCOff
),
1020 std::hash
<bool>()(asyncEagerReturn
)
1024 bool equals(const StFrameMetaData
& o
) const {
1025 return callBCOff
== o
.callBCOff
&& asyncEagerReturn
== o
.asyncEagerReturn
;
1030 bool asyncEagerReturn
;
1033 struct CallBuiltinData
: IRExtraData
{
1034 explicit CallBuiltinData(IRSPRelOffset spOffset
,
1035 folly::Optional
<IRSPRelOffset
> retSpOffset
,
1037 : spOffset(spOffset
)
1038 , retSpOffset(retSpOffset
)
1042 std::string
show() const {
1043 return folly::to
<std::string
>(
1044 spOffset
.offset
, ',',
1045 retSpOffset
? folly::to
<std::string
>(retSpOffset
->offset
) : "*", ',',
1046 callee
->fullName()->data()
1050 size_t stableHash() const {
1051 return folly::hash::hash_combine(
1052 std::hash
<int32_t>()(spOffset
.offset
),
1053 retSpOffset
? std::hash
<int32_t>()(retSpOffset
->offset
) : 0,
1054 callee
->stableHash()
1058 bool equals(const CallBuiltinData
& o
) const {
1059 return spOffset
== o
.spOffset
&& retSpOffset
== o
.retSpOffset
&&
1063 IRSPRelOffset spOffset
; // offset from StkPtr to last passed arg
1064 folly::Optional
<IRSPRelOffset
> retSpOffset
; // offset from StkPtr after a return
1068 struct CallData
: IRExtraData
{
1069 explicit CallData(IRSPRelOffset spOffset
,
1073 uint16_t genericsBitmap
,
1078 bool asyncEagerReturn
,
1080 : spOffset(spOffset
)
1083 , callOffset(callOffset
)
1084 , genericsBitmap(genericsBitmap
)
1085 , hasGenerics(hasGenerics
)
1086 , hasUnpack(hasUnpack
)
1087 , skipRepack(skipRepack
)
1088 , dynamicCall(dynamicCall
)
1089 , asyncEagerReturn(asyncEagerReturn
)
1090 , formingRegion(formingRegion
)
1093 std::string
show() const {
1094 return folly::to
<std::string
>(
1095 spOffset
.offset
, ',', numArgs
, ',', numOut
, ',', callOffset
,
1097 ? folly::sformat(",hasGenerics({})", genericsBitmap
)
1099 hasUnpack
? ",unpack" : "",
1100 skipRepack
? ",skipRepack" : "",
1101 dynamicCall
? ",dynamicCall" : "",
1102 asyncEagerReturn
? ",asyncEagerReturn" : "",
1103 formingRegion
? ",formingRegion" : ""
1107 uint32_t numInputs() const {
1108 return numArgs
+ (hasUnpack
? 1 : 0) + (hasGenerics
? 1 : 0);
1111 size_t stableHash() const {
1112 return folly::hash::hash_combine(
1113 std::hash
<int32_t>()(spOffset
.offset
),
1114 std::hash
<uint32_t>()(numArgs
),
1115 std::hash
<uint32_t>()(numOut
),
1116 std::hash
<Offset
>()(callOffset
),
1117 std::hash
<uint16_t>()(genericsBitmap
),
1118 std::hash
<uint8_t>()(
1123 asyncEagerReturn
<< 1 |
1129 bool equals(const CallData
& o
) const {
1130 return spOffset
== o
.spOffset
&&
1131 numArgs
== o
.numArgs
&&
1132 numOut
== o
.numOut
&&
1133 callOffset
== o
.callOffset
&&
1134 genericsBitmap
== o
.genericsBitmap
&&
1135 hasGenerics
== o
.hasGenerics
&&
1136 hasUnpack
== o
.hasUnpack
&&
1137 skipRepack
== o
.skipRepack
&&
1138 dynamicCall
== o
.dynamicCall
&&
1139 asyncEagerReturn
== o
.asyncEagerReturn
&&
1140 formingRegion
== o
.formingRegion
;
1144 IRSPRelOffset spOffset
; // offset from StkPtr to bottom of call's ActRec+args
1146 uint32_t numOut
; // number of values returned via stack from the callee
1147 Offset callOffset
; // offset from func->base()
1148 uint16_t genericsBitmap
;
1153 bool asyncEagerReturn
;
1157 struct RetCtrlData
: IRExtraData
{
1158 explicit RetCtrlData(IRSPRelOffset offset
, bool suspendingResumed
,
1161 , suspendingResumed(suspendingResumed
)
1165 std::string
show() const {
1166 return folly::to
<std::string
>(
1168 suspendingResumed
? ",suspendingResumed" : ""
1172 size_t stableHash() const {
1173 return folly::hash::hash_combine(
1174 std::hash
<int32_t>()(offset
.offset
),
1175 std::hash
<bool>()(suspendingResumed
),
1176 std::hash
<uint32_t>()(aux
.u_raw
)
1180 bool equals(const RetCtrlData
& o
) const {
1181 return offset
== o
.offset
&& suspendingResumed
== o
.suspendingResumed
&&
1182 aux
.u_raw
== o
.aux
.u_raw
;
1185 // Adjustment we need to make to the stack pointer (for cross-tracelet ABI
1186 // purposes) before returning.
1187 IRSPRelOffset offset
;
1189 // Indicates that the current resumable frame is being suspended without
1190 // decrefing locals. Used by refcount optimizer.
1191 bool suspendingResumed
;
1193 // TV aux value to attach to the function's return value.
1200 struct RecNameData
: IRExtraData
{
1201 explicit RecNameData(const StringData
* name
)
1205 std::string
show() const {
1206 return folly::to
<std::string
>(recName
->data());
1209 size_t hash() const { return recName
->hash(); }
1211 size_t stableHash() const { return recName
->hash(); }
1212 bool equals(const RecNameData
& o
) const {
1213 return recName
== o
.recName
;
1216 const StringData
* recName
;
1220 * Name of a class constant in a known class
1222 struct ClsCnsName
: IRExtraData
{
1223 explicit ClsCnsName(const StringData
* cls
, const StringData
* cns
)
1228 std::string
show() const {
1229 return folly::to
<std::string
>(clsName
->data(), "::", cnsName
->data());
1232 size_t stableHash() const {
1233 return folly::hash::hash_combine(
1234 clsName
->hashStatic(),
1235 cnsName
->hashStatic()
1238 bool equals(const ClsCnsName
& o
) const {
1239 return clsName
== o
.clsName
&&
1240 cnsName
== o
.cnsName
;
1243 const StringData
* clsName
;
1244 const StringData
* cnsName
;
1248 * Name of a class constant in an unknown class.
1250 struct LdSubClsCnsData
: IRExtraData
{
1251 explicit LdSubClsCnsData(const StringData
* cns
, Slot s
)
1256 std::string
show() const {
1257 return folly::sformat("<cls>::{}({})", cnsName
, slot
);
1259 size_t stableHash() const {
1260 return folly::hash::hash_combine(
1261 cnsName
->hashStatic(),
1262 std::hash
<Slot
>()(slot
)
1265 bool equals(const LdSubClsCnsData
& o
) const {
1266 return cnsName
== o
.cnsName
&& slot
== o
.slot
;
1269 const StringData
* cnsName
;
1274 * Name and handle of profiled class constant
1276 struct ProfileSubClsCnsData
: IRExtraData
{
1277 explicit ProfileSubClsCnsData(const StringData
* cns
, rds::Handle h
)
1282 std::string
show() const {
1283 return folly::to
<std::string
>("<cls>::", cnsName
->data());
1286 size_t stableHash() const {
1287 auto const sym
= rds::reverseLink(handle
);
1288 return folly::hash::hash_combine(
1289 cnsName
->hashStatic(),
1290 sym
? rds::symbol_stable_hash(*sym
) : 0
1294 bool equals(const ProfileSubClsCnsData
& o
) const {
1295 return cnsName
== o
.cnsName
&& handle
== o
.handle
;
1298 const StringData
* cnsName
;
1302 struct FuncNameData
: IRExtraData
{
1303 FuncNameData(const StringData
* name
, const Class
* context
)
1308 std::string
show() const {
1309 return folly::to
<std::string
>(
1310 name
->data(), ",", context
? context
->name()->data() : "{no context}");
1313 size_t hash() const { return name
->hash(); }
1315 size_t stableHash() const {
1316 return folly::hash::hash_combine(
1318 context
? context
->stableHash() : 0
1322 bool equals(const FuncNameData
& o
) const {
1323 return name
== o
.name
&& context
== o
.context
;
1326 const StringData
* name
;
1327 const Class
* context
;
1331 * Offset and stack deltas for InterpOne.
1333 struct InterpOneData
: IRExtraData
{
1335 explicit LocalType(uint32_t id
= 0, Type type
= TBottom
)
1344 explicit InterpOneData(IRSPRelOffset spOffset
)
1345 : spOffset(spOffset
)
1347 , changedLocals(nullptr)
1348 , smashesAllLocals(false)
1351 size_t stableHash() const {
1352 auto hash
= folly::hash::hash_combine(
1353 std::hash
<int32_t>()(spOffset
.offset
),
1354 std::hash
<Offset
>()(bcOff
),
1355 std::hash
<int64_t>()(cellsPopped
),
1356 std::hash
<int64_t>()(cellsPushed
),
1357 std::hash
<Op
>()(opcode
),
1358 std::hash
<uint32_t>()(nChangedLocals
),
1359 std::hash
<bool>()(smashesAllLocals
)
1361 for (uint32_t i
= 0; i
< nChangedLocals
; i
++) {
1362 hash
= folly::hash::hash_combine(
1364 changedLocals
[i
].id
,
1365 changedLocals
[i
].type
.stableHash()
1371 bool equals(const InterpOneData
& o
) const {
1372 if (spOffset
== o
.spOffset
&&
1374 cellsPopped
== o
.cellsPopped
&&
1375 cellsPushed
== o
.cellsPushed
&&
1376 opcode
== o
.opcode
&&
1377 nChangedLocals
== o
.nChangedLocals
&&
1378 smashesAllLocals
== o
.smashesAllLocals
) {
1379 for (uint32_t i
= 0; i
< nChangedLocals
; i
++) {
1380 if (changedLocals
[i
].id
!= o
.changedLocals
[i
].id
) return false;
1381 if (changedLocals
[i
].type
!= o
.changedLocals
[i
].type
) return false;
1388 // Offset of the BC stack top relative to the current IR stack pointer.
1389 IRSPRelOffset spOffset
;
1391 // Offset of the instruction to interpret, in the Unit indicated by the
1395 // The number of eval stack cells consumed and produced by the instruction,
1396 // respectively. Includes ActRecs.
1397 int64_t cellsPopped
;
1398 int64_t cellsPushed
;
1400 // Opcode, in case we need to fix the stack differently. Some bytecode
1401 // instructions modify things below the top of the stack.
1404 uint32_t nChangedLocals
;
1405 LocalType
* changedLocals
;
1407 bool smashesAllLocals
;
1409 InterpOneData
* clone(Arena
& arena
) const {
1410 auto* id
= new (arena
) InterpOneData(spOffset
);
1412 id
->cellsPopped
= cellsPopped
;
1413 id
->cellsPushed
= cellsPushed
;
1414 id
->opcode
= opcode
;
1415 id
->nChangedLocals
= nChangedLocals
;
1416 id
->changedLocals
= new (arena
) LocalType
[nChangedLocals
];
1417 id
->smashesAllLocals
= smashesAllLocals
;
1418 std::copy(changedLocals
, changedLocals
+ nChangedLocals
, id
->changedLocals
);
1422 std::string
show() const {
1423 auto ret
= folly::sformat(
1424 "{}: spOff:{}, bcOff:{}, popped:{}, pushed:{}",
1425 opcodeToName(opcode
),
1431 assertx(!smashesAllLocals
|| !nChangedLocals
);
1432 if (smashesAllLocals
) ret
+= ", smashes all locals";
1433 if (nChangedLocals
) {
1434 for (auto i
= 0; i
< nChangedLocals
; ++i
) {
1435 ret
+= folly::sformat(", Local {} -> {}",
1436 changedLocals
[i
].id
,
1437 changedLocals
[i
].type
);
1445 struct RBEntryData
: IRExtraData
{
1446 RBEntryData(Trace::RingBufferType t
, SrcKey sk
)
1451 std::string
show() const {
1452 return folly::sformat("{}: {}", ringbufferName(type
), showShort(sk
));
1455 size_t stableHash() const {
1456 return std::hash
<Trace::RingBufferType
>()(type
) ^
1457 SrcKey::StableHasher()(sk
);
1460 bool equals(const RBEntryData
& o
) const {
1461 return type
== o
.type
&& sk
== o
.sk
;
1464 Trace::RingBufferType type
;
1468 struct RBMsgData
: IRExtraData
{
1469 RBMsgData(Trace::RingBufferType t
, const StringData
* msg
)
1473 assertx(msg
->isStatic());
1476 std::string
show() const {
1477 return folly::sformat("{}: {}", ringbufferName(type
), msg
->data());
1480 size_t stableHash() const {
1481 return std::hash
<Trace::RingBufferType
>()(type
) ^ msg
->hash();
1484 bool equals(const RBMsgData
& o
) const {
1485 return type
== o
.type
&& msg
->equal(o
.msg
);
1488 Trace::RingBufferType type
;
1489 const StringData
* msg
;
1492 struct ClassKindData
: IRExtraData
{
1493 explicit ClassKindData(ClassKind kind
): kind(uint32_t(kind
)) {}
1495 std::string
show() const {
1496 switch (static_cast<ClassKind
>(kind
)) {
1497 case ClassKind::Class
: return "cls";
1498 case ClassKind::Interface
: return "interface";
1499 case ClassKind::Trait
: return "trait";
1500 case ClassKind::Enum
: return "enum";
1505 size_t stableHash() const {
1506 return std::hash
<uint32_t>()(kind
);
1509 bool equals(const ClassKindData
& o
) const {
1510 return kind
== o
.kind
;
1513 uint32_t kind
; // ... allows for direct usage in native_call
1516 struct NewStructData
: IRExtraData
{
1517 std::string
show() const;
1519 size_t stableHash() const {
1520 auto hash
= folly::hash::hash_combine(
1521 std::hash
<int32_t>()(offset
.offset
),
1522 std::hash
<uint32_t>()(numKeys
)
1525 for (uint32_t i
= 0; i
< numKeys
; i
++) {
1526 hash
= folly::hash::hash_combine(
1528 keys
[i
]->hashStatic()
1534 bool equals(const NewStructData
& o
) const {
1535 if (offset
!= o
.offset
) return false;
1536 if (numKeys
!= o
.numKeys
) return false;
1537 for (uint32_t i
= 0; i
< numKeys
; i
++) {
1538 if (keys
[i
] != o
.keys
[i
]) return false;
1543 IRSPRelOffset offset
;
1548 struct ArrayLayoutData
: IRExtraData
{
1549 explicit ArrayLayoutData(ArrayLayout layout
) : layout(layout
) {}
1551 std::string
show() const { return layout
.describe(); }
1553 size_t stableHash() const { return layout
.toUint16(); }
1555 bool equals(const ArrayLayoutData
& o
) const { return layout
== o
.layout
; }
1560 struct NewBespokeStructData
: IRExtraData
{
1561 NewBespokeStructData(ArrayLayout layout
, IRSPRelOffset offset
,
1562 uint32_t numSlots
, Slot
* slots
)
1563 : layout(layout
), offset(offset
), numSlots(numSlots
), slots(slots
) {}
1565 std::string
show() const;
1567 size_t stableHash() const {
1568 auto hash
= folly::hash::hash_combine(
1569 std::hash
<uint16_t>()(layout
.toUint16()),
1570 std::hash
<int32_t>()(offset
.offset
),
1571 std::hash
<uint32_t>()(numSlots
)
1573 for (auto i
= 0; i
< numSlots
; i
++) {
1574 hash
= folly::hash::hash_combine(hash
, slots
[i
]);
1579 bool equals(const NewBespokeStructData
& o
) const {
1580 if (layout
!= o
.layout
) return false;
1581 if (offset
!= o
.offset
) return false;
1582 if (numSlots
!= o
.numSlots
) return false;
1583 for (auto i
= 0; i
< numSlots
; i
++) {
1584 if (slots
[i
] != o
.slots
[i
]) return false;
1590 IRSPRelOffset offset
;
1595 struct InitStructPositionsData
: IRExtraData
{
1596 InitStructPositionsData(ArrayLayout layout
, uint32_t numSlots
, Slot
* slots
)
1597 : layout(layout
), numSlots(numSlots
), slots(slots
) {}
1599 std::string
show() const;
1601 size_t stableHash() const {
1602 auto hash
= folly::hash::hash_combine(
1603 std::hash
<uint16_t>()(layout
.toUint16()),
1604 std::hash
<uint32_t>()(numSlots
)
1606 for (auto i
= 0; i
< numSlots
; i
++) {
1607 hash
= folly::hash::hash_combine(hash
, slots
[i
]);
1612 bool equals(const InitStructPositionsData
& o
) const {
1613 if (layout
!= o
.layout
) return false;
1614 if (numSlots
!= o
.numSlots
) return false;
1615 for (auto i
= 0; i
< numSlots
; i
++) {
1616 if (slots
[i
] != o
.slots
[i
]) return false;
1626 struct PackedArrayData
: IRExtraData
{
1627 explicit PackedArrayData(uint32_t size
) : size(size
) {}
1628 std::string
show() const { return folly::format("{}", size
).str(); }
1630 size_t stableHash() const {
1631 return std::hash
<uint32_t>()(size
);
1634 bool equals(const PackedArrayData
& o
) const {
1635 return size
== o
.size
;
1641 struct InitPackedArrayLoopData
: IRExtraData
{
1642 explicit InitPackedArrayLoopData(IRSPRelOffset offset
, uint32_t size
)
1647 std::string
show() const {
1648 return folly::format("{},{}", offset
.offset
, size
).str();
1651 size_t stableHash() const {
1652 return folly::hash::hash_combine(
1653 std::hash
<int32_t>()(offset
.offset
),
1654 std::hash
<uint32_t>()(size
)
1658 bool equals(const InitPackedArrayLoopData
& o
) const {
1659 return offset
== o
.offset
&& size
== o
.size
;
1662 IRSPRelOffset offset
;
1666 struct CreateAAWHData
: IRExtraData
{
1667 explicit CreateAAWHData(uint32_t first
, uint32_t count
)
1672 std::string
show() const {
1673 return folly::format("{},{}", first
, count
).str();
1676 size_t stableHash() const {
1677 return folly::hash::hash_combine(
1678 std::hash
<uint32_t>()(first
),
1679 std::hash
<uint32_t>()(count
)
1683 bool equals(const CreateAAWHData
& o
) const {
1684 return first
== o
.first
&& count
== o
.count
;
1691 struct CountWHNotDoneData
: IRExtraData
{
1692 explicit CountWHNotDoneData(uint32_t first
, uint32_t count
)
1697 std::string
show() const {
1698 return folly::format("{},{}", first
, count
).str();
1701 size_t stableHash() const {
1702 return folly::hash::hash_combine(
1703 std::hash
<uint32_t>()(first
),
1704 std::hash
<uint32_t>()(count
)
1708 bool equals(const CountWHNotDoneData
& o
) const {
1709 return first
== o
.first
&& count
== o
.count
;
1716 struct NewKeysetArrayData
: IRExtraData
{
1717 explicit NewKeysetArrayData(IRSPRelOffset offset
, uint32_t size
)
1722 std::string
show() const {
1723 return folly::format("{},{}", offset
.offset
, size
).str();
1726 size_t stableHash() const {
1727 return folly::hash::hash_combine(
1728 std::hash
<int32_t>()(offset
.offset
),
1729 std::hash
<uint32_t>()(size
)
1733 bool equals(const NewKeysetArrayData
& o
) const {
1734 return offset
== o
.offset
&& size
== o
.size
;
1737 IRSPRelOffset offset
;
1741 struct MemoValueStaticData
: IRExtraData
{
1742 explicit MemoValueStaticData(const Func
* func
,
1743 folly::Optional
<bool> asyncEager
,
1746 , asyncEager
{asyncEager
}
1747 , loadAux
{loadAux
} {}
1748 std::string
show() const {
1749 return folly::sformat(
1751 func
->fullName()->toCppString(),
1752 asyncEager
? folly::to
<std::string
>(*asyncEager
) : "-",
1757 size_t stableHash() const {
1758 return folly::hash::hash_combine(
1760 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1761 std::hash
<bool>()(loadAux
)
1765 bool equals(const MemoValueStaticData
& o
) const {
1766 return func
== o
.func
&& asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
;
1770 folly::Optional
<bool> asyncEager
;
1774 struct MemoValueInstanceData
: IRExtraData
{
1775 explicit MemoValueInstanceData(Slot slot
,
1777 folly::Optional
<bool> asyncEager
,
1781 , asyncEager
{asyncEager
}
1782 , loadAux
{loadAux
} {}
1783 std::string
show() const {
1784 return folly::sformat(
1788 asyncEager
? folly::to
<std::string
>(*asyncEager
) : "-",
1793 size_t stableHash() const {
1794 return folly::hash::hash_combine(
1795 std::hash
<Slot
>()(slot
),
1797 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1798 std::hash
<bool>()(loadAux
)
1802 bool equals(const MemoValueInstanceData
& o
) const {
1803 return slot
== o
.slot
&& func
== o
.func
&&
1804 asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
;
1809 folly::Optional
<bool> asyncEager
;
1813 struct MemoCacheStaticData
: IRExtraData
{
1814 MemoCacheStaticData(const Func
* func
,
1817 folly::Optional
<bool> asyncEager
,
1822 , asyncEager
{asyncEager
}
1823 , loadAux
{loadAux
} {}
1825 MemoCacheStaticData
* clone(Arena
& arena
) const {
1827 new (arena
) MemoCacheStaticData(func
, keys
, types
, asyncEager
, loadAux
);
1828 auto tmp
= new (arena
) bool[keys
.count
];
1829 std::copy(types
, types
+ keys
.count
, tmp
);
1834 std::string
show() const {
1836 ret
+= folly::sformat("{},{}", func
->fullName(), HPHP::show(keys
));
1837 if (keys
.count
> 0) {
1839 for (auto i
= 0; i
< keys
.count
; ++i
) {
1840 if (i
> 0) ret
+= ",";
1841 ret
+= folly::sformat("{}", types
[i
] ? "string" : "int");
1848 size_t stableHash() const {
1849 auto hash
= folly::hash::hash_combine(
1851 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1852 std::hash
<uint32_t>()(keys
.first
),
1853 std::hash
<uint32_t>()(keys
.count
),
1854 std::hash
<bool>()(loadAux
)
1856 for (auto i
= 0; i
< keys
.count
; i
++) {
1857 hash
= folly::hash::hash_combine(
1859 std::hash
<bool>()(types
[i
])
1865 bool equals(const MemoCacheStaticData
& o
) const {
1866 if (func
== o
.func
&& asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
&&
1867 keys
.first
== o
.keys
.first
&& keys
.count
== o
.keys
.count
) {
1868 for (auto i
= 0; i
< keys
.count
; i
++) {
1869 if (types
[i
] != o
.types
[i
]) return false;
1879 folly::Optional
<bool> asyncEager
;
1883 struct MemoCacheInstanceData
: IRExtraData
{
1884 MemoCacheInstanceData(Slot slot
,
1889 folly::Optional
<bool> asyncEager
,
1896 , asyncEager
{asyncEager
}
1897 , loadAux
{loadAux
} {}
1899 MemoCacheInstanceData
* clone(Arena
& arena
) const {
1900 auto p
= new (arena
) MemoCacheInstanceData(
1901 slot
, keys
, types
, func
, shared
, asyncEager
, loadAux
1903 auto tmp
= new (arena
) bool[keys
.count
];
1904 std::copy(types
, types
+ keys
.count
, tmp
);
1909 std::string
show() const {
1910 return folly::sformat(
1916 using namespace folly::gen
;
1917 return range
<uint32_t>(0, keys
.count
)
1918 | map([this] (uint32_t i
) { return types
[i
] ? "string" : "int"; })
1919 | unsplit
<std::string
>(",");
1921 shared
? "shared" : "non-shared"
1925 size_t stableHash() const {
1926 auto hash
= folly::hash::hash_combine(
1927 std::hash
<Slot
>()(slot
),
1929 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1930 std::hash
<uint32_t>()(keys
.first
),
1931 std::hash
<uint32_t>()(keys
.count
),
1932 std::hash
<bool>()(loadAux
),
1933 std::hash
<bool>()(shared
)
1935 for (auto i
= 0; i
< keys
.count
; i
++) {
1936 hash
= folly::hash::hash_combine(
1938 std::hash
<bool>()(types
[i
])
1944 bool equals(const MemoCacheInstanceData
& o
) const {
1945 if (slot
== o
.slot
&& func
== o
.func
&& asyncEager
== o
.asyncEager
&&
1946 loadAux
== o
.loadAux
&& keys
.first
== o
.keys
.first
&&
1947 keys
.count
== o
.keys
.count
&& shared
== o
.shared
) {
1948 for (auto i
= 0; i
< keys
.count
; i
++) {
1949 if (types
[i
] != o
.types
[i
]) return false;
1961 folly::Optional
<bool> asyncEager
;
1965 struct MOpModeData
: IRExtraData
{
1966 explicit MOpModeData(MOpMode mode
) : mode
{mode
} {}
1968 std::string
show() const { return subopToName(mode
); }
1970 size_t stableHash() const {
1971 return std::hash
<MOpMode
>()(mode
);
1974 bool equals(const MOpModeData
& o
) const {
1975 return mode
== o
.mode
;
1981 struct PropData
: IRExtraData
{
1982 explicit PropData(MOpMode mode
, ReadOnlyOp op
) : mode
{mode
}, op(op
) {}
1984 std::string
show() const {
1985 return fmt::format("{} {}", subopToName(mode
), subopToName(op
));
1988 size_t stableHash() const {
1989 return folly::hash::hash_combine(
1990 std::hash
<MOpMode
>()(mode
),
1991 std::hash
<ReadOnlyOp
>()(op
)
1995 bool equals(const PropData
& o
) const {
1996 return mode
== o
.mode
&& op
== o
.op
;
2003 struct ReadOnlyData
: IRExtraData
{
2004 explicit ReadOnlyData(ReadOnlyOp op
) : op(op
) {}
2005 std::string
show() const { return subopToName(op
); }
2007 size_t stableHash() const {
2008 return std::hash
<ReadOnlyOp
>()(op
);
2011 bool equals(const ReadOnlyData
& o
) const {
2018 struct SetOpData
: IRExtraData
{
2019 explicit SetOpData(SetOpOp op
) : op(op
) {}
2020 std::string
show() const { return subopToName(op
); }
2022 size_t stableHash() const {
2023 return std::hash
<SetOpOp
>()(op
);
2026 bool equals(const SetOpData
& o
) const {
2033 struct DecRefData
: IRExtraData
{
2034 explicit DecRefData(int locId
= -1) : locId(locId
) {}
2035 std::string
show() const {
2036 return locId
!= -1 ? folly::to
<std::string
>("Loc", locId
) : "-";
2039 size_t stableHash() const {
2040 return std::hash
<int>()(locId
);
2043 bool equals(const DecRefData
& o
) const {
2044 return locId
== o
.locId
;
2047 int locId
; // If a known local, this has its id; -1 otherwise.
2050 struct IncDecData
: IRExtraData
{
2051 explicit IncDecData(IncDecOp op
) : op(op
) {}
2052 std::string
show() const { return subopToName(op
); }
2054 size_t stableHash() const {
2055 return std::hash
<IncDecOp
>()(op
);
2058 bool equals(const IncDecData
& o
) const {
2065 struct SuspendOffset
: IRExtraData
{
2066 explicit SuspendOffset(Offset off
) : off(off
) {}
2067 std::string
show() const { return folly::to
<std::string
>(off
); }
2069 size_t stableHash() const {
2070 return std::hash
<Offset
>()(off
);
2073 bool equals(const SuspendOffset
& o
) const {
2074 return off
== o
.off
;
2080 struct GeneratorState
: IRExtraData
{
2081 explicit GeneratorState(BaseGenerator::State state
) : state(state
) {}
2082 std::string
show() const {
2083 using U
= std::underlying_type
<BaseGenerator::State
>::type
;
2084 return folly::to
<std::string
>(static_cast<U
>(state
));
2087 size_t stableHash() const {
2088 return std::hash
<BaseGenerator::State
>()(state
);
2091 bool equals(const GeneratorState
& o
) const {
2092 return state
== o
.state
;
2095 BaseGenerator::State state
;
2098 struct ContEnterData
: IRExtraData
{
2099 explicit ContEnterData(IRSPRelOffset spOffset
, Offset callBCOffset
,
2101 : spOffset(spOffset
)
2102 , callBCOffset(callBCOffset
)
2106 std::string
show() const {
2107 return folly::to
<std::string
>(spOffset
.offset
, ',', callBCOffset
,
2108 isAsync
? ",async" : "");
2111 size_t stableHash() const {
2112 return folly::hash::hash_combine(
2113 std::hash
<int32_t>()(spOffset
.offset
),
2114 std::hash
<Offset
>()(callBCOffset
),
2115 std::hash
<bool>()(isAsync
)
2119 bool equals(const ContEnterData
& o
) const {
2120 return spOffset
== o
.spOffset
&& callBCOffset
== o
.callBCOffset
&&
2121 isAsync
&& o
.isAsync
;
2124 IRSPRelOffset spOffset
;
2125 Offset callBCOffset
;
2129 struct NewColData
: IRExtraData
{
2130 explicit NewColData(CollectionType itype
)
2134 std::string
show() const {
2135 return collections::typeToString(type
)->toCppString();
2138 size_t stableHash() const {
2139 return std::hash
<CollectionType
>()(type
);
2142 bool equals(const NewColData
& o
) const {
2143 return type
== o
.type
;
2146 CollectionType type
;
2149 struct LocalIdRange
: IRExtraData
{
2150 LocalIdRange(uint32_t start
, uint32_t end
)
2155 std::string
show() const {
2156 return folly::format("[{}, {})", start
, end
).str();
2159 size_t stableHash() const {
2160 return folly::hash::hash_combine(
2161 std::hash
<uint32_t>()(start
),
2162 std::hash
<uint32_t>()(end
)
2166 bool equals(const LocalIdRange
& o
) const {
2167 return start
== o
.start
&& end
== o
.end
;
2170 uint32_t start
, end
;
2173 struct StackRange
: IRExtraData
{
2174 StackRange(IRSPRelOffset start
, uint32_t count
)
2179 std::string
show() const {
2180 return folly::sformat("[{}, {})", start
.offset
, start
.offset
+ count
);
2183 size_t stableHash() const {
2184 return folly::hash::hash_combine(std::hash
<int32_t>()(start
.offset
),
2185 std::hash
<int32_t>()(count
));
2188 bool equals(const StackRange
& o
) const {
2189 return start
== o
.start
&& count
== o
.count
;
2192 IRSPRelOffset start
;
2196 struct FuncEntryData
: IRExtraData
{
2197 FuncEntryData(const Func
* func
, uint32_t argc
)
2202 std::string
show() const {
2203 return folly::format(
2210 size_t stableHash() const {
2211 return folly::hash::hash_combine(
2213 std::hash
<uint32_t>()(argc
)
2217 bool equals(const FuncEntryData
& o
) const {
2218 return func
== o
.func
&& argc
== o
.argc
;
2225 struct CheckInOutsData
: IRExtraData
{
2226 CheckInOutsData(unsigned firstBit
, uint64_t mask
, uint64_t vals
)
2227 : firstBit(safe_cast
<int>(firstBit
))
2232 std::string
show() const {
2233 return folly::format("{},{},{}", firstBit
, mask
, vals
).str();
2236 size_t stableHash() const {
2237 return folly::hash::hash_combine(
2238 std::hash
<int>()(firstBit
),
2239 std::hash
<uint64_t>()(mask
),
2240 std::hash
<uint64_t>()(vals
)
2244 bool equals(const CheckInOutsData
& o
) const {
2245 return firstBit
== o
.firstBit
&& mask
== o
.mask
&& vals
== o
.vals
;
2253 struct ProfileCallTargetData
: IRExtraData
{
2254 explicit ProfileCallTargetData(rds::Handle handle
)
2258 std::string
show() const {
2259 return folly::to
<std::string
>(handle
);
2262 size_t stableHash() const {
2263 auto const sym
= rds::reverseLink(handle
);
2265 return rds::symbol_stable_hash(*sym
);
2268 bool equals(const ProfileCallTargetData
& o
) const {
2269 return handle
== o
.handle
;
2275 struct BeginInliningData
: IRExtraData
{
2276 BeginInliningData(IRSPRelOffset offset
, const Func
* func
, int cost
, int na
)
2283 std::string
show() const {
2284 return folly::to
<std::string
>("IRSPOff ", spOffset
.offset
,
2285 " FUNC ", func
->fullName()->data());
2288 size_t stableHash() const {
2289 return folly::hash::hash_combine(
2290 std::hash
<int32_t>()(spOffset
.offset
),
2292 std::hash
<int>()(cost
),
2293 std::hash
<int>()(numArgs
)
2297 bool equals(const BeginInliningData
& o
) const {
2298 return spOffset
== o
.spOffset
&& func
== o
.func
&& cost
== o
.cost
&&
2299 numArgs
== o
.numArgs
;
2302 IRSPRelOffset spOffset
;
2308 struct ParamData
: IRExtraData
{
2309 explicit ParamData(int32_t paramId
) : paramId(paramId
) {}
2311 std::string
show() const {
2312 return folly::to
<std::string
>(paramId
);
2315 size_t stableHash() const { return std::hash
<int32_t>()(paramId
); }
2316 bool equals(const ParamData
& o
) const {
2317 return paramId
== o
.paramId
;
2322 struct ParamWithTCData
: IRExtraData
{
2323 explicit ParamWithTCData(int32_t paramId
, const TypeConstraint
* tc
)
2327 std::string
show() const {
2328 return folly::to
<std::string
>(paramId
, ":", tc
->displayName());
2331 size_t stableHash() const {
2332 return folly::hash::hash_combine(
2333 std::hash
<int32_t>()(paramId
),
2334 std::hash
<std::string
>()(tc
->fullName()) // Not great but hey its easy.
2338 bool equals(const ParamWithTCData
& o
) const {
2339 return paramId
== o
.paramId
&&
2344 const TypeConstraint
* tc
;
2347 struct TypeConstraintData
: IRExtraData
{
2348 explicit TypeConstraintData(const TypeConstraint
* tc
)
2351 std::string
show() const { return tc
->displayName(); }
2353 size_t stableHash() const {
2354 // Not great but easy.
2355 return std::hash
<std::string
>()(tc
->fullName());
2358 bool equals(const TypeConstraintData
& o
) const {
2359 return *tc
== *o
.tc
;
2362 const TypeConstraint
* tc
;
2365 struct RaiseClsMethPropConvertNoticeData
: IRExtraData
{
2366 RaiseClsMethPropConvertNoticeData(const TypeConstraint
* tc
, bool isSProp
)
2371 std::string
show() const {
2372 return folly::to
<std::string
>(tc
->displayName(), ",", isSProp
);
2375 size_t stableHash() const {
2376 return folly::hash::hash_combine(
2377 std::hash
<bool>()(isSProp
),
2378 std::hash
<std::string
>()(tc
->fullName()) // Not great but hey its easy.
2382 bool equals(const RaiseClsMethPropConvertNoticeData
& o
) const {
2383 return isSProp
== o
.isSProp
&&
2387 union { const TypeConstraint
* tc
; int64_t tcIntVal
; };
2391 struct ArrayGetExceptionData
: IRExtraData
{
2392 explicit ArrayGetExceptionData(bool isInOut
) : isInOut(isInOut
) {}
2394 std::string
show() const {
2395 return isInOut
? "inout" : "none";
2398 size_t stableHash() const {
2399 return std::hash
<bool>()(isInOut
);
2402 bool equals(const ArrayGetExceptionData
& o
) const {
2403 return isInOut
== o
.isInOut
;
2409 struct AssertReason
: IRExtraData
{
2410 explicit AssertReason(Reason r
) : reason
{r
.file
, r
.line
} {}
2412 std::string
show() const {
2413 return jit::show(reason
);
2416 size_t stableHash() const {
2417 return folly::hash::hash_combine(
2418 std::hash
<const char*>()(reason
.file
),
2419 std::hash
<unsigned>()(reason
.line
)
2423 bool equals(const AssertReason
& o
) const {
2424 return reason
== o
.reason
;
2430 #define ASSERT_REASON AssertReason{Reason{__FILE__, __LINE__}}
2432 struct EndCatchData
: IRExtraData
{
2433 enum class CatchMode
{ UnwindOnly
, CallCatch
, SideExit
, LocalsDecRefd
};
2434 enum class FrameMode
{ Phplogue
, Stublogue
};
2435 enum class Teardown
{ NA
, None
, Full
, OnlyThis
};
2437 explicit EndCatchData(IRSPRelOffset offset
, CatchMode mode
,
2438 FrameMode stublogue
, Teardown teardown
)
2441 , stublogue
{stublogue
}
2442 , teardown
{teardown
}
2445 std::string
show() const {
2446 return folly::to
<std::string
>(
2447 "IRSPOff ", offset
.offset
, ",",
2448 mode
== CatchMode::UnwindOnly
? "UnwindOnly" :
2449 mode
== CatchMode::CallCatch
? "CallCatch" :
2450 mode
== CatchMode::SideExit
? "SideExit" : "LocalsDecRefd", ",",
2451 stublogue
== FrameMode::Stublogue
? "Stublogue" : "Phplogue", ",",
2452 teardown
== Teardown::NA
? "NA" :
2453 teardown
== Teardown::None
? "None" :
2454 teardown
== Teardown::Full
? "Full" : "OnlyThis");
2457 size_t stableHash() const {
2458 return folly::hash::hash_combine(
2459 std::hash
<int32_t>()(offset
.offset
),
2460 std::hash
<CatchMode
>()(mode
),
2461 std::hash
<FrameMode
>()(stublogue
),
2462 std::hash
<Teardown
>()(teardown
)
2466 bool equals(const EndCatchData
& o
) const {
2467 return offset
== o
.offset
&& mode
== o
.mode
&& stublogue
== o
.stublogue
&&
2468 teardown
== o
.teardown
;
2471 IRSPRelOffset offset
;
2473 FrameMode stublogue
;
2477 struct EnterTCUnwindData
: IRExtraData
{
2478 explicit EnterTCUnwindData(IRSPRelOffset offset
, bool teardown
)
2479 : offset
{offset
}, teardown
{teardown
} {}
2481 std::string
show() const {
2482 return folly::to
<std::string
>(
2483 "IRSPOff ", offset
.offset
, ",",
2484 teardown
? "" : "no-", "teardown"
2488 size_t stableHash() const {
2489 return folly::hash::hash_combine(
2490 std::hash
<int32_t>()(offset
.offset
),
2491 std::hash
<bool>()(teardown
)
2495 bool equals(const EnterTCUnwindData
& o
) const {
2496 return offset
== o
.offset
&& teardown
== o
.teardown
;
2499 IRSPRelOffset offset
;
2504 * Func/Class/Prop attributes
2506 struct AttrData
: IRExtraData
{
2507 explicit AttrData(Attr attr
) : attr(static_cast<int32_t>(attr
)) {}
2509 std::string
show() const {
2510 return folly::format("{}", attr
).str();
2513 size_t stableHash() const {
2514 return std::hash
<int32_t>()(attr
);
2517 size_t hash() const {
2518 return std::hash
<int32_t>()(attr
);
2521 bool equals(const AttrData
& o
) const {
2522 return attr
== o
.attr
;
2528 struct MethCallerData
: IRExtraData
{
2529 explicit MethCallerData(bool isCls
) : isCls(isCls
) {}
2530 std::string
show() const {
2531 return folly::format("{}", isCls
).str();
2534 size_t stableHash() const {
2535 return std::hash
<bool>()(isCls
);
2538 bool equals(const MethCallerData
& o
) const {
2539 return isCls
== o
.isCls
;
2545 struct LoggingProfileData
: IRExtraData
{
2546 LoggingProfileData(bespoke::LoggingProfile
* profile
, bool isStatic
)
2548 , isStatic(isStatic
)
2551 std::string
show() const {
2552 // profile->source is already printed in the instruction's marker.
2553 return folly::sformat("{}", reinterpret_cast<void*>(profile
));
2556 size_t stableHash() const;
2558 bool equals(const LoggingProfileData
& o
) const {
2559 return profile
== o
.profile
;
2562 bespoke::LoggingProfile
* profile
;
2563 bool isStatic
; // Whether the output is guaranteed to be static
2566 struct SinkProfileData
: IRExtraData
{
2567 explicit SinkProfileData(bespoke::SinkProfile
* profile
)
2571 std::string
show() const {
2572 // profile->sink is already printed in the instruction's marker.
2573 return folly::sformat("{}", reinterpret_cast<void*>(profile
));
2576 size_t stableHash() const;
2578 bool equals(const SinkProfileData
& o
) const {
2579 return profile
== o
.profile
;
2582 bespoke::SinkProfile
* profile
;
2585 struct BespokeGetData
: IRExtraData
{
2586 enum class KeyState
{ Present
, Unknown
};
2588 explicit BespokeGetData(KeyState state
) : state(state
) {}
2590 std::string
show() const {
2592 case KeyState::Present
: return "Present";
2593 case KeyState::Unknown
: return "Unknown";
2595 always_assert(false);
2598 size_t hash() const {
2599 return stableHash();
2602 size_t stableHash() const {
2603 return std::hash
<KeyState
>()(state
);
2606 bool equals(const BespokeGetData
& o
) const {
2607 return state
== o
.state
;
2613 struct ConvNoticeData
: IRExtraData
{
2614 explicit ConvNoticeData(ConvNoticeLevel l
= ConvNoticeLevel::None
,
2615 const StringData
* r
= nullptr,
2616 bool noticeWithinNum_
= true)
2617 : level(l
), reason(r
), noticeWithinNum(noticeWithinNum_
) {}
2618 std::string
show() const {
2619 assertx(level
== ConvNoticeLevel::None
|| (reason
!= nullptr && reason
->isStatic()));
2620 const auto reason_str
= reason
? folly::format(" for {}", reason
).str() : "";
2621 const auto num_str
= !noticeWithinNum
? " with no intra-num notices": "";
2622 return folly::format("{}{}{}", convOpToName(level
), reason_str
, num_str
).str();
2625 size_t stableHash() const {
2626 return folly::hash::hash_combine(
2627 std::hash
<ConvNoticeLevel
>()(level
),
2628 std::hash
<const StringData
*>()(reason
),
2629 std::hash
<bool>()(noticeWithinNum
)
2633 bool equals(const ConvNoticeData
& o
) const {
2634 // can use pointer equality bc reason is always a StaticString
2635 return level
== o
.level
&& reason
== o
.reason
&& noticeWithinNum
== o
.noticeWithinNum
;
2638 ConvNoticeLevel level
;
2639 union { const StringData
* reason
; int64_t reasonIntVal
; };
2640 // whether to trigger notices for conversions between int and double
2641 bool noticeWithinNum
= true;
2644 struct BadComparisonData
: IRExtraData
{
2645 explicit BadComparisonData(bool eqOp
) : eq(eqOp
) {}
2646 std::string
show() const { return eq
? "For Eq" : "For Cmp"; }
2647 size_t stableHash() const { return std::hash
<bool>()(eq
); }
2648 bool equals(const BadComparisonData
& o
) const { return eq
== o
.eq
; }
2652 //////////////////////////////////////////////////////////////////////
2654 #define X(op, data) \
2655 template<> struct IRExtraDataType<op> { typedef data type; }; \
2656 template<> struct OpHasExtraData<op> { enum { value = 1 }; }; \
2657 static_assert(boost::has_trivial_destructor<data>::value, \
2658 "IR extra data type must be trivially destructible")
2660 X(DictIdx
, SizeHintData
);
2661 X(LdBindAddr
, LdBindAddrData
);
2662 X(ProfileSwitchDest
, ProfileSwitchData
);
2663 X(JmpSwitchDest
, JmpSwitchData
);
2664 X(LdSSwitchDestFast
, LdSSwitchData
);
2665 X(LdSSwitchDestSlow
, LdSSwitchData
);
2666 X(CheckLoc
, LocalId
);
2667 X(AssertLoc
, LocalId
);
2668 X(LdLocAddr
, LocalId
);
2670 X(LdClsInitElem
, IndexData
);
2671 X(StClsInitElem
, IndexData
);
2673 X(StLocRange
, LocalIdRange
);
2674 X(AdvanceDictPtrIter
, IterOffsetData
);
2675 X(StFrameFunc
, FuncData
);
2676 X(CheckIter
, IterTypeData
);
2677 X(StIterBase
, IterId
);
2678 X(StIterType
, IterTypeData
);
2679 X(StIterPos
, IterId
);
2680 X(StIterEnd
, IterId
);
2681 X(LdIterBase
, IterId
);
2682 X(LdIterPos
, IterId
);
2683 X(LdIterEnd
, IterId
);
2684 X(KillIter
, IterId
);
2685 X(IterFree
, IterId
);
2686 X(IterInit
, IterData
);
2687 X(IterInitK
, IterData
);
2688 X(IterNext
, IterData
);
2689 X(IterNextK
, IterData
);
2690 X(LIterInit
, IterData
);
2691 X(LIterInitK
, IterData
);
2692 X(LIterNext
, IterData
);
2693 X(LIterNextK
, IterData
);
2694 X(ConstructInstance
, ClassData
);
2695 X(ConstructClosure
, ClassData
);
2696 X(InitProps
, ClassData
);
2697 X(InitSProps
, ClassData
);
2698 X(NewInstanceRaw
, ClassData
);
2699 X(InitObjProps
, ClassData
);
2700 X(InitObjMemoSlots
, ClassData
);
2701 X(InstanceOfIfaceVtable
, InstanceOfIfaceVtableData
);
2702 X(ResolveTypeStruct
, ResolveTypeStructData
);
2703 X(ExtendsClass
, ExtendsClassData
);
2704 X(CheckStk
, IRSPRelOffsetData
);
2705 X(StStk
, IRSPRelOffsetData
);
2706 X(StStkRange
, StackRange
);
2707 X(StOutValue
, IndexData
);
2708 X(LdOutAddr
, IndexData
);
2709 X(AssertStk
, IRSPRelOffsetData
);
2710 X(DefFP
, DefFPData
);
2711 X(DefFrameRelSP
, DefStackData
);
2712 X(DefRegSP
, DefStackData
);
2713 X(LdStk
, IRSPRelOffsetData
);
2714 X(LdStkAddr
, IRSPRelOffsetData
);
2715 X(InlineCall
, InlineCallData
);
2716 X(StFrameMeta
, StFrameMetaData
);
2717 X(BeginInlining
, BeginInliningData
);
2718 X(ReqBindJmp
, ReqBindJmpData
);
2719 X(ReqRetranslate
, IRSPRelOffsetData
);
2720 X(ReqRetranslateOpt
, IRSPRelOffsetData
);
2721 X(CheckCold
, TransIDData
);
2722 X(IncProfCounter
, TransIDData
);
2723 X(LogArrayReach
, SinkProfileData
);
2724 X(NewLoggingArray
, LoggingProfileData
);
2725 X(BespokeGet
, BespokeGetData
);
2726 X(DefFuncEntryFP
, FuncData
);
2728 X(CallBuiltin
, CallBuiltinData
);
2729 X(RetCtrl
, RetCtrlData
);
2730 X(AsyncFuncRet
, IRSPRelOffsetData
);
2731 X(AsyncFuncRetSlow
, IRSPRelOffsetData
);
2732 X(AsyncSwitchFast
, IRSPRelOffsetData
);
2733 X(LookupClsMethodCache
, ClsMethodData
);
2734 X(LdClsMethodCacheFunc
, ClsMethodData
);
2735 X(LdClsMethodCacheCls
, ClsMethodData
);
2736 X(LdClsMethodFCacheFunc
, ClsMethodData
);
2737 X(LookupClsMethodFCache
, ClsMethodData
);
2738 X(LdIfaceMethod
, IfaceMethodData
);
2739 X(LdClsCns
, ClsCnsName
);
2740 X(InitClsCns
, ClsCnsName
);
2741 X(InitSubClsCns
, LdSubClsCnsData
);
2742 X(LdSubClsCns
, LdSubClsCnsData
);
2743 X(LdSubClsCnsClsName
, LdSubClsCnsData
);
2744 X(CheckSubClsCns
, LdSubClsCnsData
);
2745 X(ProfileSubClsCns
, ProfileSubClsCnsData
);
2746 X(LdFuncCached
, FuncNameData
);
2747 X(LookupFuncCached
, FuncNameData
);
2748 X(LdObjMethodS
, FuncNameData
);
2749 X(LdObjMethodD
, OptClassData
);
2750 X(ThrowMissingArg
, FuncArgData
);
2751 X(RaiseClsMethPropConvertNotice
,RaiseClsMethPropConvertNoticeData
);
2752 X(RaiseTooManyArg
, FuncData
);
2753 X(RaiseCoeffectsCallViolation
, FuncData
);
2754 X(RaiseCoeffectsFunParamTypeViolation
, ParamData
);
2755 X(ThrowParamInOutMismatch
, ParamData
);
2756 X(ThrowParamInOutMismatchRange
, CheckInOutsData
);
2757 X(ThrowParameterWrongType
, FuncArgTypeData
);
2758 X(CheckClsReifiedGenericMismatch
,
2760 X(IsFunReifiedGenericsMatched
, FuncData
);
2761 X(IsTypeStruct
, RDSHandleData
);
2762 X(InterpOne
, InterpOneData
);
2763 X(InterpOneCF
, InterpOneData
);
2764 X(StClosureArg
, IndexData
);
2765 X(RBTraceEntry
, RBEntryData
);
2766 X(RBTraceMsg
, RBMsgData
);
2767 X(OODeclExists
, ClassKindData
);
2768 X(NewStructDict
, NewStructData
);
2769 X(NewRecord
, NewStructData
);
2770 X(AllocStructDict
, NewStructData
);
2771 X(AllocBespokeStructDict
, ArrayLayoutData
);
2772 X(InitStructPositions
, InitStructPositionsData
);
2773 X(NewBespokeStructDict
, NewBespokeStructData
);
2774 X(AllocVec
, PackedArrayData
);
2775 X(NewKeysetArray
, NewKeysetArrayData
);
2776 X(InitVecElemLoop
, InitPackedArrayLoopData
);
2777 X(InitVecElem
, IndexData
);
2778 X(InitDictElem
, KeyedIndexData
);
2779 X(InitStructElem
, KeyedIndexData
);
2780 X(CreateAAWH
, CreateAAWHData
);
2781 X(CountWHNotDone
, CountWHNotDoneData
);
2782 X(CheckDictOffset
, IndexData
);
2783 X(CheckKeysetOffset
, IndexData
);
2784 X(ProfileDictAccess
, ArrayAccessProfileData
);
2785 X(ProfileKeysetAccess
, ArrayAccessProfileData
);
2786 X(ProfileType
, RDSHandleData
);
2787 X(ProfileCall
, ProfileCallTargetData
);
2788 X(ProfileMethod
, ProfileCallTargetData
);
2789 X(ProfileIsTypeStruct
, RDSHandleData
);
2790 X(LdRDSAddr
, RDSHandleData
);
2791 X(CheckRDSInitialized
, RDSHandleData
);
2792 X(MarkRDSInitialized
, RDSHandleData
);
2793 X(LdInitRDSAddr
, RDSHandleData
);
2794 X(BaseG
, MOpModeData
);
2796 X(PropQ
, ReadOnlyData
);
2797 X(PropDX
, PropData
);
2798 X(ElemX
, MOpModeData
);
2799 X(ElemDX
, MOpModeData
);
2800 X(ElemUX
, MOpModeData
);
2801 X(CGetProp
, PropData
);
2802 X(CGetPropQ
, ReadOnlyData
);
2803 X(CGetElem
, MOpModeData
);
2804 X(MemoGetStaticValue
, MemoValueStaticData
);
2805 X(MemoSetStaticValue
, MemoValueStaticData
);
2806 X(MemoGetStaticCache
, MemoCacheStaticData
);
2807 X(MemoSetStaticCache
, MemoCacheStaticData
);
2808 X(MemoGetLSBValue
, MemoValueStaticData
);
2809 X(MemoSetLSBValue
, MemoValueStaticData
);
2810 X(MemoGetLSBCache
, MemoCacheStaticData
);
2811 X(MemoSetLSBCache
, MemoCacheStaticData
);
2812 X(MemoGetInstanceValue
, MemoValueInstanceData
);
2813 X(MemoSetInstanceValue
, MemoValueInstanceData
);
2814 X(MemoGetInstanceCache
, MemoCacheInstanceData
);
2815 X(MemoSetInstanceCache
, MemoCacheInstanceData
);
2816 X(SetOpProp
, SetOpData
);
2817 X(SetOpTV
, SetOpData
);
2818 X(SetProp
, ReadOnlyData
);
2819 X(OutlineSetOp
, SetOpData
);
2820 X(IncDecProp
, IncDecData
);
2821 X(SetOpElem
, SetOpData
);
2822 X(IncDecElem
, IncDecData
);
2823 X(StArResumeAddr
, SuspendOffset
);
2824 X(StContArState
, GeneratorState
);
2825 X(ContEnter
, ContEnterData
);
2826 X(EagerSyncVMRegs
, IRSPRelOffsetData
);
2827 X(JmpSSwitchDest
, IRSPRelOffsetData
);
2828 X(DbgTrashStk
, IRSPRelOffsetData
);
2829 X(DbgTrashFrame
, IRSPRelOffsetData
);
2830 X(DbgTraceCall
, IRSPRelOffsetData
);
2831 X(LdPropAddr
, IndexData
);
2832 X(LdInitPropAddr
, IndexData
);
2833 X(NewCol
, NewColData
);
2834 X(NewColFromArray
, NewColData
);
2835 X(CheckSurpriseFlagsEnter
, FuncEntryData
);
2836 X(CheckSurpriseAndStack
, FuncEntryData
);
2837 X(ContPreNext
, IsAsyncData
);
2838 X(ContStartedCheck
, IsAsyncData
);
2839 X(ContValid
, IsAsyncData
);
2840 X(LdContResumeAddr
, IsAsyncData
);
2841 X(LdContActRec
, IsAsyncData
);
2842 X(DecRef
, DecRefData
);
2843 X(DecRefNZ
, DecRefData
);
2844 X(ProfileDecRef
, DecRefData
);
2845 X(LdTVAux
, LdTVAuxData
);
2846 X(CheckInOuts
, CheckInOutsData
);
2847 X(DbgAssertRefCount
, AssertReason
);
2848 X(Unreachable
, AssertReason
);
2849 X(EndBlock
, AssertReason
);
2850 X(VerifyRetCallable
, ParamData
);
2851 X(VerifyRetCls
, ParamData
);
2852 X(VerifyRetRecDesc
, ParamData
);
2853 X(VerifyParamFail
, ParamWithTCData
);
2854 X(VerifyParamFailHard
, ParamWithTCData
);
2855 X(VerifyRetFail
, ParamWithTCData
);
2856 X(VerifyRetFailHard
, ParamWithTCData
);
2857 X(VerifyReifiedLocalType
, ParamData
);
2858 X(VerifyPropCls
, TypeConstraintData
);
2859 X(VerifyPropRecDesc
, TypeConstraintData
);
2860 X(VerifyPropFail
, TypeConstraintData
);
2861 X(VerifyPropFailHard
, TypeConstraintData
);
2862 X(VerifyProp
, TypeConstraintData
);
2863 X(VerifyPropCoerce
, TypeConstraintData
);
2864 X(EndCatch
, EndCatchData
);
2865 X(EnterTCUnwind
, EnterTCUnwindData
);
2866 X(FuncHasAttr
, AttrData
);
2867 X(ClassHasAttr
, AttrData
);
2868 X(LdMethCallerName
, MethCallerData
);
2869 X(LdRecDescCached
, RecNameData
);
2870 X(LdRecDescCachedSafe
, RecNameData
);
2871 X(LdUnitPerRequestFilepath
, RDSHandleData
);
2872 X(LdClsTypeCns
, LdClsTypeCnsData
);
2873 X(ConvTVToStr
, ConvNoticeData
);
2874 X(ConvTVToInt
, ConvNoticeData
);
2875 X(ConvObjToInt
, ConvNoticeData
);
2876 X(CheckFuncNeedsCoverage
, FuncData
);
2877 X(RecordFuncCall
, FuncData
);
2878 X(RaiseBadComparisonViolation
, BadComparisonData
);
2882 //////////////////////////////////////////////////////////////////////
2884 template<bool hasExtra
, Opcode opc
, class T
> struct AssertExtraTypes
{
2885 static void doassertx() {
2886 assertx(!"called extra on an opcode without extra data");
2888 static void doassert_same() {
2889 assertx(!"called extra on an opcode without extra data");
2893 template<Opcode opc
, class T
> struct AssertExtraTypes
<true,opc
,T
> {
2894 typedef typename IRExtraDataType
<opc
>::type ExtraType
;
2896 static void doassertx() {
2897 if (!std::is_base_of
<T
,ExtraType
>::value
) {
2898 assertx(!"extra<T> was called with an extra data "
2899 "type that doesn't match the opcode type");
2902 static void doassert_same() {
2903 if (!std::is_same
<T
,ExtraType
>::value
) {
2904 fprintf(stderr
, "opcode = %s\n", opcodeName(opc
)); \
2905 assertx(!"extra<T> was called with an extra data type that "
2906 "doesn't exactly match the opcode type");
2911 // Asserts that Opcode opc has extradata and it is of type T, or a
2912 // type derived from T.
2913 template<class T
> void assert_opcode_extra(Opcode opc
) {
2914 #define O(opcode, dstinfo, srcinfo, flags) \
2917 OpHasExtraData<opcode>::value,opcode,T \
2920 switch (opc
) { IR_OPCODES
default: not_reached(); }
2924 template<class T
> void assert_opcode_extra_same(Opcode opc
) {
2925 #define O(opcode, dstinfo, srcinfo, flags) \
2928 OpHasExtraData<opcode>::value,opcode,T \
2929 >::doassert_same(); \
2931 switch (opc
) { IR_OPCODES
default: not_reached(); }
2935 size_t hashExtra(Opcode opc
, const IRExtraData
* data
);
2936 size_t stableHashExtra(Opcode opc
, const IRExtraData
* data
);
2937 bool equalsExtra(Opcode opc
, const IRExtraData
* a
, const IRExtraData
* b
);
2938 IRExtraData
* cloneExtra(Opcode opc
, IRExtraData
* data
, Arena
& a
);
2939 std::string
showExtra(Opcode opc
, const IRExtraData
* data
);
2941 //////////////////////////////////////////////////////////////////////