Equality
[hiphop-php.git] / hphp / runtime / vm / jit / extra-data.h
blob6b2916b8923f799df3f4e5534acd1ab2dee72a46
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #pragma once
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>
41 #include <algorithm>
42 #include <string>
44 namespace HPHP { namespace jit {
46 //////////////////////////////////////////////////////////////////////
49 * Some IRInstructions with compile-time-only constants may carry along extra
50 * data in the form of one of these structures.
52 * Note that this isn't really appropriate for compile-time constants that are
53 * actually representing user values (we want them to be visible to
54 * optimization passes, allocatable to registers, etc), just compile-time
55 * metadata.
57 * These types must:
59 * - Derive from IRExtraData (for overloading purposes).
60 * - Be arena-allocatable (no non-trivial destructors).
61 * - Either CopyConstructible, or implement a clone member function that
62 * takes an arena to clone to.
63 * - Implement an equals() member that indicates equality.
64 * - Implement a stableHash() method that is invariant across process
65 * restarts.
67 * In addition, extra data belonging to IRInstructions that may be hashed in
68 * IRInstrTables must:
70 * - Implement a hash() method.
72 * Finally, optionally they may implement a show() method for use in debug
73 * printouts.
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
79 * about the type.
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
95 * instructions.
97 * These are kept separate from the one-off IRExtraDatas to make it easier to
98 * find existing common parameters.
102 * Class pointer.
104 * Required to be non-null.
106 struct ClassData : IRExtraData {
107 explicit ClassData(const Class* cls)
108 : cls(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 {
118 return cls == o.cls;
121 size_t hash() const {
122 return pointer_hash<Class>()(cls);
125 size_t stableHash() const {
126 return cls->stableHash();
129 const Class* cls;
132 struct OptClassData : IRExtraData {
133 explicit OptClassData(const Class* cls)
134 : cls(cls)
137 std::string show() const {
138 return folly::to<std::string>(cls ? cls->name()->data() : "{null}");
141 bool equals(const OptClassData& o) const {
142 return cls == o.cls;
145 size_t hash() const {
146 return pointer_hash<Class>()(cls);
149 size_t stableHash() const {
150 return (cls ? cls->stableHash() : 0);
153 const Class* cls;
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(
164 const Class* cls,
165 bool suppress,
166 IRSPRelOffset offset,
167 uint32_t size,
168 bool isOrAsOp
170 : cls(cls)
171 , suppress(suppress)
172 , offset(offset)
173 , size(size)
174 , isOrAsOp(isOrAsOp)
177 std::string show() const {
178 return folly::sformat("{},{},{},{},{}",
179 cls ? cls->name()->data() : "nullptr",
180 suppress ? "suppress" : "no-suppress",
181 offset.offset,
182 size,
183 isOrAsOp);
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)
207 const Class* cls;
208 bool suppress;
209 IRSPRelOffset offset;
210 uint32_t size;
211 bool isOrAsOp;
215 * ExtendsClass.
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);
241 const Class* cls;
242 bool strictLikely;
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);
272 const Class* cls;
273 bool canOptimize;
277 * Class with method name.
279 struct ClsMethodData : IRExtraData {
280 ClsMethodData(const StringData* cls, const StringData* method,
281 const NamedEntity* ne, const Class* context)
282 : clsName(cls)
283 , methodName(method)
284 , namedEntity(ne)
285 , context(context)
288 std::string show() const {
289 return folly::sformat(
290 "{}::{} ({})",
291 clsName,
292 methodName,
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.
298 return
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);
347 Slot vtableIdx;
348 Slot methodIdx;
352 * Func
354 struct FuncData : IRExtraData {
355 explicit FuncData(const Func* f)
356 : 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();
371 const Func* func;
375 * Func with argument index.
377 struct FuncArgData : IRExtraData {
378 explicit FuncArgData(const Func* f, int64_t arg)
379 : func(f)
380 , argNum(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(
393 func->stableHash(),
394 std::hash<int64_t>()(argNum)
398 const Func* func;
399 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)
407 : func(f)
408 , argNum(arg)
409 , type(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(
422 func->stableHash(),
423 std::hash<int64_t>()(argNum),
424 type->hashStatic()
428 const Func* func;
429 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; }
442 bool noThrow;
446 * Local variable ID.
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); }
457 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;
474 uint32_t 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)
482 : index(index)
483 , key(key)
486 std::string show() const;
488 size_t stableHash() const {
489 return folly::hash::hash_combine(
490 std::hash<uint32_t>()(index),
491 key->hashStatic()
495 bool equals(const KeyedIndexData& o) const {
496 return index == o.index && key == o.key;
499 uint32_t index;
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 {
511 enum SizeHint {
512 Default,
513 SmallStatic
516 SizeHintData() : hint(SizeHint::Default) {}
517 explicit SizeHintData(SizeHint hint) : hint(hint) {}
519 std::string show() const {
520 switch (hint) {
521 case SizeHint::Default: return "Default";
522 case SizeHint::SmallStatic: return "SmallStatic";
524 not_reached();
527 size_t hash() const {
528 return stableHash();
531 size_t stableHash() const {
532 return std::hash<SizeHint>()(hint);
535 bool equals(const SizeHintData& o) const {
536 return hint == o.hint;
539 SizeHint hint;
543 * Iterator ID.
545 struct IterId : IRExtraData {
546 explicit IterId(uint32_t id)
547 : iterId(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); }
556 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;
585 IterArgs args;
588 struct IterTypeData : IRExtraData {
589 IterTypeData(uint32_t iterId, IterSpecialization type, ArrayLayout layout)
590 : iterId{iterId}
591 , type{type}
592 , layout{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 &&
613 layout == o.layout;
616 uint32_t iterId;
617 IterSpecialization type;
618 ArrayLayout layout;
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; }
630 int16_t offset;
634 * RDS handle.
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);
646 if (!sym) return 0;
647 return rds::symbol_stable_hash(*sym);
650 rds::Handle handle;
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));
677 bool cowCheck;
681 * Translation ID.
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;
698 TransID 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)
723 : irSPOff(irSPOff)
724 , bcSPOff(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
754 * Stack offset.
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); }
789 bool isAsync;
792 struct LdBindAddrData : IRExtraData {
793 explicit LdBindAddrData(SrcKey sk, SBInvOffset bcSPOff)
794 : sk(sk)
795 , bcSPOff(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;
811 SrcKey sk;
812 SBInvOffset bcSPOff;
815 struct LdSSwitchData : IRExtraData {
816 struct Elm {
817 const StringData* str;
818 SrcKey dest;
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));
832 return target;
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;
855 return true;
858 int64_t numCases;
859 const Elm* cases;
860 SrcKey defaultSk;
861 SBInvOffset bcSPOff;
864 struct ProfileSwitchData : IRExtraData {
865 ProfileSwitchData(rds::Handle handle, int32_t cases, int64_t base)
866 : handle(handle)
867 , cases(cases)
868 , base(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;
888 rds::Handle handle;
889 int32_t cases;
890 int64_t base;
893 struct JmpSwitchData : IRExtraData {
894 JmpSwitchData* clone(Arena& arena) const {
895 JmpSwitchData* sd = new (arena) JmpSwitchData;
896 sd->cases = cases;
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));
901 return sd;
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;
923 return true;
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;
947 int32_t valid;
950 struct ReqBindJmpData : IRExtraData {
951 explicit ReqBindJmpData(const SrcKey& target,
952 SBInvOffset invSPOff,
953 IRSPRelOffset irSPOff)
954 : target(target)
955 , invSPOff(invSPOff)
956 , irSPOff(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;
978 SrcKey target;
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>(
991 spOffset.offset
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>(
1012 callBCOff, ',',
1013 asyncEagerReturn
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;
1029 Offset callBCOff;
1030 bool asyncEagerReturn;
1033 struct CallBuiltinData : IRExtraData {
1034 explicit CallBuiltinData(IRSPRelOffset spOffset,
1035 folly::Optional<IRSPRelOffset> retSpOffset,
1036 const Func* callee)
1037 : spOffset(spOffset)
1038 , retSpOffset(retSpOffset)
1039 , callee{callee}
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 &&
1060 callee == o.callee;
1063 IRSPRelOffset spOffset; // offset from StkPtr to last passed arg
1064 folly::Optional<IRSPRelOffset> retSpOffset; // offset from StkPtr after a return
1065 const Func* callee;
1068 struct CallData : IRExtraData {
1069 explicit CallData(IRSPRelOffset spOffset,
1070 uint32_t numArgs,
1071 uint32_t numOut,
1072 Offset callOffset,
1073 uint16_t genericsBitmap,
1074 bool hasGenerics,
1075 bool hasUnpack,
1076 bool skipRepack,
1077 bool dynamicCall,
1078 bool asyncEagerReturn,
1079 bool formingRegion)
1080 : spOffset(spOffset)
1081 , numArgs(numArgs)
1082 , numOut(numOut)
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,
1096 hasGenerics
1097 ? folly::sformat(",hasGenerics({})", genericsBitmap)
1098 : std::string{},
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>()(
1119 hasGenerics << 5 |
1120 hasUnpack << 4 |
1121 skipRepack << 3 |
1122 dynamicCall << 2 |
1123 asyncEagerReturn << 1 |
1124 formingRegion
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
1145 uint32_t numArgs;
1146 uint32_t numOut; // number of values returned via stack from the callee
1147 Offset callOffset; // offset from func->base()
1148 uint16_t genericsBitmap;
1149 bool hasGenerics;
1150 bool hasUnpack;
1151 bool skipRepack;
1152 bool dynamicCall;
1153 bool asyncEagerReturn;
1154 bool formingRegion;
1157 struct RetCtrlData : IRExtraData {
1158 explicit RetCtrlData(IRSPRelOffset offset, bool suspendingResumed,
1159 AuxUnion aux)
1160 : offset(offset)
1161 , suspendingResumed(suspendingResumed)
1162 , aux(aux)
1165 std::string show() const {
1166 return folly::to<std::string>(
1167 offset.offset,
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.
1194 AuxUnion aux;
1198 * Name of a record
1200 struct RecNameData : IRExtraData {
1201 explicit RecNameData(const StringData* name)
1202 : recName(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)
1224 : clsName(cls)
1225 , cnsName(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)
1252 : cnsName(cns)
1253 , 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;
1270 Slot slot;
1274 * Name and handle of profiled class constant
1276 struct ProfileSubClsCnsData : IRExtraData {
1277 explicit ProfileSubClsCnsData(const StringData* cns, rds::Handle h)
1278 : cnsName(cns)
1279 , 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;
1299 rds::Handle handle;
1302 struct FuncNameData : IRExtraData {
1303 FuncNameData(const StringData* name, const Class* context)
1304 : name(name)
1305 , context(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(
1317 name->hash(),
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 {
1334 struct LocalType {
1335 explicit LocalType(uint32_t id = 0, Type type = TBottom)
1336 : id(id)
1337 , type(type)
1340 uint32_t id;
1341 Type type;
1344 explicit InterpOneData(IRSPRelOffset spOffset)
1345 : spOffset(spOffset)
1346 , nChangedLocals(0)
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(
1363 hash,
1364 changedLocals[i].id,
1365 changedLocals[i].type.stableHash()
1368 return hash;
1371 bool equals(const InterpOneData& o) const {
1372 if (spOffset == o.spOffset &&
1373 bcOff == o.bcOff &&
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;
1383 return true;
1385 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
1392 // current Marker.
1393 Offset bcOff;
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.
1402 Op opcode;
1404 uint32_t nChangedLocals;
1405 LocalType* changedLocals;
1407 bool smashesAllLocals;
1409 InterpOneData* clone(Arena& arena) const {
1410 auto* id = new (arena) InterpOneData(spOffset);
1411 id->bcOff = bcOff;
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);
1419 return id;
1422 std::string show() const {
1423 auto ret = folly::sformat(
1424 "{}: spOff:{}, bcOff:{}, popped:{}, pushed:{}",
1425 opcodeToName(opcode),
1426 spOffset.offset,
1427 bcOff,
1428 cellsPopped,
1429 cellsPushed
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);
1441 return ret;
1445 struct RBEntryData : IRExtraData {
1446 RBEntryData(Trace::RingBufferType t, SrcKey sk)
1447 : type(t)
1448 , sk(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;
1465 SrcKey sk;
1468 struct RBMsgData : IRExtraData {
1469 RBMsgData(Trace::RingBufferType t, const StringData* msg)
1470 : type(t)
1471 , msg(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";
1502 not_reached();
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(
1527 hash,
1528 keys[i]->hashStatic()
1531 return hash;
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;
1540 return true;
1543 IRSPRelOffset offset;
1544 uint32_t numKeys;
1545 StringData** keys;
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; }
1557 ArrayLayout 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]);
1576 return hash;
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;
1586 return true;
1589 ArrayLayout layout;
1590 IRSPRelOffset offset;
1591 uint32_t numSlots;
1592 Slot* slots;
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]);
1609 return hash;
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;
1618 return true;
1621 ArrayLayout layout;
1622 uint32_t numSlots;
1623 Slot* slots;
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;
1638 uint32_t size;
1641 struct InitPackedArrayLoopData : IRExtraData {
1642 explicit InitPackedArrayLoopData(IRSPRelOffset offset, uint32_t size)
1643 : offset(offset)
1644 , size(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;
1663 uint32_t size;
1666 struct CreateAAWHData : IRExtraData {
1667 explicit CreateAAWHData(uint32_t first, uint32_t count)
1668 : first(first)
1669 , count(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;
1687 uint32_t first;
1688 uint32_t count;
1691 struct CountWHNotDoneData : IRExtraData {
1692 explicit CountWHNotDoneData(uint32_t first, uint32_t count)
1693 : first(first)
1694 , count(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;
1712 uint32_t first;
1713 uint32_t count;
1716 struct NewKeysetArrayData : IRExtraData {
1717 explicit NewKeysetArrayData(IRSPRelOffset offset, uint32_t size)
1718 : offset(offset)
1719 , size(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;
1738 uint32_t size;
1741 struct MemoValueStaticData : IRExtraData {
1742 explicit MemoValueStaticData(const Func* func,
1743 folly::Optional<bool> asyncEager,
1744 bool loadAux)
1745 : func{func}
1746 , asyncEager{asyncEager}
1747 , loadAux{loadAux} {}
1748 std::string show() const {
1749 return folly::sformat(
1750 "{},{},{}",
1751 func->fullName()->toCppString(),
1752 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1753 loadAux
1757 size_t stableHash() const {
1758 return folly::hash::hash_combine(
1759 func->stableHash(),
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;
1769 const Func* func;
1770 folly::Optional<bool> asyncEager;
1771 bool loadAux;
1774 struct MemoValueInstanceData : IRExtraData {
1775 explicit MemoValueInstanceData(Slot slot,
1776 const Func* func,
1777 folly::Optional<bool> asyncEager,
1778 bool loadAux)
1779 : slot{slot}
1780 , func{func}
1781 , asyncEager{asyncEager}
1782 , loadAux{loadAux} {}
1783 std::string show() const {
1784 return folly::sformat(
1785 "{},{},{},{}",
1786 slot,
1787 func->fullName(),
1788 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1789 loadAux
1793 size_t stableHash() const {
1794 return folly::hash::hash_combine(
1795 std::hash<Slot>()(slot),
1796 func->stableHash(),
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;
1807 Slot slot;
1808 const Func* func;
1809 folly::Optional<bool> asyncEager;
1810 bool loadAux;
1813 struct MemoCacheStaticData : IRExtraData {
1814 MemoCacheStaticData(const Func* func,
1815 LocalRange keys,
1816 const bool* types,
1817 folly::Optional<bool> asyncEager,
1818 bool loadAux)
1819 : func{func}
1820 , keys{keys}
1821 , types{types}
1822 , asyncEager{asyncEager}
1823 , loadAux{loadAux} {}
1825 MemoCacheStaticData* clone(Arena& arena) const {
1826 auto p =
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);
1830 p->types = tmp;
1831 return p;
1834 std::string show() const {
1835 std::string ret;
1836 ret += folly::sformat("{},{}", func->fullName(), HPHP::show(keys));
1837 if (keys.count > 0) {
1838 ret += ",<";
1839 for (auto i = 0; i < keys.count; ++i) {
1840 if (i > 0) ret += ",";
1841 ret += folly::sformat("{}", types[i] ? "string" : "int");
1843 ret += ">";
1845 return ret;
1848 size_t stableHash() const {
1849 auto hash = folly::hash::hash_combine(
1850 func->stableHash(),
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(
1858 hash,
1859 std::hash<bool>()(types[i])
1862 return hash;
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;
1871 return true;
1873 return false;
1876 const Func* func;
1877 LocalRange keys;
1878 const bool* types;
1879 folly::Optional<bool> asyncEager;
1880 bool loadAux;
1883 struct MemoCacheInstanceData : IRExtraData {
1884 MemoCacheInstanceData(Slot slot,
1885 LocalRange keys,
1886 const bool* types,
1887 const Func* func,
1888 bool shared,
1889 folly::Optional<bool> asyncEager,
1890 bool loadAux)
1891 : slot{slot}
1892 , keys{keys}
1893 , types{types}
1894 , func{func}
1895 , shared{shared}
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);
1905 p->types = tmp;
1906 return p;
1909 std::string show() const {
1910 return folly::sformat(
1911 "{},{},{}<{}>,{}",
1912 slot,
1913 func->fullName(),
1914 HPHP::show(keys),
1915 [&]{
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>(",");
1920 }(),
1921 shared ? "shared" : "non-shared"
1925 size_t stableHash() const {
1926 auto hash = folly::hash::hash_combine(
1927 std::hash<Slot>()(slot),
1928 func->stableHash(),
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(
1937 hash,
1938 std::hash<bool>()(types[i])
1941 return hash;
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;
1951 return true;
1953 return false;
1956 Slot slot;
1957 LocalRange keys;
1958 const bool* types;
1959 const Func* func;
1960 bool shared;
1961 folly::Optional<bool> asyncEager;
1962 bool loadAux;
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;
1978 MOpMode 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;
1999 MOpMode mode;
2000 ReadOnlyOp 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 {
2012 return op == o.op;
2015 ReadOnlyOp op;
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 {
2027 return op == o.op;
2030 SetOpOp op;
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 {
2059 return op == o.op;
2062 IncDecOp op;
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;
2077 Offset 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,
2100 bool isAsync)
2101 : spOffset(spOffset)
2102 , callBCOffset(callBCOffset)
2103 , isAsync(isAsync)
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;
2126 bool isAsync;
2129 struct NewColData : IRExtraData {
2130 explicit NewColData(CollectionType itype)
2131 : type(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)
2151 : start(start)
2152 , end(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)
2175 : start(start)
2176 , count(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;
2193 uint32_t count;
2196 struct FuncEntryData : IRExtraData {
2197 FuncEntryData(const Func* func, uint32_t argc)
2198 : func(func)
2199 , argc(argc)
2202 std::string show() const {
2203 return folly::format(
2204 "{}({} args)",
2205 func->fullName(),
2206 argc
2207 ).str();
2210 size_t stableHash() const {
2211 return folly::hash::hash_combine(
2212 func->stableHash(),
2213 std::hash<uint32_t>()(argc)
2217 bool equals(const FuncEntryData& o) const {
2218 return func == o.func && argc == o.argc;
2221 const Func* func;
2222 uint32_t argc;
2225 struct CheckInOutsData : IRExtraData {
2226 CheckInOutsData(unsigned firstBit, uint64_t mask, uint64_t vals)
2227 : firstBit(safe_cast<int>(firstBit))
2228 , mask(mask)
2229 , vals(vals)
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;
2248 int firstBit;
2249 uint64_t mask;
2250 uint64_t vals;
2253 struct ProfileCallTargetData : IRExtraData {
2254 explicit ProfileCallTargetData(rds::Handle handle)
2255 : 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);
2264 if (!sym) return 0;
2265 return rds::symbol_stable_hash(*sym);
2268 bool equals(const ProfileCallTargetData& o) const {
2269 return handle == o.handle;
2272 rds::Handle handle;
2275 struct BeginInliningData : IRExtraData {
2276 BeginInliningData(IRSPRelOffset offset, const Func* func, int cost, int na)
2277 : spOffset(offset)
2278 , func(func)
2279 , cost(cost)
2280 , numArgs(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),
2291 func->stableHash(),
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;
2303 const Func* func;
2304 int cost;
2305 int numArgs;
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;
2319 int32_t paramId;
2322 struct ParamWithTCData : IRExtraData {
2323 explicit ParamWithTCData(int32_t paramId, const TypeConstraint* tc)
2324 : paramId(paramId)
2325 , tc(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 &&
2340 *tc == *o.tc;
2343 int32_t paramId;
2344 const TypeConstraint* tc;
2347 struct TypeConstraintData : IRExtraData {
2348 explicit TypeConstraintData(const TypeConstraint* tc)
2349 : tc(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)
2367 : tc(tc)
2368 , isSProp(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 &&
2384 *tc == *o.tc;
2387 union { const TypeConstraint* tc; int64_t tcIntVal; };
2388 bool isSProp;
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;
2406 bool 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;
2427 Reason 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)
2439 : offset{offset}
2440 , mode{mode}
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;
2472 CatchMode mode;
2473 FrameMode stublogue;
2474 Teardown teardown;
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;
2500 bool teardown;
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;
2525 int32_t 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;
2542 bool isCls;
2545 struct LoggingProfileData : IRExtraData {
2546 LoggingProfileData(bespoke::LoggingProfile* profile, bool isStatic)
2547 : profile(profile)
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)
2568 : profile(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 {
2591 switch (state) {
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;
2610 KeyState 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; }
2649 bool 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);
2669 X(LdLoc, LocalId);
2670 X(LdClsInitElem, IndexData);
2671 X(StClsInitElem, IndexData);
2672 X(StLoc, LocalId);
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);
2727 X(Call, CallData);
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,
2759 ClassData);
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);
2795 X(PropX, PropData);
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);
2880 #undef X
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) \
2915 case opcode: \
2916 AssertExtraTypes< \
2917 OpHasExtraData<opcode>::value,opcode,T \
2918 >::doassertx(); \
2919 break;
2920 switch (opc) { IR_OPCODES default: not_reached(); }
2921 #undef O
2924 template<class T> void assert_opcode_extra_same(Opcode opc) {
2925 #define O(opcode, dstinfo, srcinfo, flags) \
2926 case opcode: \
2927 AssertExtraTypes< \
2928 OpHasExtraData<opcode>::value,opcode,T \
2929 >::doassert_same(); \
2930 break;
2931 switch (opc) { IR_OPCODES default: not_reached(); }
2932 #undef O
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 //////////////////////////////////////////////////////////////////////