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