Optimize struct element initialization
[hiphop-php.git] / hphp / runtime / vm / jit / extra-data.h
blob17201b81055dd122df8313b1346143682245d412
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 AllocUninitBespokeStructData : IRExtraData {
1596 AllocUninitBespokeStructData(ArrayLayout layout,
1597 uint32_t numSlots,
1598 Slot* slots)
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]);
1611 return hash;
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;
1620 return true;
1623 ArrayLayout layout;
1624 uint32_t numSlots;
1625 Slot* slots;
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;
1640 uint32_t size;
1643 struct InitPackedArrayLoopData : IRExtraData {
1644 explicit InitPackedArrayLoopData(IRSPRelOffset offset, uint32_t size)
1645 : offset(offset)
1646 , size(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;
1665 uint32_t size;
1668 struct CreateAAWHData : IRExtraData {
1669 explicit CreateAAWHData(uint32_t first, uint32_t count)
1670 : first(first)
1671 , count(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;
1689 uint32_t first;
1690 uint32_t count;
1693 struct CountWHNotDoneData : IRExtraData {
1694 explicit CountWHNotDoneData(uint32_t first, uint32_t count)
1695 : first(first)
1696 , count(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;
1714 uint32_t first;
1715 uint32_t count;
1718 struct NewKeysetArrayData : IRExtraData {
1719 explicit NewKeysetArrayData(IRSPRelOffset offset, uint32_t size)
1720 : offset(offset)
1721 , size(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;
1740 uint32_t size;
1743 struct MemoValueStaticData : IRExtraData {
1744 explicit MemoValueStaticData(const Func* func,
1745 folly::Optional<bool> asyncEager,
1746 bool loadAux)
1747 : func{func}
1748 , asyncEager{asyncEager}
1749 , loadAux{loadAux} {}
1750 std::string show() const {
1751 return folly::sformat(
1752 "{},{},{}",
1753 func->fullName()->toCppString(),
1754 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1755 loadAux
1759 size_t stableHash() const {
1760 return folly::hash::hash_combine(
1761 func->stableHash(),
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;
1771 const Func* func;
1772 folly::Optional<bool> asyncEager;
1773 bool loadAux;
1776 struct MemoValueInstanceData : IRExtraData {
1777 explicit MemoValueInstanceData(Slot slot,
1778 const Func* func,
1779 folly::Optional<bool> asyncEager,
1780 bool loadAux)
1781 : slot{slot}
1782 , func{func}
1783 , asyncEager{asyncEager}
1784 , loadAux{loadAux} {}
1785 std::string show() const {
1786 return folly::sformat(
1787 "{},{},{},{}",
1788 slot,
1789 func->fullName(),
1790 asyncEager ? folly::to<std::string>(*asyncEager) : "-",
1791 loadAux
1795 size_t stableHash() const {
1796 return folly::hash::hash_combine(
1797 std::hash<Slot>()(slot),
1798 func->stableHash(),
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;
1809 Slot slot;
1810 const Func* func;
1811 folly::Optional<bool> asyncEager;
1812 bool loadAux;
1815 struct MemoCacheStaticData : IRExtraData {
1816 MemoCacheStaticData(const Func* func,
1817 LocalRange keys,
1818 const bool* types,
1819 folly::Optional<bool> asyncEager,
1820 bool loadAux)
1821 : func{func}
1822 , keys{keys}
1823 , types{types}
1824 , asyncEager{asyncEager}
1825 , loadAux{loadAux} {}
1827 MemoCacheStaticData* clone(Arena& arena) const {
1828 auto p =
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);
1832 p->types = tmp;
1833 return p;
1836 std::string show() const {
1837 std::string ret;
1838 ret += folly::sformat("{},{}", func->fullName(), HPHP::show(keys));
1839 if (keys.count > 0) {
1840 ret += ",<";
1841 for (auto i = 0; i < keys.count; ++i) {
1842 if (i > 0) ret += ",";
1843 ret += folly::sformat("{}", types[i] ? "string" : "int");
1845 ret += ">";
1847 return ret;
1850 size_t stableHash() const {
1851 auto hash = folly::hash::hash_combine(
1852 func->stableHash(),
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(
1860 hash,
1861 std::hash<bool>()(types[i])
1864 return hash;
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;
1873 return true;
1875 return false;
1878 const Func* func;
1879 LocalRange keys;
1880 const bool* types;
1881 folly::Optional<bool> asyncEager;
1882 bool loadAux;
1885 struct MemoCacheInstanceData : IRExtraData {
1886 MemoCacheInstanceData(Slot slot,
1887 LocalRange keys,
1888 const bool* types,
1889 const Func* func,
1890 bool shared,
1891 folly::Optional<bool> asyncEager,
1892 bool loadAux)
1893 : slot{slot}
1894 , keys{keys}
1895 , types{types}
1896 , func{func}
1897 , shared{shared}
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);
1907 p->types = tmp;
1908 return p;
1911 std::string show() const {
1912 return folly::sformat(
1913 "{},{},{}<{}>,{}",
1914 slot,
1915 func->fullName(),
1916 HPHP::show(keys),
1917 [&]{
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>(",");
1922 }(),
1923 shared ? "shared" : "non-shared"
1927 size_t stableHash() const {
1928 auto hash = folly::hash::hash_combine(
1929 std::hash<Slot>()(slot),
1930 func->stableHash(),
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(
1939 hash,
1940 std::hash<bool>()(types[i])
1943 return hash;
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;
1953 return true;
1955 return false;
1958 Slot slot;
1959 LocalRange keys;
1960 const bool* types;
1961 const Func* func;
1962 bool shared;
1963 folly::Optional<bool> asyncEager;
1964 bool loadAux;
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;
1980 MOpMode 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;
2001 MOpMode mode;
2002 ReadOnlyOp 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 {
2014 return op == o.op;
2017 ReadOnlyOp op;
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 {
2029 return op == o.op;
2032 SetOpOp op;
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 {
2061 return op == o.op;
2064 IncDecOp op;
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;
2079 Offset 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,
2102 bool isAsync)
2103 : spOffset(spOffset)
2104 , callBCOffset(callBCOffset)
2105 , isAsync(isAsync)
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;
2128 bool isAsync;
2131 struct NewColData : IRExtraData {
2132 explicit NewColData(CollectionType itype)
2133 : type(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)
2153 : start(start)
2154 , end(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)
2177 : func(func)
2178 , argc(argc)
2181 std::string show() const {
2182 return folly::format(
2183 "{}({} args)",
2184 func->fullName(),
2185 argc
2186 ).str();
2189 size_t stableHash() const {
2190 return folly::hash::hash_combine(
2191 func->stableHash(),
2192 std::hash<uint32_t>()(argc)
2196 bool equals(const FuncEntryData& o) const {
2197 return func == o.func && argc == o.argc;
2200 const Func* func;
2201 uint32_t argc;
2204 struct CheckInOutsData : IRExtraData {
2205 CheckInOutsData(unsigned firstBit, uint64_t mask, uint64_t vals)
2206 : firstBit(safe_cast<int>(firstBit))
2207 , mask(mask)
2208 , vals(vals)
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;
2227 int firstBit;
2228 uint64_t mask;
2229 uint64_t vals;
2232 struct ProfileCallTargetData : IRExtraData {
2233 explicit ProfileCallTargetData(rds::Handle handle)
2234 : 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);
2243 if (!sym) return 0;
2244 return rds::symbol_stable_hash(*sym);
2247 bool equals(const ProfileCallTargetData& o) const {
2248 return handle == o.handle;
2251 rds::Handle handle;
2254 struct BeginInliningData : IRExtraData {
2255 BeginInliningData(IRSPRelOffset offset, const Func* func, int cost, int na)
2256 : spOffset(offset)
2257 , func(func)
2258 , cost(cost)
2259 , numArgs(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),
2270 func->stableHash(),
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;
2282 const Func* func;
2283 int cost;
2284 int numArgs;
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;
2298 int32_t paramId;
2301 struct ParamWithTCData : IRExtraData {
2302 explicit ParamWithTCData(int32_t paramId, const TypeConstraint* tc)
2303 : paramId(paramId)
2304 , tc(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 &&
2319 *tc == *o.tc;
2322 int32_t paramId;
2323 const TypeConstraint* tc;
2326 struct TypeConstraintData : IRExtraData {
2327 explicit TypeConstraintData(const TypeConstraint* tc)
2328 : tc(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)
2346 : tc(tc)
2347 , isSProp(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 &&
2363 *tc == *o.tc;
2366 union { const TypeConstraint* tc; int64_t tcIntVal; };
2367 bool isSProp;
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;
2385 bool 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;
2406 Reason 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)
2418 : offset{offset}
2419 , mode{mode}
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;
2451 CatchMode mode;
2452 FrameMode stublogue;
2453 Teardown teardown;
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;
2479 bool teardown;
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;
2504 int32_t 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;
2521 bool isCls;
2524 struct LoggingProfileData : IRExtraData {
2525 LoggingProfileData(bespoke::LoggingProfile* profile, bool isStatic)
2526 : profile(profile)
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)
2547 : profile(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 {
2570 switch (state) {
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;
2589 KeyState 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);
2640 X(LdLoc, LocalId);
2641 X(LdClsInitElem, IndexData);
2642 X(StClsInitElem, IndexData);
2643 X(StLoc, LocalId);
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);
2697 X(Call, CallData);
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,
2729 ClassData);
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);
2765 X(PropX, PropData);
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);
2847 #undef X
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) \
2882 case opcode: \
2883 AssertExtraTypes< \
2884 OpHasExtraData<opcode>::value,opcode,T \
2885 >::doassertx(); \
2886 break;
2887 switch (opc) { IR_OPCODES default: not_reached(); }
2888 #undef O
2891 template<class T> void assert_opcode_extra_same(Opcode opc) {
2892 #define O(opcode, dstinfo, srcinfo, flags) \
2893 case opcode: \
2894 AssertExtraTypes< \
2895 OpHasExtraData<opcode>::value,opcode,T \
2896 >::doassert_same(); \
2897 break;
2898 switch (opc) { IR_OPCODES default: not_reached(); }
2899 #undef O
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 //////////////////////////////////////////////////////////////////////