2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
19 #include <type_traits>
21 #include <folly/Optional.h>
23 #include "hphp/runtime/base/repo-auth-type.h"
24 #include "hphp/runtime/base/typed-value.h"
25 #include "hphp/runtime/base/types.h"
26 #include "hphp/runtime/base/header-kind.h"
27 #include "hphp/runtime/vm/member-key.h"
28 #include "hphp/util/compact-vector.h"
29 #include "hphp/util/either.h"
30 #include "hphp/util/functional.h"
31 #include "hphp/util/hash-set.h"
35 //////////////////////////////////////////////////////////////////////
42 constexpr size_t kMaxHhbcImms
= 6;
44 // A contiguous range of locals. The count is the number of locals
45 // including the first. If the range is empty, count will be zero and
46 // first's value is arbitrary.
53 * Arguments to IterInit / IterNext opcodes.
54 * hhas format: <iterId> K:<keyId> V:<valId> (for key-value iters)
55 * <iterId> NK V:<valId> (for value-only iters)
56 * hhbc format: <uint8:flags> <iva:iterId> <iva:(keyId + 1)> <iva:valId>
58 * For value-only iters, keyId will be -1 (an invalid local ID); to take
59 * advantage of the one-byte encoding for IVA arguments, we add 1 to the key
60 * when encoding these args in the hhbc format.
62 * We don't accept flags from hhas because our flags require analyses that we
63 * currently only do in HHBBC.
66 enum Flags
: uint8_t {
68 // The base is stored in a local, and that local is unmodified in the loop.
72 static constexpr int32_t kNoKey
= -1;
74 explicit IterArgs(Flags flags
, int32_t iterId
, int32_t keyId
, int32_t valId
)
75 : iterId(iterId
), keyId(keyId
), valId(valId
), flags(flags
) {}
78 assertx(keyId
== kNoKey
|| keyId
>= 0);
79 return keyId
!= kNoKey
;
82 bool operator==(const IterArgs
& other
) const {
83 return iterId
== other
.iterId
&& keyId
== other
.keyId
&&
84 valId
== other
.valId
&& flags
== other
.flags
;
93 // Arguments to FCall opcodes.
94 // hhas format: <flags> <numArgs> <numRets> <inoutArgs> <asyncEagerOffset>
95 // hhbc format: <uint8:flags> ?<iva:numArgs> ?<iva:numRets>
96 // ?<boolvec:inoutArgs> ?<ba:asyncEagerOffset>
97 // flags = flags (hhas doesn't have HHBC-only flags)
98 // numArgs = flags >> kFirstNumArgsBit
99 // ? flags >> kFirstNumArgsBit - 1 : decode_iva()
100 // numRets = flags & HasInOut ? decode_iva() : 1
101 // inoutArgs = flags & EnforceInOut ? decode bool vec : nullptr
102 // asyncEagerOffset = flags & HasAEO ? decode_ba() : kInvalidOffset
103 struct FCallArgsBase
{
104 enum Flags
: uint8_t {
106 // Unpack remaining arguments from a varray passed by ...$args.
107 HasUnpack
= (1 << 0),
108 // Pass generics to the callee.
109 HasGenerics
= (1 << 1),
110 // Lock newly constructed object if unwinding the constructor call.
111 LockWhileUnwinding
= (1 << 2),
112 // Arguments are known to be compatible with prologue of the callee and
113 // do not need to be repacked.
114 SkipRepack
= (1 << 3),
115 // HHBC-only: Op should be resolved using an explicit context class
116 ExplicitContext
= (1 << 4),
117 // HHBC-only: is the number of returns provided? false => 1
119 // HHBC-only: should this FCall enforce argument inout-ness?
120 EnforceInOut
= (1 << 6),
121 // HHBC-only: is the async eager offset provided? false => kInvalidOffset
122 HasAsyncEagerOffset
= (1 << 7),
125 // Flags that are valid on FCallArgsBase::flags struct (i.e. non-HHBC-only).
126 static constexpr uint8_t kInternalFlags
=
127 HasUnpack
| HasGenerics
| LockWhileUnwinding
| SkipRepack
;
129 explicit FCallArgsBase(Flags flags
, uint32_t numArgs
, uint32_t numRets
)
134 assertx(!(flags
& ~kInternalFlags
));
136 bool hasUnpack() const { return flags
& Flags::HasUnpack
; }
137 bool hasGenerics() const { return flags
& Flags::HasGenerics
; }
138 bool lockWhileUnwinding() const { return flags
& Flags::LockWhileUnwinding
; }
139 bool skipRepack() const { return flags
& Flags::SkipRepack
; }
140 uint32_t numInputs() const {
141 return numArgs
+ (hasUnpack() ? 1 : 0) + (hasGenerics() ? 1 : 0);
148 struct FCallArgs
: FCallArgsBase
{
149 explicit FCallArgs(Flags flags
, uint32_t numArgs
, uint32_t numRets
,
150 const uint8_t* inoutArgs
, Offset asyncEagerOffset
,
151 const StringData
* context
)
152 : FCallArgsBase(flags
, numArgs
, numRets
)
153 , asyncEagerOffset(asyncEagerOffset
)
154 , inoutArgs(inoutArgs
)
156 assertx(IMPLIES(inoutArgs
!= nullptr, numArgs
!= 0));
158 bool enforceInOut() const { return inoutArgs
!= nullptr; }
159 bool isInOut(uint32_t i
) const {
160 assertx(enforceInOut());
161 return inoutArgs
[i
/ 8] & (1 << (i
% 8));
163 FCallArgs
withGenerics() const {
164 assertx(!hasGenerics());
166 static_cast<Flags
>(flags
| Flags::HasGenerics
),
167 numArgs
, numRets
, inoutArgs
, asyncEagerOffset
, context
);
169 Offset asyncEagerOffset
;
170 const uint8_t* inoutArgs
;
171 const StringData
* context
;
174 using PrintLocal
= std::function
<std::string(int32_t local
)>;
175 std::string
show(const IterArgs
&, PrintLocal
);
177 std::string
show(const LocalRange
&);
178 std::string
show(const FCallArgsBase
&, const uint8_t* inoutArgs
,
179 std::string asyncEagerLabel
, const StringData
* ctx
);
182 * Variable-size immediates are implemented as follows: To determine which size
183 * the immediate is, examine the first byte where the immediate is expected,
184 * and examine its high-order bit. If it is zero, it's a 1-byte immediate
185 * and the byte is the value. Otherwise, it's 4 bytes, and bits 8..31 must be
186 * logical-shifted to the right by one to get rid of the flag bit.
188 * The types in this macro for BLA, SLA, and VSA are meaningless since they
189 * are never read out of ArgUnion (they use ImmVector).
191 * There are several different local immediate types:
192 * - LA immediates are for bytecodes that only require the TypedValue* to
193 * perform their operation.
194 * - ILA immediates are used by bytecodes that need both the TypedValue* and
195 * the slot index to implement their operation. This could be used by
196 * opcodes that print an error message including this slot info.
197 * - NLA immediates are used by bytecodes that need both the TypedValue* and
198 * the name of the local to be implemented. This is commonly used for
199 * ops that raise warnings for undefined local uses.
201 * ArgTypes and their various decoding helpers should be kept in sync with the
202 * `hhx' bytecode inspection GDB command.
205 ARGTYPE(NA, void*) /* unused */ \
206 ARGTYPEVEC(BLA, Offset) /* Bytecode offset vector immediate */ \
207 ARGTYPEVEC(SLA, Id) /* String id/offset pair vector */ \
208 ARGTYPE(IVA, uint32_t) /* Variable size: 8 or 32-bit uint */ \
209 ARGTYPE(I64A, int64_t) /* 64-bit Integer */ \
210 ARGTYPE(LA, int32_t) /* Local: 8 or 32-bit int */ \
211 ARGTYPE(NLA, NamedLocal) /* Local w/ name: 2x 8 or 32-bit int */ \
212 ARGTYPE(ILA, int32_t) /* Local w/ ID: 8 or 32-bit int */ \
213 ARGTYPE(IA, int32_t) /* Iterator ID: 8 or 32-bit int */ \
214 ARGTYPE(DA, double) /* Double */ \
215 ARGTYPE(SA, Id) /* Static string ID */ \
216 ARGTYPE(AA, Id) /* Static array ID */ \
217 ARGTYPE(RATA, RepoAuthType) /* Statically inferred RepoAuthType */ \
218 ARGTYPE(BA, Offset) /* Bytecode offset */ \
219 ARGTYPE(OA, unsigned char) /* Sub-opcode, untyped */ \
220 ARGTYPE(KA, MemberKey) /* Member key: local, stack, int, str */ \
221 ARGTYPE(LAR, LocalRange) /* Contiguous range of locals */ \
222 ARGTYPE(ITA, IterArgs) /* Iterator arguments */ \
223 ARGTYPE(FCA, FCallArgs) /* FCall arguments */ \
224 ARGTYPEVEC(VSA, Id) /* Vector of static string IDs */
227 #define ARGTYPE(name, type) name,
228 #define ARGTYPEVEC(name, type) name,
235 ArgUnion() : u_LA
{0} {}
237 #define ARGTYPE(name, type) type u_##name;
238 #define ARGTYPEVEC(name, type) type u_##name;
248 CUV
, // TypedValue, or Uninit argument
255 /* Terminal: next instruction is not reachable via fall through or the callee
256 * returning control. This includes instructions like Throw that always throw
260 /* Control flow: If this instruction finishes executing (doesn't throw an
261 * exception), vmpc() is not guaranteed to point to the next instruction in
262 * the bytecode stream. This does not take VM reentry into account, as that
263 * operation is part of the instruction that performed the reentry, and does
264 * not affect what vmpc() is set to after the instruction completes. */
267 /* Shorthand for common combinations. */
278 INCDEC_OP(PostIncO) \
280 INCDEC_OP(PostDecO) \
282 enum class IncDecOp : uint8_t {
283 #define INCDEC_OP(incDecOp) incDecOp,
288 inline bool isPre(IncDecOp op
) {
290 op
== IncDecOp::PreInc
|| op
== IncDecOp::PreIncO
||
291 op
== IncDecOp::PreDec
|| op
== IncDecOp::PreDecO
;
294 inline bool isInc(IncDecOp op
) {
296 op
== IncDecOp::PreInc
|| op
== IncDecOp::PreIncO
||
297 op
== IncDecOp::PostInc
|| op
== IncDecOp::PostIncO
;
300 inline bool isIncDecO(IncDecOp op
) {
302 op
== IncDecOp::PreIncO
|| op
== IncDecOp::PreDecO
||
303 op
== IncDecOp::PostIncO
|| op
== IncDecOp::PostDecO
;
318 ISTYPE_OP(LegacyArrLike) \
327 enum class IsTypeOp
: uint8_t {
328 #define ISTYPE_OP(op) op,
333 #define INITPROP_OPS \
334 INITPROP_OP(Static) \
335 INITPROP_OP(NonStatic)
337 enum class InitPropOp
: uint8_t {
338 #define INITPROP_OP(op) op,
346 FATAL_OP(RuntimeOmitFrame)
348 enum class FatalOp
: uint8_t {
349 #define FATAL_OP(x) x,
354 // Each of the setop ops maps to a binary bytecode op. We have reasons
355 // for using distinct bitwise representations, though. This macro records
356 // their correspondence for mapping either direction.
358 SETOP_OP(PlusEqual, OpAdd) \
359 SETOP_OP(MinusEqual, OpSub) \
360 SETOP_OP(MulEqual, OpMul) \
361 SETOP_OP(ConcatEqual, OpConcat) \
362 SETOP_OP(DivEqual, OpDiv) \
363 SETOP_OP(PowEqual, OpPow) \
364 SETOP_OP(ModEqual, OpMod) \
365 SETOP_OP(AndEqual, OpBitAnd) \
366 SETOP_OP(OrEqual, OpBitOr) \
367 SETOP_OP(XorEqual, OpBitXor) \
368 SETOP_OP(SlEqual, OpShl) \
369 SETOP_OP(SrEqual, OpShr) \
370 SETOP_OP(PlusEqualO, OpAddO) \
371 SETOP_OP(MinusEqualO, OpSubO) \
372 SETOP_OP(MulEqualO, OpMulO) \
374 enum class SetOpOp : uint8_t {
375 #define SETOP_OP(setOpOp, bcOp) setOpOp,
380 #define BARETHIS_OPS \
381 BARETHIS_OP(Notice) \
382 BARETHIS_OP(NoNotice) \
383 BARETHIS_OP(NeverNull)
385 enum class BareThisOp
: uint8_t {
386 #define BARETHIS_OP(x) x,
391 #define SILENCE_OPS \
395 enum class SilenceOp
: uint8_t {
396 #define SILENCE_OP(x) x,
401 #define OO_DECL_EXISTS_OPS \
402 OO_DECL_EXISTS_OP(Class) \
403 OO_DECL_EXISTS_OP(Interface) \
404 OO_DECL_EXISTS_OP(Trait)
406 enum class OODeclExistsOp
: uint8_t {
407 #define OO_DECL_EXISTS_OP(x) x,
409 #undef OO_DECL_EXISTS_OP
412 #define OBJMETHOD_OPS \
413 OBJMETHOD_OP(NullThrows) \
414 OBJMETHOD_OP(NullSafe)
416 enum class ObjMethodOp
: uint8_t {
417 #define OBJMETHOD_OP(x) x,
422 #define SWITCH_KINDS \
426 enum class SwitchKind
: uint8_t {
437 /* InOut mode restricts allowed bases to the
438 array like types. */ \
441 enum class MOpMode
: uint8_t {
442 #define MODE(name) name,
447 #define QUERY_M_OPS \
453 enum class QueryMOp
: uint8_t {
454 #define OP(name) name,
459 #define SET_RANGE_OPS \
463 enum class SetRangeOp
: uint8_t {
464 #define OP(name) name,
469 #define TYPE_STRUCT_RESOLVE_OPS \
473 enum class TypeStructResolveOp
: uint8_t {
474 #define OP(name) name,
475 TYPE_STRUCT_RESOLVE_OPS
479 #define CONT_CHECK_OPS \
480 CONT_CHECK_OP(IgnoreStarted) \
481 CONT_CHECK_OP(CheckStarted)
483 enum class ContCheckOp
: uint8_t {
484 #define CONT_CHECK_OP(name) name,
493 enum class CudOp
: uint8_t {
494 #define CUD_OP(name) name,
499 #define SPECIAL_CLS_REFS \
504 enum class SpecialClsRef
: uint8_t {
505 #define REF(name) name,
510 #define IS_LOG_AS_DYNAMIC_CALL_OPS \
511 IS_LOG_AS_DYNAMIC_CALL_OP(LogAsDynamicCall) \
512 IS_LOG_AS_DYNAMIC_CALL_OP(DontLogAsDynamicCall)
514 enum class IsLogAsDynamicCallOp
: uint8_t {
515 #define IS_LOG_AS_DYNAMIC_CALL_OP(name) name,
516 IS_LOG_AS_DYNAMIC_CALL_OPS
517 #undef IS_LOG_AS_DYNAMIC_CALL_OP
520 constexpr uint32_t kMaxConcatN
= 4;
522 // name immediates inputs outputs flags
524 O(Nop, NA, NOV, NOV, NF) \
525 O(EntryNop, NA, NOV, NOV, NF) \
526 O(BreakTraceHint, NA, NOV, NOV, NF) \
527 O(PopC, NA, ONE(CV), NOV, NF) \
528 O(PopU, NA, ONE(UV), NOV, NF) \
529 O(PopU2, NA, TWO(CV,UV), ONE(CV), NF) \
530 O(PopL, ONE(LA), ONE(CV), NOV, NF) \
531 O(Dup, NA, ONE(CV), TWO(CV,CV), NF) \
532 O(CGetCUNop, NA, ONE(CUV), ONE(CV), NF) \
533 O(UGetCUNop, NA, ONE(CUV), ONE(UV), NF) \
534 O(Null, NA, NOV, ONE(CV), NF) \
535 O(NullUninit, NA, NOV, ONE(UV), NF) \
536 O(True, NA, NOV, ONE(CV), NF) \
537 O(False, NA, NOV, ONE(CV), NF) \
538 O(FuncCred, NA, NOV, ONE(CV), NF) \
539 O(Int, ONE(I64A), NOV, ONE(CV), NF) \
540 O(Double, ONE(DA), NOV, ONE(CV), NF) \
541 O(String, ONE(SA), NOV, ONE(CV), NF) \
542 O(Array, ONE(AA), NOV, ONE(CV), NF) \
543 O(Dict, ONE(AA), NOV, ONE(CV), NF) \
544 O(Keyset, ONE(AA), NOV, ONE(CV), NF) \
545 O(Vec, ONE(AA), NOV, ONE(CV), NF) \
546 O(NewDictArray, ONE(IVA), NOV, ONE(CV), NF) \
547 O(NewStructDArray, ONE(VSA), SMANY, ONE(CV), NF) \
548 O(NewStructDict, ONE(VSA), SMANY, ONE(CV), NF) \
549 O(NewVec, ONE(IVA), CMANY, ONE(CV), NF) \
550 O(NewKeysetArray, ONE(IVA), CMANY, ONE(CV), NF) \
551 O(NewVArray, ONE(IVA), CMANY, ONE(CV), NF) \
552 O(NewDArray, ONE(IVA), NOV, ONE(CV), NF) \
553 O(NewRecord, TWO(SA,VSA), SMANY, ONE(CV), NF) \
554 O(AddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
555 O(AddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
556 O(NewCol, ONE(OA(CollectionType)), \
558 O(NewPair, NA, TWO(CV,CV), ONE(CV), NF) \
559 O(ColFromArray, ONE(OA(CollectionType)), \
560 ONE(CV), ONE(CV), NF) \
561 O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
562 O(ClsCns, ONE(SA), ONE(CV), ONE(CV), NF) \
563 O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
564 O(ClsCnsL, ONE(LA), ONE(CV), ONE(CV), NF) \
565 O(ClassName, NA, ONE(CV), ONE(CV), NF) \
566 O(File, NA, NOV, ONE(CV), NF) \
567 O(Dir, NA, NOV, ONE(CV), NF) \
568 O(Method, NA, NOV, ONE(CV), NF) \
569 O(Concat, NA, TWO(CV,CV), ONE(CV), NF) \
570 O(ConcatN, ONE(IVA), CMANY, ONE(CV), NF) \
571 O(Add, NA, TWO(CV,CV), ONE(CV), NF) \
572 O(Sub, NA, TWO(CV,CV), ONE(CV), NF) \
573 O(Mul, NA, TWO(CV,CV), ONE(CV), NF) \
574 O(AddO, NA, TWO(CV,CV), ONE(CV), NF) \
575 O(SubO, NA, TWO(CV,CV), ONE(CV), NF) \
576 O(MulO, NA, TWO(CV,CV), ONE(CV), NF) \
577 O(Div, NA, TWO(CV,CV), ONE(CV), NF) \
578 O(Mod, NA, TWO(CV,CV), ONE(CV), NF) \
579 O(Pow, NA, TWO(CV,CV), ONE(CV), NF) \
580 O(Not, NA, ONE(CV), ONE(CV), NF) \
581 O(Same, NA, TWO(CV,CV), ONE(CV), NF) \
582 O(NSame, NA, TWO(CV,CV), ONE(CV), NF) \
583 O(Eq, NA, TWO(CV,CV), ONE(CV), NF) \
584 O(Neq, NA, TWO(CV,CV), ONE(CV), NF) \
585 O(Lt, NA, TWO(CV,CV), ONE(CV), NF) \
586 O(Lte, NA, TWO(CV,CV), ONE(CV), NF) \
587 O(Gt, NA, TWO(CV,CV), ONE(CV), NF) \
588 O(Gte, NA, TWO(CV,CV), ONE(CV), NF) \
589 O(Cmp, NA, TWO(CV,CV), ONE(CV), NF) \
590 O(BitAnd, NA, TWO(CV,CV), ONE(CV), NF) \
591 O(BitOr, NA, TWO(CV,CV), ONE(CV), NF) \
592 O(BitXor, NA, TWO(CV,CV), ONE(CV), NF) \
593 O(BitNot, NA, ONE(CV), ONE(CV), NF) \
594 O(Shl, NA, TWO(CV,CV), ONE(CV), NF) \
595 O(Shr, NA, TWO(CV,CV), ONE(CV), NF) \
596 O(CastBool, NA, ONE(CV), ONE(CV), NF) \
597 O(CastInt, NA, ONE(CV), ONE(CV), NF) \
598 O(CastDouble, NA, ONE(CV), ONE(CV), NF) \
599 O(CastString, NA, ONE(CV), ONE(CV), NF) \
600 O(CastDict, NA, ONE(CV), ONE(CV), NF) \
601 O(CastKeyset, NA, ONE(CV), ONE(CV), NF) \
602 O(CastVec, NA, ONE(CV), ONE(CV), NF) \
603 O(CastVArray, NA, ONE(CV), ONE(CV), NF) \
604 O(CastDArray, NA, ONE(CV), ONE(CV), NF) \
605 O(DblAsBits, NA, ONE(CV), ONE(CV), NF) \
606 O(InstanceOf, NA, TWO(CV,CV), ONE(CV), NF) \
607 O(InstanceOfD, ONE(SA), ONE(CV), ONE(CV), NF) \
608 O(IsLateBoundCls, NA, ONE(CV), ONE(CV), NF) \
609 O(IsTypeStructC, ONE(OA(TypeStructResolveOp)), \
610 TWO(CV,CV), ONE(CV), NF) \
611 O(ThrowAsTypeStructException, \
612 NA, TWO(CV,CV), NOV, TF) \
613 O(CombineAndResolveTypeStruct, \
614 ONE(IVA), CMANY, ONE(CV), NF) \
615 O(Select, NA, THREE(CV,CV,CV), ONE(CV), NF) \
616 O(Print, NA, ONE(CV), ONE(CV), NF) \
617 O(Clone, NA, ONE(CV), ONE(CV), NF) \
618 O(Exit, NA, ONE(CV), ONE(CV), TF) \
619 O(Fatal, ONE(OA(FatalOp)), ONE(CV), NOV, TF) \
620 O(Jmp, ONE(BA), NOV, NOV, CF_TF) \
621 O(JmpNS, ONE(BA), NOV, NOV, CF_TF) \
622 O(JmpZ, ONE(BA), ONE(CV), NOV, CF) \
623 O(JmpNZ, ONE(BA), ONE(CV), NOV, CF) \
624 O(Switch, THREE(OA(SwitchKind),I64A,BLA), \
625 ONE(CV), NOV, CF_TF) \
626 O(SSwitch, ONE(SLA), ONE(CV), NOV, CF_TF) \
627 O(RetC, NA, ONE(CV), NOV, CF_TF) \
628 O(RetM, ONE(IVA), CMANY, NOV, CF_TF) \
629 O(RetCSuspended, NA, ONE(CV), NOV, CF_TF) \
630 O(Throw, NA, ONE(CV), NOV, CF_TF) \
631 O(CGetL, ONE(NLA), NOV, ONE(CV), NF) \
632 O(CGetQuietL, ONE(LA), NOV, ONE(CV), NF) \
633 O(CUGetL, ONE(LA), NOV, ONE(CUV), NF) \
634 O(CGetL2, ONE(NLA), ONE(CV), TWO(CV,CV), NF) \
635 O(PushL, ONE(LA), NOV, ONE(CV), NF) \
636 O(CGetG, NA, ONE(CV), ONE(CV), NF) \
637 O(CGetS, ONE(OA(ReadOnlyOp)), \
638 TWO(CV,CV), ONE(CV), NF) \
639 O(ClassGetC, NA, ONE(CV), ONE(CV), NF) \
640 O(ClassGetTS, NA, ONE(CV), TWO(CV,CV), NF) \
641 O(GetMemoKeyL, ONE(NLA), NOV, ONE(CV), NF) \
642 O(AKExists, NA, TWO(CV,CV), ONE(CV), NF) \
643 O(IssetL, ONE(LA), NOV, ONE(CV), NF) \
644 O(IssetG, NA, ONE(CV), ONE(CV), NF) \
645 O(IssetS, NA, TWO(CV,CV), ONE(CV), NF) \
646 O(IsUnsetL, ONE(LA), NOV, ONE(CV), NF) \
647 O(IsTypeC, ONE(OA(IsTypeOp)),ONE(CV), ONE(CV), NF) \
648 O(IsTypeL, TWO(NLA, \
649 OA(IsTypeOp)), NOV, ONE(CV), NF) \
650 O(AssertRATL, TWO(ILA,RATA), NOV, NOV, NF) \
651 O(AssertRATStk, TWO(IVA,RATA), NOV, NOV, NF) \
652 O(SetL, ONE(LA), ONE(CV), ONE(CV), NF) \
653 O(SetG, NA, TWO(CV,CV), ONE(CV), NF) \
654 O(SetS, ONE(OA(ReadOnlyOp)), \
655 THREE(CV,CV,CV), ONE(CV), NF) \
657 OA(SetOpOp)), ONE(CV), ONE(CV), NF) \
658 O(SetOpG, ONE(OA(SetOpOp)), TWO(CV,CV), ONE(CV), NF) \
659 O(SetOpS, TWO(OA(SetOpOp), OA(ReadOnlyOp)), \
660 THREE(CV,CV,CV), ONE(CV), NF) \
661 O(IncDecL, TWO(NLA, OA(IncDecOp)), \
663 O(IncDecG, ONE(OA(IncDecOp)),ONE(CV), ONE(CV), NF) \
664 O(IncDecS, TWO(OA(IncDecOp), OA(ReadOnlyOp)), \
665 TWO(CV,CV), ONE(CV), NF) \
666 O(UnsetL, ONE(LA), NOV, NOV, NF) \
667 O(UnsetG, NA, ONE(CV), NOV, NF) \
669 O(ResolveFunc, ONE(SA), NOV, ONE(CV), NF) \
670 O(ResolveMethCaller,ONE(SA), NOV, ONE(CV), NF) \
671 O(ResolveRFunc, ONE(SA), ONE(CV), ONE(CV), NF) \
672 O(ResolveObjMethod,NA, TWO(CV,CV), ONE(CV), NF) \
673 O(ResolveClsMethod,ONE(SA), ONE(CV), ONE(CV), NF) \
674 O(ResolveClsMethodD, \
675 TWO(SA,SA), NOV, ONE(CV), NF) \
676 O(ResolveClsMethodS, \
677 TWO(OA(SpecialClsRef),SA), \
679 O(ResolveRClsMethod, \
680 ONE(SA), TWO(CV,CV), ONE(CV), NF) \
681 O(ResolveRClsMethodD, \
682 TWO(SA,SA), ONE(CV), ONE(CV), NF) \
683 O(ResolveRClsMethodS, \
684 TWO(OA(SpecialClsRef),SA), \
685 ONE(CV), ONE(CV), NF) \
686 O(ResolveClass, ONE(SA), NOV, ONE(CV), NF) \
687 O(LazyClass, ONE(SA), NOV, ONE(CV), NF) \
688 O(NewObj, NA, ONE(CV), ONE(CV), NF) \
689 O(NewObjR, NA, TWO(CV,CV), ONE(CV), NF) \
690 O(NewObjD, ONE(SA), NOV, ONE(CV), NF) \
691 O(NewObjRD, ONE(SA), ONE(CV), ONE(CV), NF) \
692 O(NewObjS, ONE(OA(SpecialClsRef)), \
694 O(LockObj, NA, ONE(CV), ONE(CV), NF) \
695 O(FCallClsMethod, THREE(FCA,SA,OA(IsLogAsDynamicCallOp)), \
696 FCALL(2, 0), FCALL, CF) \
697 O(FCallClsMethodD, FOUR(FCA,SA,SA,SA), \
698 FCALL(0, 0), FCALL, CF) \
699 O(FCallClsMethodS, THREE(FCA,SA,OA(SpecialClsRef)), \
700 FCALL(1, 0), FCALL, CF) \
701 O(FCallClsMethodSD,FOUR(FCA,SA,OA(SpecialClsRef),SA), \
702 FCALL(0, 0), FCALL, CF) \
703 O(FCallCtor, TWO(FCA,SA), FCALL(0, 1), FCALL, CF) \
704 O(FCallFunc, ONE(FCA), FCALL(1, 0), FCALL, CF) \
705 O(FCallFuncD, TWO(FCA,SA), FCALL(0, 0), FCALL, CF) \
706 O(FCallObjMethod, THREE(FCA,SA,OA(ObjMethodOp)), \
707 FCALL(1, 1), FCALL, CF) \
708 O(FCallObjMethodD, FOUR(FCA,SA,OA(ObjMethodOp),SA), \
709 FCALL(0, 1), FCALL, CF) \
710 O(IterInit, TWO(ITA,BA), ONE(CV), NOV, CF) \
711 O(LIterInit, THREE(ITA,LA,BA), NOV, NOV, CF) \
712 O(IterNext, TWO(ITA,BA), NOV, NOV, CF) \
713 O(LIterNext, THREE(ITA,LA,BA), NOV, NOV, CF) \
714 O(IterFree, ONE(IA), NOV, NOV, NF) \
715 O(LIterFree, TWO(IA,LA), NOV, NOV, NF) \
716 O(Incl, NA, ONE(CV), ONE(CV), CF) \
717 O(InclOnce, NA, ONE(CV), ONE(CV), CF) \
718 O(Req, NA, ONE(CV), ONE(CV), CF) \
719 O(ReqOnce, NA, ONE(CV), ONE(CV), CF) \
720 O(ReqDoc, NA, ONE(CV), ONE(CV), CF) \
721 O(Eval, NA, ONE(CV), ONE(CV), CF) \
722 O(This, NA, NOV, ONE(CV), NF) \
723 O(BareThis, ONE(OA(BareThisOp)), \
725 O(CheckThis, NA, NOV, NOV, NF) \
726 O(ChainFaults, NA, TWO(CV,CV), ONE(CV), NF) \
727 O(OODeclExists, ONE(OA(OODeclExistsOp)), \
728 TWO(CV,CV), ONE(CV), NF) \
729 O(VerifyOutType, ONE(IVA), ONE(CV), ONE(CV), NF) \
730 O(VerifyParamType, ONE(ILA), NOV, NOV, NF) \
731 O(VerifyParamTypeTS, ONE(ILA), ONE(CV), NOV, NF) \
732 O(VerifyRetTypeC, NA, ONE(CV), ONE(CV), NF) \
733 O(VerifyRetTypeTS, NA, TWO(CV,CV), ONE(CV), NF) \
734 O(VerifyRetNonNullC, NA, ONE(CV), ONE(CV), NF) \
735 O(Self, NA, NOV, ONE(CV), NF) \
736 O(Parent, NA, NOV, ONE(CV), NF) \
737 O(LateBoundCls, NA, NOV, ONE(CV), NF) \
738 O(RecordReifiedGeneric, NA, ONE(CV), ONE(CV), NF) \
739 O(CheckReifiedGenericMismatch, NA, ONE(CV), NOV, NF) \
740 O(NativeImpl, NA, NOV, NOV, CF_TF) \
741 O(CreateCl, TWO(IVA,IVA), CUMANY, ONE(CV), NF) \
742 O(CreateCont, NA, NOV, ONE(CV), CF) \
743 O(ContEnter, NA, ONE(CV), ONE(CV), CF) \
744 O(ContRaise, NA, ONE(CV), ONE(CV), CF) \
745 O(Yield, NA, ONE(CV), ONE(CV), CF) \
746 O(YieldK, NA, TWO(CV,CV), ONE(CV), CF) \
747 O(ContCheck, ONE(OA(ContCheckOp)), NOV, NOV, NF) \
748 O(ContValid, NA, NOV, ONE(CV), NF) \
749 O(ContKey, NA, NOV, ONE(CV), NF) \
750 O(ContCurrent, NA, NOV, ONE(CV), NF) \
751 O(ContGetReturn, NA, NOV, ONE(CV), NF) \
752 O(WHResult, NA, ONE(CV), ONE(CV), NF) \
753 O(Await, NA, ONE(CV), ONE(CV), CF) \
754 O(AwaitAll, ONE(LAR), NOV, ONE(CV), CF) \
755 O(Idx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
756 O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
757 O(ArrayMarkLegacy, NA, TWO(CV,CV), ONE(CV), NF) \
758 O(ArrayUnmarkLegacy, NA, TWO(CV,CV), ONE(CV), NF) \
759 O(TagProvenanceHere, NA, TWO(CV,CV), ONE(CV), NF) \
760 O(CheckProp, ONE(SA), NOV, ONE(CV), NF) \
761 O(InitProp, THREE(SA, OA(InitPropOp), OA(ReadOnlyOp)), \
763 O(Silence, TWO(LA,OA(SilenceOp)), \
765 O(ThrowNonExhaustiveSwitch, NA, NOV, NOV, NF) \
766 O(RaiseClassStringConversionWarning, \
768 O(BaseGC, TWO(IVA, OA(MOpMode)), \
770 O(BaseGL, TWO(LA, OA(MOpMode)), \
772 O(BaseSC, FOUR(IVA, IVA, OA(MOpMode), OA(ReadOnlyOp)), \
774 O(BaseL, TWO(NLA, OA(MOpMode)), \
776 O(BaseC, TWO(IVA, OA(MOpMode)), \
778 O(BaseH, NA, NOV, NOV, NF) \
779 O(Dim, TWO(OA(MOpMode), KA), \
781 O(QueryM, THREE(IVA, OA(QueryMOp), KA), \
782 MFINAL, ONE(CV), NF) \
783 O(SetM, TWO(IVA, KA), C_MFINAL(1), ONE(CV), NF) \
784 O(SetRangeM, FOUR(IVA, IVA, OA(SetRangeOp), OA(ReadOnlyOp)), \
785 C_MFINAL(3), NOV, NF) \
786 O(IncDecM, THREE(IVA, OA(IncDecOp), KA), \
787 MFINAL, ONE(CV), NF) \
788 O(SetOpM, THREE(IVA, OA(SetOpOp), KA), \
789 C_MFINAL(1), ONE(CV), NF) \
790 O(UnsetM, TWO(IVA, KA), MFINAL, NOV, NF) \
791 O(MemoGet, TWO(BA, LAR), NOV, ONE(CV), CF) \
792 O(MemoGetEager, THREE(BA, BA, LAR), \
794 O(MemoSet, ONE(LAR), ONE(CV), ONE(CV), NF) \
795 O(MemoSetEager, ONE(LAR), ONE(CV), ONE(CV), NF)
797 enum class Op
: uint16_t {
798 #define O(name, ...) name,
804 constexpr size_t Op_count
= OPCODES
;
808 * Also put Op* in the enclosing namespace, to avoid having to change every
809 * existing usage site of the enum values.
811 #define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
815 // These are comparable by default under MSVC.
817 inline constexpr bool operator<(Op a
, Op b
) { return size_t(a
) < size_t(b
); }
818 inline constexpr bool operator>(Op a
, Op b
) { return size_t(a
) > size_t(b
); }
819 inline constexpr bool operator<=(Op a
, Op b
) {
820 return size_t(a
) <= size_t(b
);
822 inline constexpr bool operator>=(Op a
, Op b
) {
823 return size_t(a
) >= size_t(b
);
827 constexpr bool isValidOpcode(Op op
) {
828 return size_t(op
) < Op_count
;
831 inline MOpMode
getQueryMOpMode(QueryMOp op
) {
833 case QueryMOp::CGet
: return MOpMode::Warn
;
834 case QueryMOp::CGetQuiet
:
835 case QueryMOp::Isset
: return MOpMode::None
;
836 case QueryMOp::InOut
: return MOpMode::InOut
;
838 always_assert(false);
841 #define HIGH_OPCODES \
846 OpHighStart
= Op_count
-1,
847 #define O(name) Op##name,
858 explicit ImmVector() : m_start(0) {}
860 explicit ImmVector(const uint8_t* start
,
864 , m_numStack(numStack
)
868 bool isValid() const { return m_start
!= 0; }
870 const int32_t* vec32() const {
871 return reinterpret_cast<const int32_t*>(m_start
);
873 folly::Range
<const int32_t*> range32() const {
875 return {base
, base
+ size()};
877 const StrVecItem
* strvec() const {
878 return reinterpret_cast<const StrVecItem
*>(m_start
);
882 * Returns the length of the immediate vector in bytes (for M
883 * vectors) or elements (for switch vectors)
885 int32_t size() const { return m_length
; }
888 * Returns the number of elements on the execution stack that this vector
889 * will need to access.
891 int numStackValues() const { return m_numStack
; }
896 const uint8_t* m_start
;
899 // Must be an opcode that actually has an ImmVector.
900 ImmVector
getImmVector(PC opcode
);
902 // Some decoding helper functions.
903 int numImmediates(Op opcode
);
904 ArgType
immType(Op opcode
, int idx
);
905 bool hasImmVector(Op opcode
);
906 int instrLen(PC opcode
);
907 int numSuccs(PC opcode
);
912 * The returned struct has normalized variable-sized immediates. u must be
913 * provided unless you know that the immediate is not of type KA.
915 * Don't use with RATA immediates.
917 ArgUnion
getImm(PC opcode
, int idx
, const Unit
* u
= nullptr);
919 // Don't use this with variable-sized immediates!
920 ArgUnion
* getImmPtr(PC opcode
, int idx
);
922 void staticStreamer(const TypedValue
* tv
, std::string
& out
);
924 std::string
instrToString(PC it
, Either
<const Func
*, const FuncEmitter
*> f
);
925 void staticArrayStreamer(const ArrayData
*, std::string
&);
928 * Convert subopcodes or opcodes into strings.
930 const char* opcodeToName(Op op
);
931 const char* subopToName(InitPropOp
);
932 const char* subopToName(IsTypeOp
);
933 const char* subopToName(FatalOp
);
934 const char* subopToName(CollectionType
);
935 const char* subopToName(SetOpOp
);
936 const char* subopToName(IncDecOp
);
937 const char* subopToName(BareThisOp
);
938 const char* subopToName(SilenceOp
);
939 const char* subopToName(OODeclExistsOp
);
940 const char* subopToName(ObjMethodOp
);
941 const char* subopToName(SwitchKind
);
942 const char* subopToName(MOpMode
);
943 const char* subopToName(QueryMOp
);
944 const char* subopToName(SetRangeOp
);
945 const char* subopToName(TypeStructResolveOp
);
946 const char* subopToName(ContCheckOp
);
947 const char* subopToName(CudOp
);
948 const char* subopToName(SpecialClsRef
);
949 const char* subopToName(IsLogAsDynamicCallOp
);
950 const char* subopToName(ReadOnlyOp
);
953 * Returns true iff the given SubOp is in the valid range for its type.
955 template<class Subop
>
956 bool subopValid(Subop
);
959 * Try to parse a string into a subop name of a given type.
961 * Returns folly::none if the string is not recognized as that type of
964 template<class SubOpType
>
965 folly::Optional
<SubOpType
> nameToSubop(const char*);
967 using OffsetList
= std::vector
<Offset
>;
969 // Returns a jump offsets relative to the instruction, or nothing if
970 // the instruction cannot jump.
971 OffsetList
instrJumpOffsets(PC instr
);
973 // returns absolute address of targets, or nothing if instruction
975 OffsetList
instrJumpTargets(PC instrs
, Offset pos
);
978 * Returns the set of bytecode offsets for the instructions that may
979 * be executed immediately after opc.
981 using OffsetSet
= hphp_hash_set
<Offset
>;
982 OffsetSet
instrSuccOffsets(PC opc
, const Func
* func
);
985 * Some CF instructions can be treated as non-CF instructions for most analysis
986 * purposes, such as bytecode verification and HHBBC. These instructions change
987 * vmpc() to point somewhere in a different function, but the runtime
988 * guarantees that if excution ever returns to the original frame, it will be
989 * at the location immediately following the instruction in question. This
990 * creates the illusion that the instruction fell through normally to the
991 * instruction after it, within the context of its execution frame.
993 * The canonical example of this behavior are the FCall* instructions, so we use
994 * "non-call control flow" to describe the set of CF instruction that do not
995 * exhibit this behavior. This function returns true if `opcode' is a non-call
996 * control flow instruction.
998 bool instrIsNonCallControlFlow(Op opcode
);
1000 bool instrAllowsFallThru(Op opcode
);
1002 constexpr InstrFlags instrFlagsData
[] = {
1003 #define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
1008 constexpr InstrFlags
instrFlags(Op opcode
) {
1009 return instrFlagsData
[size_t(opcode
)];
1012 constexpr bool instrIsControlFlow(Op opcode
) {
1013 return (instrFlags(opcode
) & CF
) != 0;
1016 constexpr bool isUnconditionalJmp(Op opcode
) {
1017 return opcode
== Op::Jmp
|| opcode
== Op::JmpNS
;
1020 constexpr bool isConditionalJmp(Op opcode
) {
1021 return opcode
== Op::JmpZ
|| opcode
== Op::JmpNZ
;
1024 constexpr bool isJmp(Op opcode
) {
1026 opcode
== Op::Jmp
||
1027 opcode
== Op::JmpNS
||
1028 opcode
== Op::JmpZ
||
1029 opcode
== Op::JmpNZ
;
1032 constexpr bool isArrLikeConstructorOp(Op opcode
) {
1034 opcode
== Op::Array
||
1035 opcode
== Op::Dict
||
1036 opcode
== Op::Keyset
||
1037 opcode
== Op::Vec
||
1038 opcode
== Op::NewDictArray
||
1039 opcode
== Op::NewStructDArray
||
1040 opcode
== Op::NewStructDict
||
1041 opcode
== Op::NewVec
||
1042 opcode
== Op::NewKeysetArray
||
1043 opcode
== Op::NewVArray
||
1044 opcode
== Op::NewDArray
;
1047 constexpr bool isArrLikeCastOp(Op opcode
) {
1049 opcode
== Op::CastVArray
||
1050 opcode
== Op::CastDArray
||
1051 opcode
== Op::CastVec
||
1052 opcode
== Op::CastDict
||
1053 opcode
== Op::CastKeyset
;
1056 constexpr bool isComparisonOp(Op opcode
) {
1058 opcode
== Op::Cmp
||
1060 opcode
== Op::Neq
||
1062 opcode
== Op::Gte
||
1064 opcode
== Op::Lte
||
1065 opcode
== Op::Same
||
1066 opcode
== Op::NSame
;
1069 constexpr bool isFCallClsMethod(Op opcode
) {
1071 opcode
== OpFCallClsMethod
||
1072 opcode
== OpFCallClsMethodD
||
1073 opcode
== OpFCallClsMethodS
||
1074 opcode
== OpFCallClsMethodSD
;
1077 constexpr bool isFCallFunc(Op opcode
) {
1079 opcode
== OpFCallFunc
||
1080 opcode
== OpFCallFuncD
;
1083 constexpr bool isFCallObjMethod(Op opcode
) {
1085 opcode
== OpFCallObjMethod
||
1086 opcode
== OpFCallObjMethodD
;
1089 constexpr bool isFCall(Op opcode
) {
1091 opcode
== OpFCallCtor
||
1092 isFCallClsMethod(opcode
) ||
1093 isFCallFunc(opcode
) ||
1094 isFCallObjMethod(opcode
);
1097 constexpr bool isRet(Op op
) {
1098 return op
== OpRetC
|| op
== OpRetCSuspended
|| op
== OpRetM
;
1101 constexpr bool isReturnish(Op op
) {
1102 return isRet(op
) || op
== Op::NativeImpl
;
1105 constexpr bool isSwitch(Op op
) {
1106 return op
== OpSwitch
|| op
== OpSSwitch
;
1109 constexpr bool isTypeAssert(Op op
) {
1110 return op
== OpAssertRATL
|| op
== OpAssertRATStk
;
1113 constexpr bool isIteratorOp(Op op
) {
1114 return op
== OpIterInit
|| op
== Op::LIterInit
||
1115 op
== OpIterNext
|| op
== Op::LIterNext
;
1118 inline bool isMemberBaseOp(Op op
) {
1133 inline bool isMemberDimOp(Op op
) {
1134 return op
== Op::Dim
;
1137 inline bool isMemberFinalOp(Op op
) {
1152 inline bool isMemberOp(Op op
) {
1153 return isMemberBaseOp(op
) || isMemberDimOp(op
) || isMemberFinalOp(op
);
1156 inline MOpMode
finalMemberOpMode(Op op
) {
1162 return MOpMode::Define
;
1164 return MOpMode::Unset
;
1166 return MOpMode::None
;
1169 false, "Unknown final member op {}", opcodeToName(op
)
1174 // true if the opcode body can set pc=0 to halt the interpreter.
1175 constexpr bool instrCanHalt(Op op
) {
1176 return op
== OpRetC
|| op
== OpNativeImpl
||
1177 op
== OpAwait
|| op
== OpAwaitAll
|| op
== OpCreateCont
||
1178 op
== OpYield
|| op
== OpYieldK
|| op
== OpRetM
||
1179 op
== OpRetCSuspended
;
1182 int instrNumPops(PC opcode
);
1183 int instrNumPushes(PC opcode
);
1184 FlavorDesc
instrInputFlavor(PC op
, uint32_t idx
);
1188 //////////////////////////////////////////////////////////////////////
1192 struct hash
<HPHP::Op
> {
1193 size_t operator()(HPHP::Op op
) const {
1194 return HPHP::hash_int64(size_t(op
));
1199 //////////////////////////////////////////////////////////////////////