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 AllocUninitBespokeStructData
: IRExtraData
{
1596 AllocUninitBespokeStructData(ArrayLayout layout
,
1599 : layout(layout
), numSlots(numSlots
), slots(slots
) {}
1601 std::string
show() const;
1603 size_t stableHash() const {
1604 auto hash
= folly::hash::hash_combine(
1605 std::hash
<uint16_t>()(layout
.toUint16()),
1606 std::hash
<uint32_t>()(numSlots
)
1608 for (auto i
= 0; i
< numSlots
; i
++) {
1609 hash
= folly::hash::hash_combine(hash
, slots
[i
]);
1614 bool equals(const AllocUninitBespokeStructData
& o
) const {
1615 if (layout
!= o
.layout
) return false;
1616 if (numSlots
!= o
.numSlots
) return false;
1617 for (auto i
= 0; i
< numSlots
; i
++) {
1618 if (slots
[i
] != o
.slots
[i
]) return false;
1628 struct PackedArrayData
: IRExtraData
{
1629 explicit PackedArrayData(uint32_t size
) : size(size
) {}
1630 std::string
show() const { return folly::format("{}", size
).str(); }
1632 size_t stableHash() const {
1633 return std::hash
<uint32_t>()(size
);
1636 bool equals(const PackedArrayData
& o
) const {
1637 return size
== o
.size
;
1643 struct InitPackedArrayLoopData
: IRExtraData
{
1644 explicit InitPackedArrayLoopData(IRSPRelOffset offset
, uint32_t size
)
1649 std::string
show() const {
1650 return folly::format("{},{}", offset
.offset
, size
).str();
1653 size_t stableHash() const {
1654 return folly::hash::hash_combine(
1655 std::hash
<int32_t>()(offset
.offset
),
1656 std::hash
<uint32_t>()(size
)
1660 bool equals(const InitPackedArrayLoopData
& o
) const {
1661 return offset
== o
.offset
&& size
== o
.size
;
1664 IRSPRelOffset offset
;
1668 struct CreateAAWHData
: IRExtraData
{
1669 explicit CreateAAWHData(uint32_t first
, uint32_t count
)
1674 std::string
show() const {
1675 return folly::format("{},{}", first
, count
).str();
1678 size_t stableHash() const {
1679 return folly::hash::hash_combine(
1680 std::hash
<uint32_t>()(first
),
1681 std::hash
<uint32_t>()(count
)
1685 bool equals(const CreateAAWHData
& o
) const {
1686 return first
== o
.first
&& count
== o
.count
;
1693 struct CountWHNotDoneData
: IRExtraData
{
1694 explicit CountWHNotDoneData(uint32_t first
, uint32_t count
)
1699 std::string
show() const {
1700 return folly::format("{},{}", first
, count
).str();
1703 size_t stableHash() const {
1704 return folly::hash::hash_combine(
1705 std::hash
<uint32_t>()(first
),
1706 std::hash
<uint32_t>()(count
)
1710 bool equals(const CountWHNotDoneData
& o
) const {
1711 return first
== o
.first
&& count
== o
.count
;
1718 struct NewKeysetArrayData
: IRExtraData
{
1719 explicit NewKeysetArrayData(IRSPRelOffset offset
, uint32_t size
)
1724 std::string
show() const {
1725 return folly::format("{},{}", offset
.offset
, size
).str();
1728 size_t stableHash() const {
1729 return folly::hash::hash_combine(
1730 std::hash
<int32_t>()(offset
.offset
),
1731 std::hash
<uint32_t>()(size
)
1735 bool equals(const NewKeysetArrayData
& o
) const {
1736 return offset
== o
.offset
&& size
== o
.size
;
1739 IRSPRelOffset offset
;
1743 struct MemoValueStaticData
: IRExtraData
{
1744 explicit MemoValueStaticData(const Func
* func
,
1745 folly::Optional
<bool> asyncEager
,
1748 , asyncEager
{asyncEager
}
1749 , loadAux
{loadAux
} {}
1750 std::string
show() const {
1751 return folly::sformat(
1753 func
->fullName()->toCppString(),
1754 asyncEager
? folly::to
<std::string
>(*asyncEager
) : "-",
1759 size_t stableHash() const {
1760 return folly::hash::hash_combine(
1762 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1763 std::hash
<bool>()(loadAux
)
1767 bool equals(const MemoValueStaticData
& o
) const {
1768 return func
== o
.func
&& asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
;
1772 folly::Optional
<bool> asyncEager
;
1776 struct MemoValueInstanceData
: IRExtraData
{
1777 explicit MemoValueInstanceData(Slot slot
,
1779 folly::Optional
<bool> asyncEager
,
1783 , asyncEager
{asyncEager
}
1784 , loadAux
{loadAux
} {}
1785 std::string
show() const {
1786 return folly::sformat(
1790 asyncEager
? folly::to
<std::string
>(*asyncEager
) : "-",
1795 size_t stableHash() const {
1796 return folly::hash::hash_combine(
1797 std::hash
<Slot
>()(slot
),
1799 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1800 std::hash
<bool>()(loadAux
)
1804 bool equals(const MemoValueInstanceData
& o
) const {
1805 return slot
== o
.slot
&& func
== o
.func
&&
1806 asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
;
1811 folly::Optional
<bool> asyncEager
;
1815 struct MemoCacheStaticData
: IRExtraData
{
1816 MemoCacheStaticData(const Func
* func
,
1819 folly::Optional
<bool> asyncEager
,
1824 , asyncEager
{asyncEager
}
1825 , loadAux
{loadAux
} {}
1827 MemoCacheStaticData
* clone(Arena
& arena
) const {
1829 new (arena
) MemoCacheStaticData(func
, keys
, types
, asyncEager
, loadAux
);
1830 auto tmp
= new (arena
) bool[keys
.count
];
1831 std::copy(types
, types
+ keys
.count
, tmp
);
1836 std::string
show() const {
1838 ret
+= folly::sformat("{},{}", func
->fullName(), HPHP::show(keys
));
1839 if (keys
.count
> 0) {
1841 for (auto i
= 0; i
< keys
.count
; ++i
) {
1842 if (i
> 0) ret
+= ",";
1843 ret
+= folly::sformat("{}", types
[i
] ? "string" : "int");
1850 size_t stableHash() const {
1851 auto hash
= folly::hash::hash_combine(
1853 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1854 std::hash
<uint32_t>()(keys
.first
),
1855 std::hash
<uint32_t>()(keys
.count
),
1856 std::hash
<bool>()(loadAux
)
1858 for (auto i
= 0; i
< keys
.count
; i
++) {
1859 hash
= folly::hash::hash_combine(
1861 std::hash
<bool>()(types
[i
])
1867 bool equals(const MemoCacheStaticData
& o
) const {
1868 if (func
== o
.func
&& asyncEager
== o
.asyncEager
&& loadAux
== o
.loadAux
&&
1869 keys
.first
== o
.keys
.first
&& keys
.count
== o
.keys
.count
) {
1870 for (auto i
= 0; i
< keys
.count
; i
++) {
1871 if (types
[i
] != o
.types
[i
]) return false;
1881 folly::Optional
<bool> asyncEager
;
1885 struct MemoCacheInstanceData
: IRExtraData
{
1886 MemoCacheInstanceData(Slot slot
,
1891 folly::Optional
<bool> asyncEager
,
1898 , asyncEager
{asyncEager
}
1899 , loadAux
{loadAux
} {}
1901 MemoCacheInstanceData
* clone(Arena
& arena
) const {
1902 auto p
= new (arena
) MemoCacheInstanceData(
1903 slot
, keys
, types
, func
, shared
, asyncEager
, loadAux
1905 auto tmp
= new (arena
) bool[keys
.count
];
1906 std::copy(types
, types
+ keys
.count
, tmp
);
1911 std::string
show() const {
1912 return folly::sformat(
1918 using namespace folly::gen
;
1919 return range
<uint32_t>(0, keys
.count
)
1920 | map([this] (uint32_t i
) { return types
[i
] ? "string" : "int"; })
1921 | unsplit
<std::string
>(",");
1923 shared
? "shared" : "non-shared"
1927 size_t stableHash() const {
1928 auto hash
= folly::hash::hash_combine(
1929 std::hash
<Slot
>()(slot
),
1931 std::hash
<folly::Optional
<bool>>()(asyncEager
),
1932 std::hash
<uint32_t>()(keys
.first
),
1933 std::hash
<uint32_t>()(keys
.count
),
1934 std::hash
<bool>()(loadAux
),
1935 std::hash
<bool>()(shared
)
1937 for (auto i
= 0; i
< keys
.count
; i
++) {
1938 hash
= folly::hash::hash_combine(
1940 std::hash
<bool>()(types
[i
])
1946 bool equals(const MemoCacheInstanceData
& o
) const {
1947 if (slot
== o
.slot
&& func
== o
.func
&& asyncEager
== o
.asyncEager
&&
1948 loadAux
== o
.loadAux
&& keys
.first
== o
.keys
.first
&&
1949 keys
.count
== o
.keys
.count
&& shared
== o
.shared
) {
1950 for (auto i
= 0; i
< keys
.count
; i
++) {
1951 if (types
[i
] != o
.types
[i
]) return false;
1963 folly::Optional
<bool> asyncEager
;
1967 struct MOpModeData
: IRExtraData
{
1968 explicit MOpModeData(MOpMode mode
) : mode
{mode
} {}
1970 std::string
show() const { return subopToName(mode
); }
1972 size_t stableHash() const {
1973 return std::hash
<MOpMode
>()(mode
);
1976 bool equals(const MOpModeData
& o
) const {
1977 return mode
== o
.mode
;
1983 struct PropData
: IRExtraData
{
1984 explicit PropData(MOpMode mode
, ReadOnlyOp op
) : mode
{mode
}, op(op
) {}
1986 std::string
show() const {
1987 return fmt::format("{} {}", subopToName(mode
), subopToName(op
));
1990 size_t stableHash() const {
1991 return folly::hash::hash_combine(
1992 std::hash
<MOpMode
>()(mode
),
1993 std::hash
<ReadOnlyOp
>()(op
)
1997 bool equals(const PropData
& o
) const {
1998 return mode
== o
.mode
&& op
== o
.op
;
2005 struct ReadOnlyData
: IRExtraData
{
2006 explicit ReadOnlyData(ReadOnlyOp op
) : op(op
) {}
2007 std::string
show() const { return subopToName(op
); }
2009 size_t stableHash() const {
2010 return std::hash
<ReadOnlyOp
>()(op
);
2013 bool equals(const ReadOnlyData
& o
) const {
2020 struct SetOpData
: IRExtraData
{
2021 explicit SetOpData(SetOpOp op
) : op(op
) {}
2022 std::string
show() const { return subopToName(op
); }
2024 size_t stableHash() const {
2025 return std::hash
<SetOpOp
>()(op
);
2028 bool equals(const SetOpData
& o
) const {
2035 struct DecRefData
: IRExtraData
{
2036 explicit DecRefData(int locId
= -1) : locId(locId
) {}
2037 std::string
show() const {
2038 return locId
!= -1 ? folly::to
<std::string
>("Loc", locId
) : "-";
2041 size_t stableHash() const {
2042 return std::hash
<int>()(locId
);
2045 bool equals(const DecRefData
& o
) const {
2046 return locId
== o
.locId
;
2049 int locId
; // If a known local, this has its id; -1 otherwise.
2052 struct IncDecData
: IRExtraData
{
2053 explicit IncDecData(IncDecOp op
) : op(op
) {}
2054 std::string
show() const { return subopToName(op
); }
2056 size_t stableHash() const {
2057 return std::hash
<IncDecOp
>()(op
);
2060 bool equals(const IncDecData
& o
) const {
2067 struct SuspendOffset
: IRExtraData
{
2068 explicit SuspendOffset(Offset off
) : off(off
) {}
2069 std::string
show() const { return folly::to
<std::string
>(off
); }
2071 size_t stableHash() const {
2072 return std::hash
<Offset
>()(off
);
2075 bool equals(const SuspendOffset
& o
) const {
2076 return off
== o
.off
;
2082 struct GeneratorState
: IRExtraData
{
2083 explicit GeneratorState(BaseGenerator::State state
) : state(state
) {}
2084 std::string
show() const {
2085 using U
= std::underlying_type
<BaseGenerator::State
>::type
;
2086 return folly::to
<std::string
>(static_cast<U
>(state
));
2089 size_t stableHash() const {
2090 return std::hash
<BaseGenerator::State
>()(state
);
2093 bool equals(const GeneratorState
& o
) const {
2094 return state
== o
.state
;
2097 BaseGenerator::State state
;
2100 struct ContEnterData
: IRExtraData
{
2101 explicit ContEnterData(IRSPRelOffset spOffset
, Offset callBCOffset
,
2103 : spOffset(spOffset
)
2104 , callBCOffset(callBCOffset
)
2108 std::string
show() const {
2109 return folly::to
<std::string
>(spOffset
.offset
, ',', callBCOffset
,
2110 isAsync
? ",async" : "");
2113 size_t stableHash() const {
2114 return folly::hash::hash_combine(
2115 std::hash
<int32_t>()(spOffset
.offset
),
2116 std::hash
<Offset
>()(callBCOffset
),
2117 std::hash
<bool>()(isAsync
)
2121 bool equals(const ContEnterData
& o
) const {
2122 return spOffset
== o
.spOffset
&& callBCOffset
== o
.callBCOffset
&&
2123 isAsync
&& o
.isAsync
;
2126 IRSPRelOffset spOffset
;
2127 Offset callBCOffset
;
2131 struct NewColData
: IRExtraData
{
2132 explicit NewColData(CollectionType itype
)
2136 std::string
show() const {
2137 return collections::typeToString(type
)->toCppString();
2140 size_t stableHash() const {
2141 return std::hash
<CollectionType
>()(type
);
2144 bool equals(const NewColData
& o
) const {
2145 return type
== o
.type
;
2148 CollectionType type
;
2151 struct LocalIdRange
: IRExtraData
{
2152 LocalIdRange(uint32_t start
, uint32_t end
)
2157 std::string
show() const {
2158 return folly::format("[{}, {})", start
, end
).str();
2161 size_t stableHash() const {
2162 return folly::hash::hash_combine(
2163 std::hash
<uint32_t>()(start
),
2164 std::hash
<uint32_t>()(end
)
2168 bool equals(const LocalIdRange
& o
) const {
2169 return start
== o
.start
&& end
== o
.end
;
2172 uint32_t start
, end
;
2175 struct FuncEntryData
: IRExtraData
{
2176 FuncEntryData(const Func
* func
, uint32_t argc
)
2181 std::string
show() const {
2182 return folly::format(
2189 size_t stableHash() const {
2190 return folly::hash::hash_combine(
2192 std::hash
<uint32_t>()(argc
)
2196 bool equals(const FuncEntryData
& o
) const {
2197 return func
== o
.func
&& argc
== o
.argc
;
2204 struct CheckInOutsData
: IRExtraData
{
2205 CheckInOutsData(unsigned firstBit
, uint64_t mask
, uint64_t vals
)
2206 : firstBit(safe_cast
<int>(firstBit
))
2211 std::string
show() const {
2212 return folly::format("{},{},{}", firstBit
, mask
, vals
).str();
2215 size_t stableHash() const {
2216 return folly::hash::hash_combine(
2217 std::hash
<int>()(firstBit
),
2218 std::hash
<uint64_t>()(mask
),
2219 std::hash
<uint64_t>()(vals
)
2223 bool equals(const CheckInOutsData
& o
) const {
2224 return firstBit
== o
.firstBit
&& mask
== o
.mask
&& vals
== o
.vals
;
2232 struct ProfileCallTargetData
: IRExtraData
{
2233 explicit ProfileCallTargetData(rds::Handle handle
)
2237 std::string
show() const {
2238 return folly::to
<std::string
>(handle
);
2241 size_t stableHash() const {
2242 auto const sym
= rds::reverseLink(handle
);
2244 return rds::symbol_stable_hash(*sym
);
2247 bool equals(const ProfileCallTargetData
& o
) const {
2248 return handle
== o
.handle
;
2254 struct BeginInliningData
: IRExtraData
{
2255 BeginInliningData(IRSPRelOffset offset
, const Func
* func
, int cost
, int na
)
2262 std::string
show() const {
2263 return folly::to
<std::string
>("IRSPOff ", spOffset
.offset
,
2264 " FUNC ", func
->fullName()->data());
2267 size_t stableHash() const {
2268 return folly::hash::hash_combine(
2269 std::hash
<int32_t>()(spOffset
.offset
),
2271 std::hash
<int>()(cost
),
2272 std::hash
<int>()(numArgs
)
2276 bool equals(const BeginInliningData
& o
) const {
2277 return spOffset
== o
.spOffset
&& func
== o
.func
&& cost
== o
.cost
&&
2278 numArgs
== o
.numArgs
;
2281 IRSPRelOffset spOffset
;
2287 struct ParamData
: IRExtraData
{
2288 explicit ParamData(int32_t paramId
) : paramId(paramId
) {}
2290 std::string
show() const {
2291 return folly::to
<std::string
>(paramId
);
2294 size_t stableHash() const { return std::hash
<int32_t>()(paramId
); }
2295 bool equals(const ParamData
& o
) const {
2296 return paramId
== o
.paramId
;
2301 struct ParamWithTCData
: IRExtraData
{
2302 explicit ParamWithTCData(int32_t paramId
, const TypeConstraint
* tc
)
2306 std::string
show() const {
2307 return folly::to
<std::string
>(paramId
, ":", tc
->displayName());
2310 size_t stableHash() const {
2311 return folly::hash::hash_combine(
2312 std::hash
<int32_t>()(paramId
),
2313 std::hash
<std::string
>()(tc
->fullName()) // Not great but hey its easy.
2317 bool equals(const ParamWithTCData
& o
) const {
2318 return paramId
== o
.paramId
&&
2323 const TypeConstraint
* tc
;
2326 struct TypeConstraintData
: IRExtraData
{
2327 explicit TypeConstraintData(const TypeConstraint
* tc
)
2330 std::string
show() const { return tc
->displayName(); }
2332 size_t stableHash() const {
2333 // Not great but easy.
2334 return std::hash
<std::string
>()(tc
->fullName());
2337 bool equals(const TypeConstraintData
& o
) const {
2338 return *tc
== *o
.tc
;
2341 const TypeConstraint
* tc
;
2344 struct RaiseClsMethPropConvertNoticeData
: IRExtraData
{
2345 RaiseClsMethPropConvertNoticeData(const TypeConstraint
* tc
, bool isSProp
)
2350 std::string
show() const {
2351 return folly::to
<std::string
>(tc
->displayName(), ",", isSProp
);
2354 size_t stableHash() const {
2355 return folly::hash::hash_combine(
2356 std::hash
<bool>()(isSProp
),
2357 std::hash
<std::string
>()(tc
->fullName()) // Not great but hey its easy.
2361 bool equals(const RaiseClsMethPropConvertNoticeData
& o
) const {
2362 return isSProp
== o
.isSProp
&&
2366 union { const TypeConstraint
* tc
; int64_t tcIntVal
; };
2370 struct ArrayGetExceptionData
: IRExtraData
{
2371 explicit ArrayGetExceptionData(bool isInOut
) : isInOut(isInOut
) {}
2373 std::string
show() const {
2374 return isInOut
? "inout" : "none";
2377 size_t stableHash() const {
2378 return std::hash
<bool>()(isInOut
);
2381 bool equals(const ArrayGetExceptionData
& o
) const {
2382 return isInOut
== o
.isInOut
;
2388 struct AssertReason
: IRExtraData
{
2389 explicit AssertReason(Reason r
) : reason
{r
.file
, r
.line
} {}
2391 std::string
show() const {
2392 return jit::show(reason
);
2395 size_t stableHash() const {
2396 return folly::hash::hash_combine(
2397 std::hash
<const char*>()(reason
.file
),
2398 std::hash
<unsigned>()(reason
.line
)
2402 bool equals(const AssertReason
& o
) const {
2403 return reason
== o
.reason
;
2409 #define ASSERT_REASON AssertReason{Reason{__FILE__, __LINE__}}
2411 struct EndCatchData
: IRExtraData
{
2412 enum class CatchMode
{ UnwindOnly
, CallCatch
, SideExit
, LocalsDecRefd
};
2413 enum class FrameMode
{ Phplogue
, Stublogue
};
2414 enum class Teardown
{ NA
, None
, Full
, OnlyThis
};
2416 explicit EndCatchData(IRSPRelOffset offset
, CatchMode mode
,
2417 FrameMode stublogue
, Teardown teardown
)
2420 , stublogue
{stublogue
}
2421 , teardown
{teardown
}
2424 std::string
show() const {
2425 return folly::to
<std::string
>(
2426 "IRSPOff ", offset
.offset
, ",",
2427 mode
== CatchMode::UnwindOnly
? "UnwindOnly" :
2428 mode
== CatchMode::CallCatch
? "CallCatch" :
2429 mode
== CatchMode::SideExit
? "SideExit" : "LocalsDecRefd", ",",
2430 stublogue
== FrameMode::Stublogue
? "Stublogue" : "Phplogue", ",",
2431 teardown
== Teardown::NA
? "NA" :
2432 teardown
== Teardown::None
? "None" :
2433 teardown
== Teardown::Full
? "Full" : "OnlyThis");
2436 size_t stableHash() const {
2437 return folly::hash::hash_combine(
2438 std::hash
<int32_t>()(offset
.offset
),
2439 std::hash
<CatchMode
>()(mode
),
2440 std::hash
<FrameMode
>()(stublogue
),
2441 std::hash
<Teardown
>()(teardown
)
2445 bool equals(const EndCatchData
& o
) const {
2446 return offset
== o
.offset
&& mode
== o
.mode
&& stublogue
== o
.stublogue
&&
2447 teardown
== o
.teardown
;
2450 IRSPRelOffset offset
;
2452 FrameMode stublogue
;
2456 struct EnterTCUnwindData
: IRExtraData
{
2457 explicit EnterTCUnwindData(IRSPRelOffset offset
, bool teardown
)
2458 : offset
{offset
}, teardown
{teardown
} {}
2460 std::string
show() const {
2461 return folly::to
<std::string
>(
2462 "IRSPOff ", offset
.offset
, ",",
2463 teardown
? "" : "no-", "teardown"
2467 size_t stableHash() const {
2468 return folly::hash::hash_combine(
2469 std::hash
<int32_t>()(offset
.offset
),
2470 std::hash
<bool>()(teardown
)
2474 bool equals(const EnterTCUnwindData
& o
) const {
2475 return offset
== o
.offset
&& teardown
== o
.teardown
;
2478 IRSPRelOffset offset
;
2483 * Func/Class/Prop attributes
2485 struct AttrData
: IRExtraData
{
2486 explicit AttrData(Attr attr
) : attr(static_cast<int32_t>(attr
)) {}
2488 std::string
show() const {
2489 return folly::format("{}", attr
).str();
2492 size_t stableHash() const {
2493 return std::hash
<int32_t>()(attr
);
2496 size_t hash() const {
2497 return std::hash
<int32_t>()(attr
);
2500 bool equals(const AttrData
& o
) const {
2501 return attr
== o
.attr
;
2507 struct MethCallerData
: IRExtraData
{
2508 explicit MethCallerData(bool isCls
) : isCls(isCls
) {}
2509 std::string
show() const {
2510 return folly::format("{}", isCls
).str();
2513 size_t stableHash() const {
2514 return std::hash
<bool>()(isCls
);
2517 bool equals(const MethCallerData
& o
) const {
2518 return isCls
== o
.isCls
;
2524 struct LoggingProfileData
: IRExtraData
{
2525 LoggingProfileData(bespoke::LoggingProfile
* profile
, bool isStatic
)
2527 , isStatic(isStatic
)
2530 std::string
show() const {
2531 // profile->source is already printed in the instruction's marker.
2532 return folly::sformat("{}", reinterpret_cast<void*>(profile
));
2535 size_t stableHash() const;
2537 bool equals(const LoggingProfileData
& o
) const {
2538 return profile
== o
.profile
;
2541 bespoke::LoggingProfile
* profile
;
2542 bool isStatic
; // Whether the output is guaranteed to be static
2545 struct SinkProfileData
: IRExtraData
{
2546 explicit SinkProfileData(bespoke::SinkProfile
* profile
)
2550 std::string
show() const {
2551 // profile->sink is already printed in the instruction's marker.
2552 return folly::sformat("{}", reinterpret_cast<void*>(profile
));
2555 size_t stableHash() const;
2557 bool equals(const SinkProfileData
& o
) const {
2558 return profile
== o
.profile
;
2561 bespoke::SinkProfile
* profile
;
2564 struct BespokeGetData
: IRExtraData
{
2565 enum class KeyState
{ Present
, Unknown
};
2567 explicit BespokeGetData(KeyState state
) : state(state
) {}
2569 std::string
show() const {
2571 case KeyState::Present
: return "Present";
2572 case KeyState::Unknown
: return "Unknown";
2574 always_assert(false);
2577 size_t hash() const {
2578 return stableHash();
2581 size_t stableHash() const {
2582 return std::hash
<KeyState
>()(state
);
2585 bool equals(const BespokeGetData
& o
) const {
2586 return state
== o
.state
;
2592 struct ConvNoticeData
: IRExtraData
{
2593 explicit ConvNoticeData(ConvNoticeLevel l
= ConvNoticeLevel::None
,
2594 const StringData
* r
= nullptr,
2595 bool noticeWithinNum_
= true)
2596 : level(l
), reason(r
), noticeWithinNum(noticeWithinNum_
) {}
2597 std::string
show() const {
2598 assertx(level
== ConvNoticeLevel::None
|| (reason
!= nullptr && reason
->isStatic()));
2599 const auto reason_str
= reason
? folly::format(" for {}", reason
).str() : "";
2600 const auto num_str
= !noticeWithinNum
? " with no intra-num notices": "";
2601 return folly::format("{}{}{}", convOpToName(level
), reason_str
, num_str
).str();
2604 size_t stableHash() const {
2605 return folly::hash::hash_combine(
2606 std::hash
<ConvNoticeLevel
>()(level
),
2607 std::hash
<const StringData
*>()(reason
),
2608 std::hash
<bool>()(noticeWithinNum
)
2612 bool equals(const ConvNoticeData
& o
) const {
2613 // can use pointer equality bc reason is always a StaticString
2614 return level
== o
.level
&& reason
== o
.reason
&& noticeWithinNum
== o
.noticeWithinNum
;
2617 ConvNoticeLevel level
;
2618 union { const StringData
* reason
; int64_t reasonIntVal
; };
2619 // whether to trigger notices for conversions between int and double
2620 bool noticeWithinNum
= true;
2623 //////////////////////////////////////////////////////////////////////
2625 #define X(op, data) \
2626 template<> struct IRExtraDataType<op> { typedef data type; }; \
2627 template<> struct OpHasExtraData<op> { enum { value = 1 }; }; \
2628 static_assert(boost::has_trivial_destructor<data>::value, \
2629 "IR extra data type must be trivially destructible")
2631 X(DictIdx
, SizeHintData
);
2632 X(LdBindAddr
, LdBindAddrData
);
2633 X(ProfileSwitchDest
, ProfileSwitchData
);
2634 X(JmpSwitchDest
, JmpSwitchData
);
2635 X(LdSSwitchDestFast
, LdSSwitchData
);
2636 X(LdSSwitchDestSlow
, LdSSwitchData
);
2637 X(CheckLoc
, LocalId
);
2638 X(AssertLoc
, LocalId
);
2639 X(LdLocAddr
, LocalId
);
2641 X(LdClsInitElem
, IndexData
);
2642 X(StClsInitElem
, IndexData
);
2644 X(StLocRange
, LocalIdRange
);
2645 X(AdvanceDictPtrIter
, IterOffsetData
);
2646 X(StFrameFunc
, FuncData
);
2647 X(CheckIter
, IterTypeData
);
2648 X(StIterBase
, IterId
);
2649 X(StIterType
, IterTypeData
);
2650 X(StIterPos
, IterId
);
2651 X(StIterEnd
, IterId
);
2652 X(LdIterBase
, IterId
);
2653 X(LdIterPos
, IterId
);
2654 X(LdIterEnd
, IterId
);
2655 X(KillIter
, IterId
);
2656 X(IterFree
, IterId
);
2657 X(IterInit
, IterData
);
2658 X(IterInitK
, IterData
);
2659 X(IterNext
, IterData
);
2660 X(IterNextK
, IterData
);
2661 X(LIterInit
, IterData
);
2662 X(LIterInitK
, IterData
);
2663 X(LIterNext
, IterData
);
2664 X(LIterNextK
, IterData
);
2665 X(ConstructInstance
, ClassData
);
2666 X(ConstructClosure
, ClassData
);
2667 X(InitProps
, ClassData
);
2668 X(InitSProps
, ClassData
);
2669 X(NewInstanceRaw
, ClassData
);
2670 X(InitObjProps
, ClassData
);
2671 X(InitObjMemoSlots
, ClassData
);
2672 X(InstanceOfIfaceVtable
, InstanceOfIfaceVtableData
);
2673 X(ResolveTypeStruct
, ResolveTypeStructData
);
2674 X(ExtendsClass
, ExtendsClassData
);
2675 X(CheckStk
, IRSPRelOffsetData
);
2676 X(StStk
, IRSPRelOffsetData
);
2677 X(StOutValue
, IndexData
);
2678 X(LdOutAddr
, IndexData
);
2679 X(AssertStk
, IRSPRelOffsetData
);
2680 X(DefFP
, DefFPData
);
2681 X(DefFrameRelSP
, DefStackData
);
2682 X(DefRegSP
, DefStackData
);
2683 X(LdStk
, IRSPRelOffsetData
);
2684 X(LdStkAddr
, IRSPRelOffsetData
);
2685 X(InlineCall
, InlineCallData
);
2686 X(StFrameMeta
, StFrameMetaData
);
2687 X(BeginInlining
, BeginInliningData
);
2688 X(ReqBindJmp
, ReqBindJmpData
);
2689 X(ReqRetranslate
, IRSPRelOffsetData
);
2690 X(ReqRetranslateOpt
, IRSPRelOffsetData
);
2691 X(CheckCold
, TransIDData
);
2692 X(IncProfCounter
, TransIDData
);
2693 X(LogArrayReach
, SinkProfileData
);
2694 X(NewLoggingArray
, LoggingProfileData
);
2695 X(BespokeGet
, BespokeGetData
);
2696 X(DefFuncEntryFP
, FuncData
);
2698 X(CallBuiltin
, CallBuiltinData
);
2699 X(RetCtrl
, RetCtrlData
);
2700 X(AsyncFuncRet
, IRSPRelOffsetData
);
2701 X(AsyncFuncRetSlow
, IRSPRelOffsetData
);
2702 X(AsyncSwitchFast
, IRSPRelOffsetData
);
2703 X(LookupClsMethodCache
, ClsMethodData
);
2704 X(LdClsMethodCacheFunc
, ClsMethodData
);
2705 X(LdClsMethodCacheCls
, ClsMethodData
);
2706 X(LdClsMethodFCacheFunc
, ClsMethodData
);
2707 X(LookupClsMethodFCache
, ClsMethodData
);
2708 X(LdIfaceMethod
, IfaceMethodData
);
2709 X(LdClsCns
, ClsCnsName
);
2710 X(InitClsCns
, ClsCnsName
);
2711 X(InitSubClsCns
, LdSubClsCnsData
);
2712 X(LdSubClsCns
, LdSubClsCnsData
);
2713 X(LdSubClsCnsClsName
, LdSubClsCnsData
);
2714 X(CheckSubClsCns
, LdSubClsCnsData
);
2715 X(ProfileSubClsCns
, ProfileSubClsCnsData
);
2716 X(LdFuncCached
, FuncNameData
);
2717 X(LookupFuncCached
, FuncNameData
);
2718 X(LdObjMethodS
, FuncNameData
);
2719 X(LdObjMethodD
, OptClassData
);
2720 X(ThrowMissingArg
, FuncArgData
);
2721 X(RaiseClsMethPropConvertNotice
,RaiseClsMethPropConvertNoticeData
);
2722 X(RaiseTooManyArg
, FuncData
);
2723 X(RaiseCoeffectsCallViolation
, FuncData
);
2724 X(RaiseCoeffectsFunParamTypeViolation
, ParamData
);
2725 X(ThrowParamInOutMismatch
, ParamData
);
2726 X(ThrowParamInOutMismatchRange
, CheckInOutsData
);
2727 X(ThrowParameterWrongType
, FuncArgTypeData
);
2728 X(CheckClsReifiedGenericMismatch
,
2730 X(IsFunReifiedGenericsMatched
, FuncData
);
2731 X(IsTypeStruct
, RDSHandleData
);
2732 X(InterpOne
, InterpOneData
);
2733 X(InterpOneCF
, InterpOneData
);
2734 X(StClosureArg
, IndexData
);
2735 X(RBTraceEntry
, RBEntryData
);
2736 X(RBTraceMsg
, RBMsgData
);
2737 X(OODeclExists
, ClassKindData
);
2738 X(NewStructDict
, NewStructData
);
2739 X(NewRecord
, NewStructData
);
2740 X(AllocStructDict
, NewStructData
);
2741 X(AllocBespokeStructDict
, ArrayLayoutData
);
2742 X(AllocUninitBespokeStructDict
, AllocUninitBespokeStructData
);
2743 X(NewBespokeStructDict
, NewBespokeStructData
);
2744 X(AllocVec
, PackedArrayData
);
2745 X(NewKeysetArray
, NewKeysetArrayData
);
2746 X(InitVecElemLoop
, InitPackedArrayLoopData
);
2747 X(InitVecElem
, IndexData
);
2748 X(InitDictElem
, KeyedIndexData
);
2749 X(InitStructElem
, KeyedIndexData
);
2750 X(CreateAAWH
, CreateAAWHData
);
2751 X(CountWHNotDone
, CountWHNotDoneData
);
2752 X(CheckDictOffset
, IndexData
);
2753 X(CheckKeysetOffset
, IndexData
);
2754 X(ProfileDictAccess
, ArrayAccessProfileData
);
2755 X(ProfileKeysetAccess
, ArrayAccessProfileData
);
2756 X(ProfileType
, RDSHandleData
);
2757 X(ProfileCall
, ProfileCallTargetData
);
2758 X(ProfileMethod
, ProfileCallTargetData
);
2759 X(ProfileIsTypeStruct
, RDSHandleData
);
2760 X(LdRDSAddr
, RDSHandleData
);
2761 X(CheckRDSInitialized
, RDSHandleData
);
2762 X(MarkRDSInitialized
, RDSHandleData
);
2763 X(LdInitRDSAddr
, RDSHandleData
);
2764 X(BaseG
, MOpModeData
);
2766 X(PropQ
, ReadOnlyData
);
2767 X(PropDX
, PropData
);
2768 X(ElemX
, MOpModeData
);
2769 X(ElemDX
, MOpModeData
);
2770 X(ElemUX
, MOpModeData
);
2771 X(CGetProp
, PropData
);
2772 X(CGetPropQ
, ReadOnlyData
);
2773 X(CGetElem
, MOpModeData
);
2774 X(MemoGetStaticValue
, MemoValueStaticData
);
2775 X(MemoSetStaticValue
, MemoValueStaticData
);
2776 X(MemoGetStaticCache
, MemoCacheStaticData
);
2777 X(MemoSetStaticCache
, MemoCacheStaticData
);
2778 X(MemoGetLSBValue
, MemoValueStaticData
);
2779 X(MemoSetLSBValue
, MemoValueStaticData
);
2780 X(MemoGetLSBCache
, MemoCacheStaticData
);
2781 X(MemoSetLSBCache
, MemoCacheStaticData
);
2782 X(MemoGetInstanceValue
, MemoValueInstanceData
);
2783 X(MemoSetInstanceValue
, MemoValueInstanceData
);
2784 X(MemoGetInstanceCache
, MemoCacheInstanceData
);
2785 X(MemoSetInstanceCache
, MemoCacheInstanceData
);
2786 X(SetOpProp
, SetOpData
);
2787 X(SetOpTV
, SetOpData
);
2788 X(SetProp
, ReadOnlyData
);
2789 X(OutlineSetOp
, SetOpData
);
2790 X(IncDecProp
, IncDecData
);
2791 X(SetOpElem
, SetOpData
);
2792 X(IncDecElem
, IncDecData
);
2793 X(StArResumeAddr
, SuspendOffset
);
2794 X(StContArState
, GeneratorState
);
2795 X(ContEnter
, ContEnterData
);
2796 X(EagerSyncVMRegs
, IRSPRelOffsetData
);
2797 X(JmpSSwitchDest
, IRSPRelOffsetData
);
2798 X(DbgTrashStk
, IRSPRelOffsetData
);
2799 X(DbgTrashFrame
, IRSPRelOffsetData
);
2800 X(DbgTraceCall
, IRSPRelOffsetData
);
2801 X(LdPropAddr
, IndexData
);
2802 X(LdInitPropAddr
, IndexData
);
2803 X(NewCol
, NewColData
);
2804 X(NewColFromArray
, NewColData
);
2805 X(CheckSurpriseFlagsEnter
, FuncEntryData
);
2806 X(CheckSurpriseAndStack
, FuncEntryData
);
2807 X(ContPreNext
, IsAsyncData
);
2808 X(ContStartedCheck
, IsAsyncData
);
2809 X(ContValid
, IsAsyncData
);
2810 X(LdContResumeAddr
, IsAsyncData
);
2811 X(LdContActRec
, IsAsyncData
);
2812 X(DecRef
, DecRefData
);
2813 X(DecRefNZ
, DecRefData
);
2814 X(ProfileDecRef
, DecRefData
);
2815 X(LdTVAux
, LdTVAuxData
);
2816 X(CheckInOuts
, CheckInOutsData
);
2817 X(DbgAssertRefCount
, AssertReason
);
2818 X(Unreachable
, AssertReason
);
2819 X(EndBlock
, AssertReason
);
2820 X(VerifyRetCallable
, ParamData
);
2821 X(VerifyRetCls
, ParamData
);
2822 X(VerifyRetRecDesc
, ParamData
);
2823 X(VerifyParamFail
, ParamWithTCData
);
2824 X(VerifyParamFailHard
, ParamWithTCData
);
2825 X(VerifyRetFail
, ParamWithTCData
);
2826 X(VerifyRetFailHard
, ParamWithTCData
);
2827 X(VerifyReifiedLocalType
, ParamData
);
2828 X(VerifyPropCls
, TypeConstraintData
);
2829 X(VerifyPropRecDesc
, TypeConstraintData
);
2830 X(VerifyPropFail
, TypeConstraintData
);
2831 X(VerifyPropFailHard
, TypeConstraintData
);
2832 X(VerifyProp
, TypeConstraintData
);
2833 X(VerifyPropCoerce
, TypeConstraintData
);
2834 X(EndCatch
, EndCatchData
);
2835 X(EnterTCUnwind
, EnterTCUnwindData
);
2836 X(FuncHasAttr
, AttrData
);
2837 X(ClassHasAttr
, AttrData
);
2838 X(LdMethCallerName
, MethCallerData
);
2839 X(LdRecDescCached
, RecNameData
);
2840 X(LdRecDescCachedSafe
, RecNameData
);
2841 X(LdUnitPerRequestFilepath
, RDSHandleData
);
2842 X(LdClsTypeCns
, LdClsTypeCnsData
);
2843 X(ConvTVToStr
, ConvNoticeData
);
2844 X(ConvTVToInt
, ConvNoticeData
);
2845 X(ConvObjToInt
, ConvNoticeData
);
2849 //////////////////////////////////////////////////////////////////////
2851 template<bool hasExtra
, Opcode opc
, class T
> struct AssertExtraTypes
{
2852 static void doassertx() {
2853 assertx(!"called extra on an opcode without extra data");
2855 static void doassert_same() {
2856 assertx(!"called extra on an opcode without extra data");
2860 template<Opcode opc
, class T
> struct AssertExtraTypes
<true,opc
,T
> {
2861 typedef typename IRExtraDataType
<opc
>::type ExtraType
;
2863 static void doassertx() {
2864 if (!std::is_base_of
<T
,ExtraType
>::value
) {
2865 assertx(!"extra<T> was called with an extra data "
2866 "type that doesn't match the opcode type");
2869 static void doassert_same() {
2870 if (!std::is_same
<T
,ExtraType
>::value
) {
2871 fprintf(stderr
, "opcode = %s\n", opcodeName(opc
)); \
2872 assertx(!"extra<T> was called with an extra data type that "
2873 "doesn't exactly match the opcode type");
2878 // Asserts that Opcode opc has extradata and it is of type T, or a
2879 // type derived from T.
2880 template<class T
> void assert_opcode_extra(Opcode opc
) {
2881 #define O(opcode, dstinfo, srcinfo, flags) \
2884 OpHasExtraData<opcode>::value,opcode,T \
2887 switch (opc
) { IR_OPCODES
default: not_reached(); }
2891 template<class T
> void assert_opcode_extra_same(Opcode opc
) {
2892 #define O(opcode, dstinfo, srcinfo, flags) \
2895 OpHasExtraData<opcode>::value,opcode,T \
2896 >::doassert_same(); \
2898 switch (opc
) { IR_OPCODES
default: not_reached(); }
2902 size_t hashExtra(Opcode opc
, const IRExtraData
* data
);
2903 size_t stableHashExtra(Opcode opc
, const IRExtraData
* data
);
2904 bool equalsExtra(Opcode opc
, const IRExtraData
* a
, const IRExtraData
* b
);
2905 IRExtraData
* cloneExtra(Opcode opc
, IRExtraData
* data
, Arena
& a
);
2906 std::string
showExtra(Opcode opc
, const IRExtraData
* data
);
2908 //////////////////////////////////////////////////////////////////////