Move func_num_args() to an opcode
[hiphop-php.git] / hphp / runtime / vm / hhbc.h
blob4ff80c518524f9220f9151c8acabaa1ca24113f9
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_HHBC_H_
18 #define incl_HPHP_VM_HHBC_H_
20 #include <type_traits>
22 #include <folly/Optional.h>
24 #include "hphp/runtime/base/repo-auth-type.h"
25 #include "hphp/runtime/base/typed-value.h"
26 #include "hphp/runtime/base/types.h"
27 #include "hphp/runtime/base/header-kind.h"
28 #include "hphp/runtime/vm/member-key.h"
29 #include "hphp/util/compact-vector.h"
30 #include "hphp/util/either.h"
31 #include "hphp/util/functional.h"
32 #include "hphp/util/hash-set.h"
34 namespace HPHP {
36 //////////////////////////////////////////////////////////////////////
38 struct Unit;
39 struct UnitEmitter;
40 struct Func;
42 constexpr size_t kMaxHhbcImms = 5;
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 FCall opcodes.
54 // hhas format: <flags> <numArgs> <numRets> <byRefs> <asyncEagerOffset>
55 // hhbc format: <uint8:flags> ?<iva:numArgs> ?<iva:numRets>
56 // ?<boolvec:byRefs> ?<ba:asyncEagerOffset>
57 // flags = flags (hhas doesn't have HHBC-only flags)
58 // numArgs = flags >> kFirstNumArgsBit
59 // ? flags >> kFirstNumArgsBit - 1 : decode_iva()
60 // numRets = flags & HasInOut ? decode_iva() : 1
61 // byRefs = flags & EnforceReffiness ? decode bool vec : nullptr
62 // asyncEagerOffset = flags & HasAEO ? decode_ba() : kInvalidOffset
63 struct FCallArgsBase {
64 enum Flags : uint8_t {
65 None = 0,
66 // Unpack remaining arguments from a varray passed by ...$args.
67 HasUnpack = (1 << 0),
68 // Callee is known to support async eager return.
69 SupportsAsyncEagerReturn = (1 << 1),
70 // HHBC-only: is the number of returns provided? false => 1
71 HasInOut = (1 << 2),
72 // HHBC-only: should this FCall enforce argument reffiness?
73 EnforceReffiness = (1 << 3),
74 // HHBC-only: is the async eager offset provided? false => kInvalidOffset
75 HasAsyncEagerOffset = (1 << 4),
76 // HHBC-only: the remaining space is used for number of arguments
77 NumArgsStart = (1 << 5),
80 // Flags that are valid on FCallArgsBase::flags struct (i.e. non-HHBC-only).
81 static constexpr uint8_t kInternalFlags =
82 HasUnpack | SupportsAsyncEagerReturn;
83 // The first (lowest) bit of numArgs.
84 static constexpr uint8_t kFirstNumArgsBit = 5;
86 explicit FCallArgsBase(Flags flags, uint32_t numArgs, uint32_t numRets)
87 : numArgs(numArgs), numRets(numRets), flags(flags) {
88 assertx(!(flags & ~kInternalFlags));
90 bool hasUnpack() const { return flags & Flags::HasUnpack; }
91 bool supportsAsyncEagerReturn() const {
92 return flags & Flags::SupportsAsyncEagerReturn;
94 uint32_t numArgs;
95 uint32_t numRets;
96 Flags flags;
99 struct FCallArgs : FCallArgsBase {
100 explicit FCallArgs(Flags flags, uint32_t numArgs, uint32_t numRets,
101 const uint8_t* byRefs, Offset asyncEagerOffset)
102 : FCallArgsBase(flags, numArgs, numRets)
103 , asyncEagerOffset(asyncEagerOffset)
104 , byRefs(byRefs) {
105 assertx(IMPLIES(byRefs != nullptr, numArgs != 0));
106 assertx(IMPLIES(asyncEagerOffset == kInvalidOffset,
107 !supportsAsyncEagerReturn()));
109 bool enforceReffiness() const { return byRefs != nullptr; }
110 bool byRef(uint32_t i) const {
111 assertx(enforceReffiness());
112 return byRefs[i / 8] & (1 << (i % 8));
114 Offset asyncEagerOffset;
115 const uint8_t* byRefs;
118 static_assert(1 << FCallArgs::kFirstNumArgsBit == FCallArgs::NumArgsStart, "");
120 std::string show(const LocalRange&);
121 std::string show(const FCallArgsBase&, const uint8_t* byRefs,
122 std::string asyncEagerLabel);
125 * Variable-size immediates are implemented as follows: To determine which size
126 * the immediate is, examine the first byte where the immediate is expected,
127 * and examine its high-order bit. If it is zero, it's a 1-byte immediate
128 * and the byte is the value. Otherwise, it's 4 bytes, and bits 8..31 must be
129 * logical-shifted to the right by one to get rid of the flag bit.
131 * The types in this macro for BLA, SLA, ILA, I32LA and VSA are meaningless
132 * since they are never read out of ArgUnion (they use ImmVector).
134 * ArgTypes and their various decoding helpers should be kept in sync with the
135 * `hhx' bytecode inspection GDB command.
137 #define ARGTYPES \
138 ARGTYPE(NA, void*) /* unused */ \
139 ARGTYPEVEC(BLA, Offset) /* Bytecode offset vector immediate */ \
140 ARGTYPEVEC(SLA, Id) /* String id/offset pair vector */ \
141 ARGTYPEVEC(ILA, Id) /* IterKind/IterId pair vector */ \
142 ARGTYPEVEC(I32LA,uint32_t) /* Vector of 32-bit uint */ \
143 ARGTYPE(IVA, uint32_t) /* Variable size: 8 or 32-bit uint */ \
144 ARGTYPE(I64A, int64_t) /* 64-bit Integer */ \
145 ARGTYPE(LA, int32_t) /* Local variable ID: 8 or 32-bit int */ \
146 ARGTYPE(IA, int32_t) /* Iterator ID: 8 or 32-bit int */ \
147 ARGTYPE(CAR, int32_t) /* Class-ref slot (read): 8 or 32-bit int */ \
148 ARGTYPE(CAW, int32_t) /* Class-ref slot (write): 8 or 32-bit int */ \
149 ARGTYPE(DA, double) /* Double */ \
150 ARGTYPE(SA, Id) /* Static string ID */ \
151 ARGTYPE(AA, Id) /* Static array ID */ \
152 ARGTYPE(RATA, RepoAuthType) /* Statically inferred RepoAuthType */ \
153 ARGTYPE(BA, Offset) /* Bytecode offset */ \
154 ARGTYPE(OA, unsigned char) /* Sub-opcode, untyped */ \
155 ARGTYPE(KA, MemberKey) /* Member key: local, stack, int, str */ \
156 ARGTYPE(LAR, LocalRange) /* Contiguous range of locals */ \
157 ARGTYPE(FCA, FCallArgs) /* FCall arguments */ \
158 ARGTYPEVEC(VSA, Id) /* Vector of static string IDs */
160 enum ArgType {
161 #define ARGTYPE(name, type) name,
162 #define ARGTYPEVEC(name, type) name,
163 ARGTYPES
164 #undef ARGTYPE
165 #undef ARGTYPEVEC
168 union ArgUnion {
169 ArgUnion() : u_LA{0} {}
170 uint8_t bytes[0];
171 #define ARGTYPE(name, type) type u_##name;
172 #define ARGTYPEVEC(name, type) type u_##name;
173 ARGTYPES
174 #undef ARGTYPE
175 #undef ARGTYPEVEC
178 const Offset InvalidAbsoluteOffset = -1;
180 enum FlavorDesc {
181 NOV, // None
182 CV, // Cell
183 VV, // Var
184 UV, // Uninit
185 CVV, // Cell or Var argument
186 CUV, // Cell, or Uninit argument
187 CVUV, // Cell, Var, or Uninit argument
190 enum InstrFlags {
191 /* No flags. */
192 NF = 0x0,
194 /* Terminal: next instruction is not reachable via fall through or the callee
195 * returning control. This includes instructions like Throw and Unwind that
196 * always throw exceptions. */
197 TF = 0x1,
199 /* Control flow: If this instruction finishes executing (doesn't throw an
200 * exception), vmpc() is not guaranteed to point to the next instruction in
201 * the bytecode stream. This does not take VM reentry into account, as that
202 * operation is part of the instruction that performed the reentry, and does
203 * not affect what vmpc() is set to after the instruction completes. */
204 CF = 0x2,
206 /* Instruction pushes an FPI */
207 PF = 0x4,
209 /* Shorthand for common combinations. */
210 CF_TF = (CF | TF),
213 #define INCDEC_OPS \
214 INCDEC_OP(PreInc) \
215 INCDEC_OP(PostInc) \
216 INCDEC_OP(PreDec) \
217 INCDEC_OP(PostDec) \
219 INCDEC_OP(PreIncO) \
220 INCDEC_OP(PostIncO) \
221 INCDEC_OP(PreDecO) \
222 INCDEC_OP(PostDecO) \
224 enum class IncDecOp : uint8_t {
225 #define INCDEC_OP(incDecOp) incDecOp,
226 INCDEC_OPS
227 #undef INCDEC_OP
230 inline bool isPre(IncDecOp op) {
231 return
232 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
233 op == IncDecOp::PreDec || op == IncDecOp::PreDecO;
236 inline bool isInc(IncDecOp op) {
237 return
238 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
239 op == IncDecOp::PostInc || op == IncDecOp::PostIncO;
242 inline bool isIncDecO(IncDecOp op) {
243 return
244 op == IncDecOp::PreIncO || op == IncDecOp::PreDecO ||
245 op == IncDecOp::PostIncO || op == IncDecOp::PostDecO;
248 #define ISTYPE_OPS \
249 ISTYPE_OP(Null) \
250 ISTYPE_OP(Bool) \
251 ISTYPE_OP(Int) \
252 ISTYPE_OP(Dbl) \
253 ISTYPE_OP(Str) \
254 ISTYPE_OP(Arr) \
255 ISTYPE_OP(Vec) \
256 ISTYPE_OP(Dict) \
257 ISTYPE_OP(Keyset) \
258 ISTYPE_OP(Obj) \
259 ISTYPE_OP(Scalar) \
260 ISTYPE_OP(ArrLike) \
261 ISTYPE_OP(Res) \
262 ISTYPE_OP(VArray) \
263 ISTYPE_OP(DArray) \
264 ISTYPE_OP(ClsMeth)
266 enum class IsTypeOp : uint8_t {
267 #define ISTYPE_OP(op) op,
268 ISTYPE_OPS
269 #undef ISTYPE_OP
272 #define INITPROP_OPS \
273 INITPROP_OP(Static) \
274 INITPROP_OP(NonStatic)
276 enum class InitPropOp : uint8_t {
277 #define INITPROP_OP(op) op,
278 INITPROP_OPS
279 #undef INITPROP_OP
282 enum IterKind {
283 KindOfIter = 0,
284 KindOfLIter = 1,
287 #define FATAL_OPS \
288 FATAL_OP(Runtime) \
289 FATAL_OP(Parse) \
290 FATAL_OP(RuntimeOmitFrame)
292 enum class FatalOp : uint8_t {
293 #define FATAL_OP(x) x,
294 FATAL_OPS
295 #undef FATAL_OP
298 // Each of the setop ops maps to a binary bytecode op. We have reasons
299 // for using distinct bitwise representations, though. This macro records
300 // their correspondence for mapping either direction.
301 #define SETOP_OPS \
302 SETOP_OP(PlusEqual, OpAdd) \
303 SETOP_OP(MinusEqual, OpSub) \
304 SETOP_OP(MulEqual, OpMul) \
305 SETOP_OP(ConcatEqual, OpConcat) \
306 SETOP_OP(DivEqual, OpDiv) \
307 SETOP_OP(PowEqual, OpPow) \
308 SETOP_OP(ModEqual, OpMod) \
309 SETOP_OP(AndEqual, OpBitAnd) \
310 SETOP_OP(OrEqual, OpBitOr) \
311 SETOP_OP(XorEqual, OpBitXor) \
312 SETOP_OP(SlEqual, OpShl) \
313 SETOP_OP(SrEqual, OpShr) \
314 SETOP_OP(PlusEqualO, OpAddO) \
315 SETOP_OP(MinusEqualO, OpSubO) \
316 SETOP_OP(MulEqualO, OpMulO) \
318 enum class SetOpOp : uint8_t {
319 #define SETOP_OP(setOpOp, bcOp) setOpOp,
320 SETOP_OPS
321 #undef SETOP_OP
324 #define BARETHIS_OPS \
325 BARETHIS_OP(Notice) \
326 BARETHIS_OP(NoNotice) \
327 BARETHIS_OP(NeverNull)
329 enum class BareThisOp : uint8_t {
330 #define BARETHIS_OP(x) x,
331 BARETHIS_OPS
332 #undef BARETHIS_OP
335 #define SILENCE_OPS \
336 SILENCE_OP(Start) \
337 SILENCE_OP(End)
339 enum class SilenceOp : uint8_t {
340 #define SILENCE_OP(x) x,
341 SILENCE_OPS
342 #undef SILENCE_OP
345 #define OO_DECL_EXISTS_OPS \
346 OO_DECL_EXISTS_OP(Class) \
347 OO_DECL_EXISTS_OP(Interface) \
348 OO_DECL_EXISTS_OP(Trait)
350 enum class OODeclExistsOp : uint8_t {
351 #define OO_DECL_EXISTS_OP(x) x,
352 OO_DECL_EXISTS_OPS
353 #undef OO_DECL_EXISTS_OP
356 #define OBJMETHOD_OPS \
357 OBJMETHOD_OP(NullThrows) \
358 OBJMETHOD_OP(NullSafe)
360 enum class ObjMethodOp : uint8_t {
361 #define OBJMETHOD_OP(x) x,
362 OBJMETHOD_OPS
363 #undef OBJMETHOD_OP
366 #define SWITCH_KINDS \
367 KIND(Unbounded) \
368 KIND(Bounded)
370 enum class SwitchKind : uint8_t {
371 #define KIND(x) x,
372 SWITCH_KINDS
373 #undef KIND
376 #define M_OP_MODES \
377 MODE(None) \
378 MODE(Warn) \
379 MODE(Define) \
380 MODE(Unset) \
381 /* InOut mode restricts allowed bases to the
382 array like types. */ \
383 MODE(InOut)
385 enum class MOpMode : uint8_t {
386 #define MODE(name) name,
387 M_OP_MODES
388 #undef MODE
391 #define QUERY_M_OPS \
392 OP(CGet) \
393 OP(CGetQuiet) \
394 OP(Isset) \
395 OP(Empty) \
396 OP(InOut)
398 enum class QueryMOp : uint8_t {
399 #define OP(name) name,
400 QUERY_M_OPS
401 #undef OP
404 #define SET_RANGE_OPS \
405 OP(Forward) \
406 OP(Reverse)
408 enum class SetRangeOp : uint8_t {
409 #define OP(name) name,
410 SET_RANGE_OPS
411 #undef OP
414 #define TYPE_STRUCT_RESOLVE_OPS \
415 OP(Resolve) \
416 OP(DontResolve)
418 enum class TypeStructResolveOp : uint8_t {
419 #define OP(name) name,
420 TYPE_STRUCT_RESOLVE_OPS
421 #undef OP
424 #define HAS_GENERICS_OPS \
425 OP(NoGenerics) \
426 OP(HasGenerics) \
427 OP(MaybeGenerics)
429 enum class HasGenericsOp : uint8_t {
430 #define OP(name) name,
431 HAS_GENERICS_OPS
432 #undef OP
435 #define CONT_CHECK_OPS \
436 CONT_CHECK_OP(IgnoreStarted) \
437 CONT_CHECK_OP(CheckStarted)
439 enum class ContCheckOp : uint8_t {
440 #define CONT_CHECK_OP(name) name,
441 CONT_CHECK_OPS
442 #undef CONT_CHECK_OP
445 #define CUD_OPS \
446 CUD_OP(IgnoreIter) \
447 CUD_OP(FreeIter)
449 enum class CudOp : uint8_t {
450 #define CUD_OP(name) name,
451 CUD_OPS
452 #undef CUD_OP
455 #define SPECIAL_CLS_REFS \
456 REF(Self) \
457 REF(Static) \
458 REF(Parent)
460 enum class SpecialClsRef : uint8_t {
461 #define REF(name) name,
462 SPECIAL_CLS_REFS
463 #undef REF
466 constexpr uint32_t kMaxConcatN = 4;
468 // name immediates inputs outputs flags
469 #define OPCODES \
470 O(Nop, NA, NOV, NOV, NF) \
471 O(EntryNop, NA, NOV, NOV, NF) \
472 O(BreakTraceHint, NA, NOV, NOV, NF) \
473 O(DiscardClsRef, ONE(CAR), NOV, NOV, NF) \
474 O(PopC, NA, ONE(CV), NOV, NF) \
475 O(PopV, NA, ONE(VV), NOV, NF) \
476 O(PopU, NA, ONE(UV), NOV, NF) \
477 O(PopU2, NA, TWO(CV,UV), ONE(CV), NF) \
478 O(PopL, ONE(LA), ONE(CV), NOV, NF) \
479 O(Dup, NA, ONE(CV), TWO(CV,CV), NF) \
480 O(Box, NA, ONE(CV), ONE(VV), NF) \
481 O(Unbox, NA, ONE(VV), ONE(CV), NF) \
482 O(CGetCUNop, NA, ONE(CUV), ONE(CV), NF) \
483 O(UGetCUNop, NA, ONE(CUV), ONE(UV), NF) \
484 O(Null, NA, NOV, ONE(CV), NF) \
485 O(NullUninit, NA, NOV, ONE(UV), NF) \
486 O(True, NA, NOV, ONE(CV), NF) \
487 O(False, NA, NOV, ONE(CV), NF) \
488 O(Int, ONE(I64A), NOV, ONE(CV), NF) \
489 O(Double, ONE(DA), NOV, ONE(CV), NF) \
490 O(String, ONE(SA), NOV, ONE(CV), NF) \
491 O(Array, ONE(AA), NOV, ONE(CV), NF) \
492 O(Dict, ONE(AA), NOV, ONE(CV), NF) \
493 O(Keyset, ONE(AA), NOV, ONE(CV), NF) \
494 O(Vec, ONE(AA), NOV, ONE(CV), NF) \
495 O(NewArray, ONE(IVA), NOV, ONE(CV), NF) \
496 O(NewMixedArray, ONE(IVA), NOV, ONE(CV), NF) \
497 O(NewDictArray, ONE(IVA), NOV, ONE(CV), NF) \
498 O(NewLikeArrayL, TWO(LA,IVA), NOV, ONE(CV), NF) \
499 O(NewPackedArray, ONE(IVA), CMANY, ONE(CV), NF) \
500 O(NewStructArray, ONE(VSA), SMANY, ONE(CV), NF) \
501 O(NewStructDArray, ONE(VSA), SMANY, ONE(CV), NF) \
502 O(NewStructDict, ONE(VSA), SMANY, ONE(CV), NF) \
503 O(NewVecArray, ONE(IVA), CMANY, ONE(CV), NF) \
504 O(NewKeysetArray, ONE(IVA), CMANY, ONE(CV), NF) \
505 O(NewVArray, ONE(IVA), CMANY, ONE(CV), NF) \
506 O(NewDArray, ONE(IVA), NOV, ONE(CV), NF) \
507 O(AddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
508 O(AddElemV, NA, THREE(VV,CV,CV), ONE(CV), NF) \
509 O(AddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
510 O(AddNewElemV, NA, TWO(VV,CV), ONE(CV), NF) \
511 O(NewCol, ONE(OA(CollectionType)), \
512 NOV, ONE(CV), NF) \
513 O(NewPair, NA, TWO(CV,CV), ONE(CV), NF) \
514 O(ColFromArray, ONE(OA(CollectionType)), \
515 ONE(CV), ONE(CV), NF) \
516 O(Cns, ONE(SA), NOV, ONE(CV), NF) \
517 O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
518 O(CnsU, TWO(SA,SA), NOV, ONE(CV), NF) \
519 O(CnsUE, TWO(SA,SA), NOV, ONE(CV), NF) \
520 O(ClsCns, TWO(SA,CAR), NOV, ONE(CV), NF) \
521 O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
522 O(ClsRefName, ONE(CAR), NOV, ONE(CV), NF) \
523 O(File, NA, NOV, ONE(CV), NF) \
524 O(Dir, NA, NOV, ONE(CV), NF) \
525 O(Method, NA, NOV, ONE(CV), NF) \
526 O(Concat, NA, TWO(CV,CV), ONE(CV), NF) \
527 O(ConcatN, ONE(IVA), CMANY, ONE(CV), NF) \
528 O(Add, NA, TWO(CV,CV), ONE(CV), NF) \
529 O(Sub, NA, TWO(CV,CV), ONE(CV), NF) \
530 O(Mul, NA, TWO(CV,CV), ONE(CV), NF) \
531 O(AddO, NA, TWO(CV,CV), ONE(CV), NF) \
532 O(SubO, NA, TWO(CV,CV), ONE(CV), NF) \
533 O(MulO, NA, TWO(CV,CV), ONE(CV), NF) \
534 O(Div, NA, TWO(CV,CV), ONE(CV), NF) \
535 O(Mod, NA, TWO(CV,CV), ONE(CV), NF) \
536 O(Pow, NA, TWO(CV,CV), ONE(CV), NF) \
537 O(Xor, NA, TWO(CV,CV), ONE(CV), NF) \
538 O(Not, NA, ONE(CV), ONE(CV), NF) \
539 O(Same, NA, TWO(CV,CV), ONE(CV), NF) \
540 O(NSame, NA, TWO(CV,CV), ONE(CV), NF) \
541 O(Eq, NA, TWO(CV,CV), ONE(CV), NF) \
542 O(Neq, NA, TWO(CV,CV), ONE(CV), NF) \
543 O(Lt, NA, TWO(CV,CV), ONE(CV), NF) \
544 O(Lte, NA, TWO(CV,CV), ONE(CV), NF) \
545 O(Gt, NA, TWO(CV,CV), ONE(CV), NF) \
546 O(Gte, NA, TWO(CV,CV), ONE(CV), NF) \
547 O(Cmp, NA, TWO(CV,CV), ONE(CV), NF) \
548 O(BitAnd, NA, TWO(CV,CV), ONE(CV), NF) \
549 O(BitOr, NA, TWO(CV,CV), ONE(CV), NF) \
550 O(BitXor, NA, TWO(CV,CV), ONE(CV), NF) \
551 O(BitNot, NA, ONE(CV), ONE(CV), NF) \
552 O(Shl, NA, TWO(CV,CV), ONE(CV), NF) \
553 O(Shr, NA, TWO(CV,CV), ONE(CV), NF) \
554 O(CastBool, NA, ONE(CV), ONE(CV), NF) \
555 O(CastInt, NA, ONE(CV), ONE(CV), NF) \
556 O(CastDouble, NA, ONE(CV), ONE(CV), NF) \
557 O(CastString, NA, ONE(CV), ONE(CV), NF) \
558 O(CastArray, NA, ONE(CV), ONE(CV), NF) \
559 O(CastObject, NA, ONE(CV), ONE(CV), NF) \
560 O(CastDict, NA, ONE(CV), ONE(CV), NF) \
561 O(CastKeyset, NA, ONE(CV), ONE(CV), NF) \
562 O(CastVec, NA, ONE(CV), ONE(CV), NF) \
563 O(CastVArray, NA, ONE(CV), ONE(CV), NF) \
564 O(CastDArray, NA, ONE(CV), ONE(CV), NF) \
565 O(DblAsBits, NA, ONE(CV), ONE(CV), NF) \
566 O(InstanceOf, NA, TWO(CV,CV), ONE(CV), NF) \
567 O(InstanceOfD, ONE(SA), ONE(CV), ONE(CV), NF) \
568 O(IsTypeStructC, ONE(OA(TypeStructResolveOp)), \
569 TWO(CV,CV), ONE(CV), NF) \
570 O(AsTypeStructC, ONE(OA(TypeStructResolveOp)), \
571 TWO(CV,CV), ONE(CV), NF) \
572 O(CombineAndResolveTypeStruct, \
573 ONE(IVA), CMANY, ONE(CV), NF) \
574 O(Select, NA, THREE(CV,CV,CV), ONE(CV), NF) \
575 O(Print, NA, ONE(CV), ONE(CV), NF) \
576 O(Clone, NA, ONE(CV), ONE(CV), NF) \
577 O(Exit, NA, ONE(CV), ONE(CV), TF) \
578 O(Fatal, ONE(OA(FatalOp)), ONE(CV), NOV, TF) \
579 O(Jmp, ONE(BA), NOV, NOV, CF_TF) \
580 O(JmpNS, ONE(BA), NOV, NOV, CF_TF) \
581 O(JmpZ, ONE(BA), ONE(CV), NOV, CF) \
582 O(JmpNZ, ONE(BA), ONE(CV), NOV, CF) \
583 O(Switch, THREE(OA(SwitchKind),I64A,BLA), \
584 ONE(CV), NOV, CF_TF) \
585 O(SSwitch, ONE(SLA), ONE(CV), NOV, CF_TF) \
586 O(RetC, NA, ONE(CV), NOV, CF_TF) \
587 O(RetM, ONE(IVA), CMANY, NOV, CF_TF) \
588 O(RetCSuspended, NA, ONE(CV), NOV, CF_TF) \
589 O(Unwind, NA, NOV, NOV, TF) \
590 O(Throw, NA, ONE(CV), NOV, CF_TF) \
591 O(CGetL, ONE(LA), NOV, ONE(CV), NF) \
592 O(CGetQuietL, ONE(LA), NOV, ONE(CV), NF) \
593 O(CUGetL, ONE(LA), NOV, ONE(CUV), NF) \
594 O(CGetL2, ONE(LA), NOV, INS_1(CV), NF) \
595 O(PushL, ONE(LA), NOV, ONE(CV), NF) \
596 O(CGetG, NA, ONE(CV), ONE(CV), NF) \
597 O(CGetQuietG, NA, ONE(CV), ONE(CV), NF) \
598 O(CGetS, ONE(CAR), ONE(CV), ONE(CV), NF) \
599 O(VGetL, ONE(LA), NOV, ONE(VV), NF) \
600 O(VGetG, NA, ONE(CV), ONE(VV), NF) \
601 O(VGetS, ONE(CAR), ONE(CV), ONE(VV), NF) \
602 O(ClsRefGetC, ONE(CAW), ONE(CV), NOV, NF) \
603 O(ClsRefGetTS, ONE(CAW), ONE(CV), NOV, NF) \
604 O(GetMemoKeyL, ONE(LA), NOV, ONE(CV), NF) \
605 O(AKExists, NA, TWO(CV,CV), ONE(CV), NF) \
606 O(IssetL, ONE(LA), NOV, ONE(CV), NF) \
607 O(IssetG, NA, ONE(CV), ONE(CV), NF) \
608 O(IssetS, ONE(CAR), ONE(CV), ONE(CV), NF) \
609 O(EmptyL, ONE(LA), NOV, ONE(CV), NF) \
610 O(EmptyG, NA, ONE(CV), ONE(CV), NF) \
611 O(EmptyS, ONE(CAR), ONE(CV), ONE(CV), NF) \
612 O(IsTypeC, ONE(OA(IsTypeOp)),ONE(CV), ONE(CV), NF) \
613 O(IsTypeL, TWO(LA, \
614 OA(IsTypeOp)), NOV, ONE(CV), NF) \
615 O(AssertRATL, TWO(LA,RATA), NOV, NOV, NF) \
616 O(AssertRATStk, TWO(IVA,RATA), NOV, NOV, NF) \
617 O(SetL, ONE(LA), ONE(CV), ONE(CV), NF) \
618 O(SetG, NA, TWO(CV,CV), ONE(CV), NF) \
619 O(SetS, ONE(CAR), TWO(CV,CV), ONE(CV), NF) \
620 O(SetOpL, TWO(LA, \
621 OA(SetOpOp)), ONE(CV), ONE(CV), NF) \
622 O(SetOpG, ONE(OA(SetOpOp)), TWO(CV,CV), ONE(CV), NF) \
623 O(SetOpS, TWO(OA(SetOpOp),CAR), \
624 TWO(CV,CV), ONE(CV), NF) \
625 O(IncDecL, TWO(LA, \
626 OA(IncDecOp)), NOV, ONE(CV), NF) \
627 O(IncDecG, ONE(OA(IncDecOp)),ONE(CV), ONE(CV), NF) \
628 O(IncDecS, TWO(OA(IncDecOp),CAR), \
629 ONE(CV), ONE(CV), NF) \
630 O(BindL, ONE(LA), ONE(VV), ONE(VV), NF) \
631 O(BindG, NA, TWO(VV,CV), ONE(VV), NF) \
632 O(BindS, ONE(CAR), TWO(VV,CV), ONE(VV), NF) \
633 O(UnsetL, ONE(LA), NOV, NOV, NF) \
634 O(UnsetG, NA, ONE(CV), NOV, NF) \
636 O(FPushFunc, TWO(IVA,I32LA), ONE(CV), NOV, PF) \
637 O(FPushFuncD, TWO(IVA,SA), NOV, NOV, PF) \
638 O(FPushFuncU, THREE(IVA,SA,SA), NOV, NOV, PF) \
639 O(ResolveFunc, ONE(SA), NOV, ONE(CV), NF) \
640 O(ResolveObjMethod,NA, TWO(CV,CV), ONE(CV), NF) \
641 O(ResolveClsMethod,NA, TWO(CV,CV), ONE(CV), NF) \
642 O(FPushObjMethod, THREE(IVA, \
643 OA(ObjMethodOp), \
644 I32LA), TWO(CV,CV), NOV, PF) \
645 O(FPushObjMethodD, THREE(IVA,SA, \
646 OA(ObjMethodOp)), ONE(CV), NOV, PF) \
647 O(FPushClsMethod, THREE(IVA,CAR,I32LA), \
648 ONE(CV), NOV, PF) \
649 O(FPushClsMethodS, THREE(IVA,OA(SpecialClsRef),I32LA), \
650 ONE(CV), NOV, PF) \
651 O(FPushClsMethodSD,THREE(IVA,OA(SpecialClsRef),SA), \
652 NOV, NOV, PF) \
653 O(FPushClsMethodD, THREE(IVA,SA,SA), NOV, NOV, PF) \
654 O(NewObj, TWO(CAR,OA(HasGenericsOp)), \
655 NOV, ONE(CV), NF) \
656 O(NewObjD, ONE(SA), NOV, ONE(CV), NF) \
657 O(NewObjI, ONE(IVA), NOV, ONE(CV), NF) \
658 O(NewObjS, ONE(OA(SpecialClsRef)), \
659 NOV, ONE(CV), NF) \
660 O(FPushCtor, ONE(IVA), ONE(CV), NOV, PF) \
661 O(FCall, THREE(FCA,SA,SA), FCALL, FCALL, CF) \
662 O(FCallBuiltin, THREE(IVA,IVA,SA),CVUMANY, ONE(CV), NF) \
663 O(IterInit, THREE(IA,BA,LA), ONE(CV), NOV, CF) \
664 O(LIterInit, FOUR(IA,LA,BA,LA),NOV, NOV, CF) \
665 O(IterInitK, FOUR(IA,BA,LA,LA),ONE(CV), NOV, CF) \
666 O(LIterInitK, FIVE(IA,LA,BA,LA,LA),NOV, NOV, CF) \
667 O(IterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
668 O(LIterNext, FOUR(IA,LA,BA,LA),NOV, NOV, CF) \
669 O(IterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
670 O(LIterNextK, FIVE(IA,LA,BA,LA,LA),NOV, NOV, CF) \
671 O(IterFree, ONE(IA), NOV, NOV, NF) \
672 O(LIterFree, TWO(IA,LA), NOV, NOV, NF) \
673 O(IterBreak, TWO(BA,ILA), NOV, NOV, CF_TF) \
674 O(Incl, NA, ONE(CV), ONE(CV), CF) \
675 O(InclOnce, NA, ONE(CV), ONE(CV), CF) \
676 O(Req, NA, ONE(CV), ONE(CV), CF) \
677 O(ReqOnce, NA, ONE(CV), ONE(CV), CF) \
678 O(ReqDoc, NA, ONE(CV), ONE(CV), CF) \
679 O(Eval, NA, ONE(CV), ONE(CV), CF) \
680 O(DefCls, ONE(IVA), NOV, NOV, NF) \
681 O(DefClsNop, ONE(IVA), NOV, NOV, NF) \
682 O(AliasCls, TWO(SA,SA), ONE(CV), ONE(CV), NF) \
683 O(DefCns, ONE(SA), ONE(CV), ONE(CV), NF) \
684 O(DefTypeAlias, ONE(IVA), NOV, NOV, NF) \
685 O(This, NA, NOV, ONE(CV), NF) \
686 O(BareThis, ONE(OA(BareThisOp)), \
687 NOV, ONE(CV), NF) \
688 O(CheckThis, NA, NOV, NOV, NF) \
689 O(InitThisLoc, ONE(LA), NOV, NOV, NF) \
690 O(FuncNumArgs, NA, NOV, ONE(CV), NF) \
691 O(StaticLocCheck, TWO(LA,SA), NOV, ONE(CV), NF) \
692 O(StaticLocDef, TWO(LA,SA), ONE(CV), NOV, NF) \
693 O(StaticLocInit, TWO(LA,SA), ONE(CV), NOV, NF) \
694 O(Catch, NA, NOV, ONE(CV), NF) \
695 O(ChainFaults, NA, TWO(CV,CV), ONE(CV), NF) \
696 O(OODeclExists, ONE(OA(OODeclExistsOp)), \
697 TWO(CV,CV), ONE(CV), NF) \
698 O(VerifyOutType, ONE(IVA), ONE(CV), ONE(CV), NF) \
699 O(VerifyParamType, ONE(LA), NOV, NOV, NF) \
700 O(VerifyParamTypeTS, ONE(LA), ONE(CV), NOV, NF) \
701 O(VerifyRetTypeC, NA, ONE(CV), ONE(CV), NF) \
702 O(VerifyRetTypeTS, NA, TWO(CV,CV), ONE(CV), NF) \
703 O(VerifyRetNonNullC, NA, ONE(CV), ONE(CV), NF) \
704 O(Self, ONE(CAW), NOV, NOV, NF) \
705 O(Parent, ONE(CAW), NOV, NOV, NF) \
706 O(LateBoundCls, ONE(CAW), NOV, NOV, NF) \
707 O(RecordReifiedGeneric, \
708 ONE(IVA), CMANY, ONE(CV), NF) \
709 O(ReifiedName, TWO(IVA,SA), CMANY, ONE(CV), NF) \
710 O(CheckReifiedGenericMismatch, NA, ONE(CV), NOV, NF) \
711 O(NativeImpl, NA, NOV, NOV, CF_TF) \
712 O(CreateCl, TWO(IVA,IVA), CVUMANY, ONE(CV), NF) \
713 O(CreateCont, NA, NOV, ONE(CV), CF) \
714 O(ContEnter, NA, ONE(CV), ONE(CV), CF) \
715 O(ContRaise, NA, ONE(CV), ONE(CV), CF) \
716 O(Yield, NA, ONE(CV), ONE(CV), CF) \
717 O(YieldK, NA, TWO(CV,CV), ONE(CV), CF) \
718 O(ContAssignDelegate, \
719 ONE(IA), ONE(CV), NOV, NF) \
720 O(ContEnterDelegate, \
721 NA, ONE(CV), NOV, CF) \
722 O(YieldFromDelegate, \
723 TWO(IA,BA), NOV, ONE(CV), CF) \
724 O(ContUnsetDelegate, TWO(OA(CudOp),IA), NOV, NOV, NF) \
725 O(ContCheck, ONE(OA(ContCheckOp)), NOV, NOV, NF) \
726 O(ContValid, NA, NOV, ONE(CV), NF) \
727 O(ContKey, NA, NOV, ONE(CV), NF) \
728 O(ContCurrent, NA, NOV, ONE(CV), NF) \
729 O(ContGetReturn, NA, NOV, ONE(CV), NF) \
730 O(WHResult, NA, ONE(CV), ONE(CV), NF) \
731 O(Await, NA, ONE(CV), ONE(CV), CF) \
732 O(AwaitAll, ONE(LAR), NOV, ONE(CV), CF) \
733 O(Idx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
734 O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
735 O(CheckProp, ONE(SA), NOV, ONE(CV), NF) \
736 O(InitProp, TWO(SA, \
737 OA(InitPropOp)),ONE(CV), NOV, NF) \
738 O(Silence, TWO(LA,OA(SilenceOp)), \
739 NOV, NOV, NF) \
740 O(BaseGC, TWO(IVA, OA(MOpMode)), \
741 NOV, NOV, NF) \
742 O(BaseGL, TWO(LA, OA(MOpMode)), \
743 NOV, NOV, NF) \
744 O(BaseSC, THREE(IVA, CAR, OA(MOpMode)), \
745 NOV, NOV, NF) \
746 O(BaseL, TWO(LA, OA(MOpMode)), \
747 NOV, NOV, NF) \
748 O(BaseC, TWO(IVA, OA(MOpMode)), \
749 NOV, NOV, NF) \
750 O(BaseH, NA, NOV, NOV, NF) \
751 O(Dim, TWO(OA(MOpMode), KA), \
752 NOV, NOV, NF) \
753 O(QueryM, THREE(IVA, OA(QueryMOp), KA), \
754 MFINAL, ONE(CV), NF) \
755 O(VGetM, TWO(IVA, KA), MFINAL, ONE(VV), NF) \
756 O(SetM, TWO(IVA, KA), C_MFINAL(1), ONE(CV), NF) \
757 O(SetRangeM, THREE(IVA, OA(SetRangeOp), IVA), \
758 C_MFINAL(3), NOV, NF) \
759 O(IncDecM, THREE(IVA, OA(IncDecOp), KA), \
760 MFINAL, ONE(CV), NF) \
761 O(SetOpM, THREE(IVA, OA(SetOpOp), KA), \
762 C_MFINAL(1), ONE(CV), NF) \
763 O(BindM, TWO(IVA, KA), V_MFINAL, ONE(VV), NF) \
764 O(UnsetM, TWO(IVA, KA), MFINAL, NOV, NF) \
765 O(MemoGet, TWO(BA, LAR), NOV, ONE(CV), CF) \
766 O(MemoGetEager, THREE(BA, BA, LAR), \
767 NOV, ONE(CV), CF) \
768 O(MemoSet, ONE(LAR), ONE(CV), ONE(CV), NF) \
769 O(MemoSetEager, ONE(LAR), ONE(CV), ONE(CV), NF)
771 enum class Op : uint16_t {
772 #define O(name, ...) name,
773 OPCODES
774 #undef O
777 #define O(...) + 1
778 constexpr size_t Op_count = OPCODES;
779 #undef O
782 * Also put Op* in the enclosing namespace, to avoid having to change every
783 * existing usage site of the enum values.
785 #define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
786 OPCODES
787 #undef O
789 // These are comparable by default under MSVC.
790 #ifndef _MSC_VER
791 inline constexpr bool operator<(Op a, Op b) { return size_t(a) < size_t(b); }
792 inline constexpr bool operator>(Op a, Op b) { return size_t(a) > size_t(b); }
793 inline constexpr bool operator<=(Op a, Op b) {
794 return size_t(a) <= size_t(b);
796 inline constexpr bool operator>=(Op a, Op b) {
797 return size_t(a) >= size_t(b);
799 #endif
801 constexpr bool isValidOpcode(Op op) {
802 return size_t(op) < Op_count;
805 inline MOpMode getQueryMOpMode(QueryMOp op) {
806 switch (op) {
807 case QueryMOp::CGet: return MOpMode::Warn;
808 case QueryMOp::CGetQuiet:
809 case QueryMOp::Isset:
810 case QueryMOp::Empty: return MOpMode::None;
811 case QueryMOp::InOut: return MOpMode::InOut;
813 always_assert(false);
816 #define HIGH_OPCODES \
817 O(FuncPrologue) \
818 O(TraceletGuard)
820 enum HighOp {
821 OpHighStart = Op_count-1,
822 #define O(name) Op##name,
823 HIGH_OPCODES
824 #undef O
827 struct StrVecItem {
828 Id str;
829 Offset dest;
832 struct ImmVector {
833 explicit ImmVector() : m_start(0) {}
835 explicit ImmVector(const uint8_t* start,
836 int32_t length,
837 int32_t numStack)
838 : m_length(length)
839 , m_numStack(numStack)
840 , m_start(start)
843 bool isValid() const { return m_start != 0; }
845 const int32_t* vec32() const {
846 return reinterpret_cast<const int32_t*>(m_start);
848 folly::Range<const int32_t*> range32() const {
849 auto base = vec32();
850 return {base, base + size()};
852 const StrVecItem* strvec() const {
853 return reinterpret_cast<const StrVecItem*>(m_start);
857 * Returns the length of the immediate vector in bytes (for M
858 * vectors) or elements (for switch vectors)
860 int32_t size() const { return m_length; }
863 * Returns the number of elements on the execution stack that this vector
864 * will need to access.
866 int numStackValues() const { return m_numStack; }
868 private:
869 int32_t m_length;
870 int32_t m_numStack;
871 const uint8_t* m_start;
874 struct IterTableEnt {
875 IterKind kind;
876 int32_t id;
877 int32_t local;
879 using IterTable = CompactVector<IterTableEnt>;
881 // Must be an opcode that actually has an ImmVector.
882 ImmVector getImmVector(PC opcode);
884 // Must be an opcode that actually has an IterTable.
885 IterTable getIterTable(PC opcode);
887 // Some decoding helper functions.
888 int numImmediates(Op opcode);
889 ArgType immType(Op opcode, int idx);
890 bool hasImmVector(Op opcode);
891 bool hasIterTable(Op opcode);
892 int instrLen(PC opcode);
893 int numSuccs(PC opcode);
894 bool pushesActRec(Op opcode);
896 PC skipCall(PC pc);
897 IterTable iterTableFromStream(PC&);
900 * The returned struct has normalized variable-sized immediates. u must be
901 * provided unless you know that the immediate is not of type KA.
903 * Don't use with RATA immediates.
905 ArgUnion getImm(PC opcode, int idx, const Unit* u = nullptr);
907 // Don't use this with variable-sized immediates!
908 ArgUnion* getImmPtr(PC opcode, int idx);
910 void staticStreamer(const TypedValue* tv, std::string& out);
912 std::string instrToString(PC it, Either<const Unit*, const UnitEmitter*> u);
913 void staticArrayStreamer(const ArrayData*, std::string&);
916 * Convert subopcodes or opcodes into strings.
918 const char* opcodeToName(Op op);
919 const char* subopToName(InitPropOp);
920 const char* subopToName(IsTypeOp);
921 const char* subopToName(FatalOp);
922 const char* subopToName(CollectionType);
923 const char* subopToName(SetOpOp);
924 const char* subopToName(IncDecOp);
925 const char* subopToName(BareThisOp);
926 const char* subopToName(SilenceOp);
927 const char* subopToName(OODeclExistsOp);
928 const char* subopToName(ObjMethodOp);
929 const char* subopToName(SwitchKind);
930 const char* subopToName(MOpMode);
931 const char* subopToName(QueryMOp);
932 const char* subopToName(SetRangeOp);
933 const char* subopToName(TypeStructResolveOp);
934 const char* subopToName(HasGenericsOp);
935 const char* subopToName(ContCheckOp);
936 const char* subopToName(CudOp);
937 const char* subopToName(SpecialClsRef);
940 * Returns true iff the given SubOp is in the valid range for its type.
942 template<class Subop>
943 bool subopValid(Subop);
946 * Try to parse a string into a subop name of a given type.
948 * Returns folly::none if the string is not recognized as that type of
949 * subop.
951 template<class SubOpType>
952 folly::Optional<SubOpType> nameToSubop(const char*);
954 using OffsetList = std::vector<Offset>;
956 // Returns a jump offsets relative to the instruction, or nothing if
957 // the instruction cannot jump.
958 OffsetList instrJumpOffsets(PC instr);
960 // returns absolute address of targets, or nothing if instruction
961 // cannot jump
962 OffsetList instrJumpTargets(PC instrs, Offset pos);
965 * Returns the set of bytecode offsets for the instructions that may
966 * be executed immediately after opc.
968 using OffsetSet = hphp_hash_set<Offset>;
969 OffsetSet instrSuccOffsets(PC opc, const Func* func);
971 struct StackTransInfo {
972 enum class Kind {
973 PushPop,
974 InsertMid
976 Kind kind;
977 int numPops; // only for PushPop
978 int numPushes; // only for PushPop
979 int pos; // only for InsertMid
983 * Some CF instructions can be treated as non-CF instructions for most analysis
984 * purposes, such as bytecode verification and HHBBC. These instructions change
985 * vmpc() to point somewhere in a different function, but the runtime
986 * guarantees that if excution ever returns to the original frame, it will be
987 * at the location immediately following the instruction in question. This
988 * creates the illusion that the instruction fell through normally to the
989 * instruction after it, within the context of its execution frame.
991 * The canonical example of this behavior is the FCall instruction, so we use
992 * "non-call control flow" to describe the set of CF instruction that do not
993 * exhibit this behavior. This function returns true if `opcode' is a non-call
994 * control flow instruction.
996 bool instrIsNonCallControlFlow(Op opcode);
998 bool instrAllowsFallThru(Op opcode);
1000 constexpr InstrFlags instrFlagsData[] = {
1001 #define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
1002 OPCODES
1003 #undef O
1006 constexpr InstrFlags instrFlags(Op opcode) {
1007 return instrFlagsData[size_t(opcode)];
1010 constexpr bool instrIsControlFlow(Op opcode) {
1011 return (instrFlags(opcode) & CF) != 0;
1014 constexpr bool isUnconditionalJmp(Op opcode) {
1015 return opcode == Op::Jmp || opcode == Op::JmpNS;
1018 constexpr bool isConditionalJmp(Op opcode) {
1019 return opcode == Op::JmpZ || opcode == Op::JmpNZ;
1022 constexpr bool isJmp(Op opcode) {
1023 return
1024 opcode == Op::Jmp ||
1025 opcode == Op::JmpNS ||
1026 opcode == Op::JmpZ ||
1027 opcode == Op::JmpNZ;
1030 constexpr bool isFPush(Op opcode) {
1031 return (instrFlags(opcode) & PF) != 0;
1034 constexpr bool isFPushClsMethod(Op opcode) {
1035 return
1036 opcode == OpFPushClsMethod ||
1037 opcode == OpFPushClsMethodS ||
1038 opcode == OpFPushClsMethodSD ||
1039 opcode == OpFPushClsMethodD;
1042 constexpr bool isFPushObjMethod(Op opcode) {
1043 return
1044 opcode == OpFPushObjMethod ||
1045 opcode == OpFPushObjMethodD;
1048 constexpr bool isFPushFunc(Op opcode) {
1049 return
1050 opcode == OpFPushFunc ||
1051 opcode == OpFPushFuncD ||
1052 opcode == OpFPushFuncU;
1055 inline bool isFCallStar(Op opcode) {
1056 switch (opcode) {
1057 case Op::FCall:
1058 return true;
1059 default:
1060 return false;
1064 constexpr bool isRet(Op op) {
1065 return op == OpRetC || op == OpRetCSuspended || op == OpRetM;
1068 constexpr bool isReturnish(Op op) {
1069 return isRet(op) || op == Op::NativeImpl;
1072 constexpr bool isSwitch(Op op) {
1073 return op == OpSwitch || op == OpSSwitch;
1076 constexpr bool isTypeAssert(Op op) {
1077 return op == OpAssertRATL || op == OpAssertRATStk;
1080 inline bool isMemberBaseOp(Op op) {
1081 switch (op) {
1082 case Op::BaseGC:
1083 case Op::BaseGL:
1084 case Op::BaseSC:
1085 case Op::BaseL:
1086 case Op::BaseC:
1087 case Op::BaseH:
1088 return true;
1090 default:
1091 return false;
1095 inline bool isMemberDimOp(Op op) {
1096 return op == Op::Dim;
1099 inline bool isMemberFinalOp(Op op) {
1100 switch (op) {
1101 case Op::QueryM:
1102 case Op::VGetM:
1103 case Op::SetM:
1104 case Op::SetRangeM:
1105 case Op::IncDecM:
1106 case Op::SetOpM:
1107 case Op::BindM:
1108 case Op::UnsetM:
1109 return true;
1111 default:
1112 return false;
1116 inline bool isMemberOp(Op op) {
1117 return isMemberBaseOp(op) || isMemberDimOp(op) || isMemberFinalOp(op);
1120 inline MOpMode finalMemberOpMode(Op op) {
1121 switch(op){
1122 case Op::SetM:
1123 case Op::SetRangeM:
1124 case Op::VGetM:
1125 case Op::IncDecM:
1126 case Op::SetOpM:
1127 case Op::BindM:
1128 return MOpMode::Define;
1129 case Op::UnsetM:
1130 return MOpMode::Unset;
1131 case Op::QueryM:
1132 return MOpMode::None;
1133 default:
1134 always_assert_flog(
1135 false, "Unknown final member op {}", opcodeToName(op)
1140 // true if the opcode body can set pc=0 to halt the interpreter.
1141 constexpr bool instrCanHalt(Op op) {
1142 return op == OpRetC || op == OpNativeImpl ||
1143 op == OpAwait || op == OpAwaitAll || op == OpCreateCont ||
1144 op == OpYield || op == OpYieldK || op == OpRetM ||
1145 op == OpRetCSuspended || op == OpYieldFromDelegate;
1148 int instrNumPops(PC opcode);
1149 int instrNumPushes(PC opcode);
1150 FlavorDesc instrInputFlavor(PC op, uint32_t idx);
1151 StackTransInfo instrStackTransInfo(PC opcode);
1155 //////////////////////////////////////////////////////////////////////
1157 namespace std {
1158 template<>
1159 struct hash<HPHP::Op> {
1160 size_t operator()(HPHP::Op op) const {
1161 return HPHP::hash_int64(size_t(op));
1166 //////////////////////////////////////////////////////////////////////
1168 #endif