Compute ambient coeffects and write to coeffects local
[hiphop-php.git] / hphp / runtime / vm / hhbc.h
blobef6945dada52cf2bd4f3649f55e339970822a16b
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 <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"
33 namespace HPHP {
35 //////////////////////////////////////////////////////////////////////
37 struct Unit;
38 struct UnitEmitter;
39 struct Func;
40 struct FuncEmitter;
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.
47 struct LocalRange {
48 uint32_t first;
49 uint32_t count;
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.
65 struct IterArgs {
66 enum Flags : uint8_t {
67 None = 0,
68 // The base is stored in a local, and that local is unmodified in the loop.
69 BaseConst = (1 << 0),
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) {}
77 bool hasKey() const {
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;
87 int32_t iterId;
88 int32_t keyId;
89 int32_t valId;
90 Flags 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 {
105 None = 0,
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
118 HasInOut = (1 << 5),
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)
130 : numArgs(numArgs)
131 , numRets(numRets)
132 , flags(flags)
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);
143 uint32_t numArgs;
144 uint32_t numRets;
145 Flags flags;
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)
155 , context(context) {
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());
165 return FCallArgs(
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.
204 #define ARGTYPES \
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 */
226 enum ArgType {
227 #define ARGTYPE(name, type) name,
228 #define ARGTYPEVEC(name, type) name,
229 ARGTYPES
230 #undef ARGTYPE
231 #undef ARGTYPEVEC
234 union ArgUnion {
235 ArgUnion() : u_LA{0} {}
236 uint8_t bytes[0];
237 #define ARGTYPE(name, type) type u_##name;
238 #define ARGTYPEVEC(name, type) type u_##name;
239 ARGTYPES
240 #undef ARGTYPE
241 #undef ARGTYPEVEC
244 enum FlavorDesc {
245 NOV, // None
246 CV, // TypedValue
247 UV, // Uninit
248 CUV, // TypedValue, or Uninit argument
251 enum InstrFlags {
252 /* No flags. */
253 NF = 0x0,
255 /* Terminal: next instruction is not reachable via fall through or the callee
256 * returning control. This includes instructions like Throw that always throw
257 * exceptions. */
258 TF = 0x1,
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. */
265 CF = 0x2,
267 /* Shorthand for common combinations. */
268 CF_TF = (CF | TF),
271 #define INCDEC_OPS \
272 INCDEC_OP(PreInc) \
273 INCDEC_OP(PostInc) \
274 INCDEC_OP(PreDec) \
275 INCDEC_OP(PostDec) \
277 INCDEC_OP(PreIncO) \
278 INCDEC_OP(PostIncO) \
279 INCDEC_OP(PreDecO) \
280 INCDEC_OP(PostDecO) \
282 enum class IncDecOp : uint8_t {
283 #define INCDEC_OP(incDecOp) incDecOp,
284 INCDEC_OPS
285 #undef INCDEC_OP
288 inline bool isPre(IncDecOp op) {
289 return
290 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
291 op == IncDecOp::PreDec || op == IncDecOp::PreDecO;
294 inline bool isInc(IncDecOp op) {
295 return
296 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
297 op == IncDecOp::PostInc || op == IncDecOp::PostIncO;
300 inline bool isIncDecO(IncDecOp op) {
301 return
302 op == IncDecOp::PreIncO || op == IncDecOp::PreDecO ||
303 op == IncDecOp::PostIncO || op == IncDecOp::PostDecO;
306 #define ISTYPE_OPS \
307 ISTYPE_OP(Null) \
308 ISTYPE_OP(Bool) \
309 ISTYPE_OP(Int) \
310 ISTYPE_OP(Dbl) \
311 ISTYPE_OP(Str) \
312 ISTYPE_OP(Vec) \
313 ISTYPE_OP(Dict) \
314 ISTYPE_OP(Keyset) \
315 ISTYPE_OP(Obj) \
316 ISTYPE_OP(Scalar) \
317 ISTYPE_OP(ArrLike) \
318 ISTYPE_OP(LegacyArrLike) \
319 ISTYPE_OP(Res) \
320 ISTYPE_OP(VArray) \
321 ISTYPE_OP(DArray) \
322 ISTYPE_OP(ClsMeth) \
323 ISTYPE_OP(Func) \
324 ISTYPE_OP(PHPArr) \
325 ISTYPE_OP(Class)
327 enum class IsTypeOp : uint8_t {
328 #define ISTYPE_OP(op) op,
329 ISTYPE_OPS
330 #undef ISTYPE_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,
339 INITPROP_OPS
340 #undef INITPROP_OP
343 #define FATAL_OPS \
344 FATAL_OP(Runtime) \
345 FATAL_OP(Parse) \
346 FATAL_OP(RuntimeOmitFrame)
348 enum class FatalOp : uint8_t {
349 #define FATAL_OP(x) x,
350 FATAL_OPS
351 #undef FATAL_OP
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.
357 #define SETOP_OPS \
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,
376 SETOP_OPS
377 #undef SETOP_OP
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,
387 BARETHIS_OPS
388 #undef BARETHIS_OP
391 #define SILENCE_OPS \
392 SILENCE_OP(Start) \
393 SILENCE_OP(End)
395 enum class SilenceOp : uint8_t {
396 #define SILENCE_OP(x) x,
397 SILENCE_OPS
398 #undef SILENCE_OP
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,
408 OO_DECL_EXISTS_OPS
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,
418 OBJMETHOD_OPS
419 #undef OBJMETHOD_OP
422 #define SWITCH_KINDS \
423 KIND(Unbounded) \
424 KIND(Bounded)
426 enum class SwitchKind : uint8_t {
427 #define KIND(x) x,
428 SWITCH_KINDS
429 #undef KIND
432 #define M_OP_MODES \
433 MODE(None) \
434 MODE(Warn) \
435 MODE(Define) \
436 MODE(Unset) \
437 /* InOut mode restricts allowed bases to the
438 array like types. */ \
439 MODE(InOut)
441 enum class MOpMode : uint8_t {
442 #define MODE(name) name,
443 M_OP_MODES
444 #undef MODE
447 #define QUERY_M_OPS \
448 OP(CGet) \
449 OP(CGetQuiet) \
450 OP(Isset) \
451 OP(InOut)
453 enum class QueryMOp : uint8_t {
454 #define OP(name) name,
455 QUERY_M_OPS
456 #undef OP
459 #define SET_RANGE_OPS \
460 OP(Forward) \
461 OP(Reverse)
463 enum class SetRangeOp : uint8_t {
464 #define OP(name) name,
465 SET_RANGE_OPS
466 #undef OP
469 #define TYPE_STRUCT_RESOLVE_OPS \
470 OP(Resolve) \
471 OP(DontResolve)
473 enum class TypeStructResolveOp : uint8_t {
474 #define OP(name) name,
475 TYPE_STRUCT_RESOLVE_OPS
476 #undef OP
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,
485 CONT_CHECK_OPS
486 #undef CONT_CHECK_OP
489 #define CUD_OPS \
490 CUD_OP(IgnoreIter) \
491 CUD_OP(FreeIter)
493 enum class CudOp : uint8_t {
494 #define CUD_OP(name) name,
495 CUD_OPS
496 #undef CUD_OP
499 #define SPECIAL_CLS_REFS \
500 REF(Self) \
501 REF(Static) \
502 REF(Parent)
504 enum class SpecialClsRef : uint8_t {
505 #define REF(name) name,
506 SPECIAL_CLS_REFS
507 #undef REF
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
523 #define OPCODES \
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)), \
557 NOV, ONE(CV), NF) \
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) \
656 O(SetOpL, TWO(LA, \
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)), \
662 NOV, ONE(CV), NF) \
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), \
678 NOV, ONE(CV), NF) \
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)), \
693 NOV, ONE(CV), NF) \
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)), \
724 NOV, ONE(CV), NF) \
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)), \
762 ONE(CV), NOV, NF) \
763 O(Silence, TWO(LA,OA(SilenceOp)), \
764 NOV, NOV, NF) \
765 O(ThrowNonExhaustiveSwitch, NA, NOV, NOV, NF) \
766 O(RaiseClassStringConversionWarning, \
767 NA, NOV, NOV, NF) \
768 O(BaseGC, TWO(IVA, OA(MOpMode)), \
769 NOV, NOV, NF) \
770 O(BaseGL, TWO(LA, OA(MOpMode)), \
771 NOV, NOV, NF) \
772 O(BaseSC, FOUR(IVA, IVA, OA(MOpMode), OA(ReadOnlyOp)), \
773 NOV, NOV, NF) \
774 O(BaseL, TWO(NLA, OA(MOpMode)), \
775 NOV, NOV, NF) \
776 O(BaseC, TWO(IVA, OA(MOpMode)), \
777 NOV, NOV, NF) \
778 O(BaseH, NA, NOV, NOV, NF) \
779 O(Dim, TWO(OA(MOpMode), KA), \
780 NOV, NOV, NF) \
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), \
793 NOV, ONE(CV), CF) \
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,
799 OPCODES
800 #undef O
803 #define O(...) + 1
804 constexpr size_t Op_count = OPCODES;
805 #undef O
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;
812 OPCODES
813 #undef O
815 // These are comparable by default under MSVC.
816 #ifndef _MSC_VER
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);
825 #endif
827 constexpr bool isValidOpcode(Op op) {
828 return size_t(op) < Op_count;
831 inline MOpMode getQueryMOpMode(QueryMOp op) {
832 switch (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 \
842 O(FuncPrologue) \
843 O(TraceletGuard)
845 enum HighOp {
846 OpHighStart = Op_count-1,
847 #define O(name) Op##name,
848 HIGH_OPCODES
849 #undef O
852 struct StrVecItem {
853 Id str;
854 Offset dest;
857 struct ImmVector {
858 explicit ImmVector() : m_start(0) {}
860 explicit ImmVector(const uint8_t* start,
861 int32_t length,
862 int32_t numStack)
863 : m_length(length)
864 , m_numStack(numStack)
865 , m_start(start)
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 {
874 auto base = vec32();
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; }
893 private:
894 int32_t m_length;
895 int32_t 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);
909 PC skipCall(PC pc);
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
962 * subop.
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
974 // cannot jump
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,
1004 OPCODES
1005 #undef O
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) {
1025 return
1026 opcode == Op::Jmp ||
1027 opcode == Op::JmpNS ||
1028 opcode == Op::JmpZ ||
1029 opcode == Op::JmpNZ;
1032 constexpr bool isArrLikeConstructorOp(Op opcode) {
1033 return
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) {
1048 return
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) {
1057 return
1058 opcode == Op::Cmp ||
1059 opcode == Op::Eq ||
1060 opcode == Op::Neq ||
1061 opcode == Op::Gt ||
1062 opcode == Op::Gte ||
1063 opcode == Op::Lt ||
1064 opcode == Op::Lte ||
1065 opcode == Op::Same ||
1066 opcode == Op::NSame;
1069 constexpr bool isFCallClsMethod(Op opcode) {
1070 return
1071 opcode == OpFCallClsMethod ||
1072 opcode == OpFCallClsMethodD ||
1073 opcode == OpFCallClsMethodS ||
1074 opcode == OpFCallClsMethodSD;
1077 constexpr bool isFCallFunc(Op opcode) {
1078 return
1079 opcode == OpFCallFunc ||
1080 opcode == OpFCallFuncD;
1083 constexpr bool isFCallObjMethod(Op opcode) {
1084 return
1085 opcode == OpFCallObjMethod ||
1086 opcode == OpFCallObjMethodD;
1089 constexpr bool isFCall(Op opcode) {
1090 return
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) {
1119 switch (op) {
1120 case Op::BaseGC:
1121 case Op::BaseGL:
1122 case Op::BaseSC:
1123 case Op::BaseL:
1124 case Op::BaseC:
1125 case Op::BaseH:
1126 return true;
1128 default:
1129 return false;
1133 inline bool isMemberDimOp(Op op) {
1134 return op == Op::Dim;
1137 inline bool isMemberFinalOp(Op op) {
1138 switch (op) {
1139 case Op::QueryM:
1140 case Op::SetM:
1141 case Op::SetRangeM:
1142 case Op::IncDecM:
1143 case Op::SetOpM:
1144 case Op::UnsetM:
1145 return true;
1147 default:
1148 return false;
1152 inline bool isMemberOp(Op op) {
1153 return isMemberBaseOp(op) || isMemberDimOp(op) || isMemberFinalOp(op);
1156 inline MOpMode finalMemberOpMode(Op op) {
1157 switch(op){
1158 case Op::SetM:
1159 case Op::SetRangeM:
1160 case Op::IncDecM:
1161 case Op::SetOpM:
1162 return MOpMode::Define;
1163 case Op::UnsetM:
1164 return MOpMode::Unset;
1165 case Op::QueryM:
1166 return MOpMode::None;
1167 default:
1168 always_assert_flog(
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 //////////////////////////////////////////////////////////////////////
1190 namespace std {
1191 template<>
1192 struct hash<HPHP::Op> {
1193 size_t operator()(HPHP::Op op) const {
1194 return HPHP::hash_int64(size_t(op));
1199 //////////////////////////////////////////////////////////////////////