Add support for HHBC ops with 5 immediates
[hiphop-php.git] / hphp / runtime / vm / hhbc.h
blob6dd2b59b2c346bf22d9f4c1334534b705e1d1ac7
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/either.h"
30 #include "hphp/util/functional.h"
31 #include "hphp/util/hash-map-typedefs.h"
33 namespace HPHP {
35 //////////////////////////////////////////////////////////////////////
37 struct Unit;
38 struct UnitEmitter;
39 struct Func;
41 constexpr size_t kMaxHhbcImms = 5;
43 // A contiguous range of locals. The range always includes at least a single
44 // local (first), plus some number of additional locals immediately after
45 // (restCount).
46 struct LocalRange {
47 uint32_t first;
48 uint32_t restCount;
51 std::string show(const LocalRange&);
54 * Variable-size immediates are implemented as follows: To determine which size
55 * the immediate is, examine the first byte where the immediate is expected,
56 * and examine its high-order bit. If it is zero, it's a 1-byte immediate
57 * and the byte is the value. Otherwise, it's 4 bytes, and bits 8..31 must be
58 * logical-shifted to the right by one to get rid of the flag bit.
60 * The types in this macro for BLA and SLA are meaningless since they are never
61 * read out of ArgUnion (they use ImmVector and ImmVectorO).
63 * ArgTypes and their various decoding helpers should be kept in sync with the
64 * `hhx' bytecode inspection GDB command.
66 #define ARGTYPES \
67 ARGTYPE(NA, void*) /* unused */ \
68 ARGTYPEVEC(BLA, Offset) /* Bytecode offset vector immediate */ \
69 ARGTYPEVEC(SLA, Id) /* String id/offset pair vector */ \
70 ARGTYPEVEC(ILA, Id) /* IterKind/IterId pair vector */ \
71 ARGTYPEVEC(I32LA,uint32_t) /* Vector of 32-bit uint */ \
72 ARGTYPE(IVA, uint32_t) /* Variable size: 8 or 32-bit uint */ \
73 ARGTYPE(I64A, int64_t) /* 64-bit Integer */ \
74 ARGTYPE(LA, int32_t) /* Local variable ID: 8 or 32-bit int */ \
75 ARGTYPE(IA, int32_t) /* Iterator ID: 8 or 32-bit int */ \
76 ARGTYPE(CAR, int32_t) /* Class-ref slot (read): 8 or 32-bit int */ \
77 ARGTYPE(CAW, int32_t) /* Class-ref slot (write): 8 or 32-bit int */ \
78 ARGTYPE(DA, double) /* Double */ \
79 ARGTYPE(SA, Id) /* Static string ID */ \
80 ARGTYPE(AA, Id) /* Static array ID */ \
81 ARGTYPE(RATA, RepoAuthType) /* Statically inferred RepoAuthType */ \
82 ARGTYPE(BA, Offset) /* Bytecode offset */ \
83 ARGTYPE(OA, unsigned char) /* Sub-opcode, untyped */ \
84 ARGTYPE(KA, MemberKey) /* Member key: local, stack, int, str */ \
85 ARGTYPE(LAR, LocalRange) /* Contiguous range of locals */ \
86 ARGTYPEVEC(VSA, Id) /* Vector of static string IDs */
88 enum ArgType {
89 #define ARGTYPE(name, type) name,
90 #define ARGTYPEVEC(name, type) name,
91 ARGTYPES
92 #undef ARGTYPE
93 #undef ARGTYPEVEC
96 union ArgUnion {
97 ArgUnion() : u_LA{0} {}
98 char bytes[0];
99 #define ARGTYPE(name, type) type u_##name;
100 #define ARGTYPEVEC(name, type) type u_##name;
101 ARGTYPES
102 #undef ARGTYPE
103 #undef ARGTYPEVEC
106 const Offset InvalidAbsoluteOffset = -1;
108 enum FlavorDesc {
109 NOV, // None
110 CV, // Cell
111 VV, // Var
112 RV, // Return value (cell or var)
113 FV, // Function parameter (cell or var)
114 UV, // Uninit
115 CVV, // Cell or Var argument
116 CRV, // Cell or Return value argument
117 CUV, // Cell, or Uninit argument
118 CVUV, // Cell, Var, or Uninit argument
121 enum InstrFlags {
122 /* No flags. */
123 NF = 0x0,
125 /* Terminal: next instruction is not reachable via fall through or the callee
126 * returning control. This includes instructions like Throw and Unwind that
127 * always throw exceptions. */
128 TF = 0x1,
130 /* Control flow: If this instruction finishes executing (doesn't throw an
131 * exception), vmpc() is not guaranteed to point to the next instruction in
132 * the bytecode stream. This does not take VM reentry into account, as that
133 * operation is part of the instruction that performed the reentry, and does
134 * not affect what vmpc() is set to after the instruction completes. */
135 CF = 0x2,
137 /* Instruction uses current FPI. */
138 FF = 0x4,
140 /* Instruction pushes an FPI */
141 PF = 0x8,
143 /* Shorthand for common combinations. */
144 CF_TF = (CF | TF),
145 CF_FF = (CF | FF)
148 #define INCDEC_OPS \
149 INCDEC_OP(PreInc) \
150 INCDEC_OP(PostInc) \
151 INCDEC_OP(PreDec) \
152 INCDEC_OP(PostDec) \
154 INCDEC_OP(PreIncO) \
155 INCDEC_OP(PostIncO) \
156 INCDEC_OP(PreDecO) \
157 INCDEC_OP(PostDecO) \
159 enum class IncDecOp : uint8_t {
160 #define INCDEC_OP(incDecOp) incDecOp,
161 INCDEC_OPS
162 #undef INCDEC_OP
165 inline bool isPre(IncDecOp op) {
166 return
167 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
168 op == IncDecOp::PreDec || op == IncDecOp::PreDecO;
171 inline bool isInc(IncDecOp op) {
172 return
173 op == IncDecOp::PreInc || op == IncDecOp::PreIncO ||
174 op == IncDecOp::PostInc || op == IncDecOp::PostIncO;
177 inline bool isIncDecO(IncDecOp op) {
178 return
179 op == IncDecOp::PreIncO || op == IncDecOp::PreDecO ||
180 op == IncDecOp::PostIncO || op == IncDecOp::PostDecO;
183 #define ISTYPE_OPS \
184 ISTYPE_OP(Uninit) \
185 ISTYPE_OP(Null) \
186 ISTYPE_OP(Bool) \
187 ISTYPE_OP(Int) \
188 ISTYPE_OP(Dbl) \
189 ISTYPE_OP(Str) \
190 ISTYPE_OP(Arr) \
191 ISTYPE_OP(Vec) \
192 ISTYPE_OP(Dict) \
193 ISTYPE_OP(Keyset) \
194 ISTYPE_OP(Obj) \
195 ISTYPE_OP(Scalar) \
196 ISTYPE_OP(ArrLike) \
197 ISTYPE_OP(Res) \
198 ISTYPE_OP(VArray) \
199 ISTYPE_OP(DArray)
201 enum class IsTypeOp : uint8_t {
202 #define ISTYPE_OP(op) op,
203 ISTYPE_OPS
204 #undef ISTYPE_OP
207 #define INITPROP_OPS \
208 INITPROP_OP(Static) \
209 INITPROP_OP(NonStatic)
211 enum class InitPropOp : uint8_t {
212 #define INITPROP_OP(op) op,
213 INITPROP_OPS
214 #undef INITPROP_OP
217 enum IterKind {
218 KindOfIter = 0,
219 KindOfMIter = 1,
220 KindOfCIter = 2,
223 #define FATAL_OPS \
224 FATAL_OP(Runtime) \
225 FATAL_OP(Parse) \
226 FATAL_OP(RuntimeOmitFrame)
228 enum class FatalOp : uint8_t {
229 #define FATAL_OP(x) x,
230 FATAL_OPS
231 #undef FATAL_OP
234 // Each of the setop ops maps to a binary bytecode op. We have reasons
235 // for using distinct bitwise representations, though. This macro records
236 // their correspondence for mapping either direction.
237 #define SETOP_OPS \
238 SETOP_OP(PlusEqual, OpAdd) \
239 SETOP_OP(MinusEqual, OpSub) \
240 SETOP_OP(MulEqual, OpMul) \
241 SETOP_OP(ConcatEqual, OpConcat) \
242 SETOP_OP(DivEqual, OpDiv) \
243 SETOP_OP(PowEqual, OpPow) \
244 SETOP_OP(ModEqual, OpMod) \
245 SETOP_OP(AndEqual, OpBitAnd) \
246 SETOP_OP(OrEqual, OpBitOr) \
247 SETOP_OP(XorEqual, OpBitXor) \
248 SETOP_OP(SlEqual, OpShl) \
249 SETOP_OP(SrEqual, OpShr) \
250 SETOP_OP(PlusEqualO, OpAddO) \
251 SETOP_OP(MinusEqualO, OpSubO) \
252 SETOP_OP(MulEqualO, OpMulO) \
254 enum class SetOpOp : uint8_t {
255 #define SETOP_OP(setOpOp, bcOp) setOpOp,
256 SETOP_OPS
257 #undef SETOP_OP
260 #define BARETHIS_OPS \
261 BARETHIS_OP(Notice) \
262 BARETHIS_OP(NoNotice) \
263 BARETHIS_OP(NeverNull)
265 enum class BareThisOp : uint8_t {
266 #define BARETHIS_OP(x) x,
267 BARETHIS_OPS
268 #undef BARETHIS_OP
271 #define SILENCE_OPS \
272 SILENCE_OP(Start) \
273 SILENCE_OP(End)
275 enum class SilenceOp : uint8_t {
276 #define SILENCE_OP(x) x,
277 SILENCE_OPS
278 #undef SILENCE_OP
281 #define OO_DECL_EXISTS_OPS \
282 OO_DECL_EXISTS_OP(Class) \
283 OO_DECL_EXISTS_OP(Interface) \
284 OO_DECL_EXISTS_OP(Trait)
286 enum class OODeclExistsOp : uint8_t {
287 #define OO_DECL_EXISTS_OP(x) x,
288 OO_DECL_EXISTS_OPS
289 #undef OO_DECL_EXISTS_OP
292 #define OBJMETHOD_OPS \
293 OBJMETHOD_OP(NullThrows) \
294 OBJMETHOD_OP(NullSafe)
296 enum class ObjMethodOp : uint8_t {
297 #define OBJMETHOD_OP(x) x,
298 OBJMETHOD_OPS
299 #undef OBJMETHOD_OP
302 #define SWITCH_KINDS \
303 KIND(Unbounded) \
304 KIND(Bounded)
306 enum class SwitchKind : uint8_t {
307 #define KIND(x) x,
308 SWITCH_KINDS
309 #undef KIND
312 #define M_OP_MODES \
313 MODE(None) \
314 MODE(Warn) \
315 MODE(Define) \
316 MODE(Unset) \
317 /* InOut mode restricts allowed bases to the
318 array like types. */ \
319 MODE(InOut)
321 enum class MOpMode : uint8_t {
322 #define MODE(name) name,
323 M_OP_MODES
324 #undef MODE
327 #define QUERY_M_OPS \
328 OP(CGet) \
329 OP(CGetQuiet) \
330 OP(Isset) \
331 OP(Empty) \
332 OP(InOut)
334 enum class QueryMOp : uint8_t {
335 #define OP(name) name,
336 QUERY_M_OPS
337 #undef OP
340 #define CONT_CHECK_OPS \
341 CONT_CHECK_OP(IgnoreStarted) \
342 CONT_CHECK_OP(CheckStarted)
344 enum class ContCheckOp : uint8_t {
345 #define CONT_CHECK_OP(name) name,
346 CONT_CHECK_OPS
347 #undef CONT_CHECK_OP
350 #define CUD_OPS \
351 CUD_OP(IgnoreIter) \
352 CUD_OP(FreeIter)
354 enum class CudOp : uint8_t {
355 #define CUD_OP(name) name,
356 CUD_OPS
357 #undef CUD_OP
360 #define FPASS_HINT_OPS \
361 OP(Any) \
362 OP(Cell) \
363 OP(Ref)
365 enum class FPassHint : uint8_t {
366 #define OP(name) name,
367 FPASS_HINT_OPS
368 #undef OP
371 #define SPECIAL_CLS_REFS \
372 REF(Self) \
373 REF(Static) \
374 REF(Parent)
376 enum class SpecialClsRef : uint8_t {
377 #define REF(name) name,
378 SPECIAL_CLS_REFS
379 #undef REF
382 constexpr uint32_t kMaxConcatN = 4;
384 // name immediates inputs outputs flags
385 #define OPCODES \
386 O(Nop, NA, NOV, NOV, NF) \
387 O(EntryNop, NA, NOV, NOV, NF) \
388 O(BreakTraceHint, NA, NOV, NOV, NF) \
389 O(DiscardClsRef, ONE(CAR), NOV, NOV, NF) \
390 O(PopC, NA, ONE(CV), NOV, NF) \
391 O(PopV, NA, ONE(VV), NOV, NF) \
392 O(PopR, NA, ONE(RV), NOV, NF) \
393 O(PopU, NA, ONE(UV), NOV, NF) \
394 O(PopL, ONE(LA), ONE(CV), NOV, NF) \
395 O(Dup, NA, ONE(CV), TWO(CV,CV), NF) \
396 O(Box, NA, ONE(CV), ONE(VV), NF) \
397 O(Unbox, NA, ONE(VV), ONE(CV), NF) \
398 O(BoxR, NA, ONE(RV), ONE(VV), NF) \
399 O(BoxRNop, NA, ONE(RV), ONE(VV), NF) \
400 O(UnboxR, NA, ONE(RV), ONE(CV), NF) \
401 O(UnboxRNop, NA, ONE(RV), ONE(CV), NF) \
402 O(RGetCNop, NA, ONE(CV), ONE(RV), NF) \
403 O(CGetCUNop, NA, ONE(CUV), ONE(CV), NF) \
404 O(UGetCUNop, NA, ONE(CUV), ONE(UV), NF) \
405 O(Null, NA, NOV, ONE(CV), NF) \
406 O(NullUninit, NA, NOV, ONE(UV), NF) \
407 O(True, NA, NOV, ONE(CV), NF) \
408 O(False, NA, NOV, ONE(CV), NF) \
409 O(Int, ONE(I64A), NOV, ONE(CV), NF) \
410 O(Double, ONE(DA), NOV, ONE(CV), NF) \
411 O(String, ONE(SA), NOV, ONE(CV), NF) \
412 O(Array, ONE(AA), NOV, ONE(CV), NF) \
413 O(Dict, ONE(AA), NOV, ONE(CV), NF) \
414 O(Keyset, ONE(AA), NOV, ONE(CV), NF) \
415 O(Vec, ONE(AA), NOV, ONE(CV), NF) \
416 O(NewArray, ONE(IVA), NOV, ONE(CV), NF) \
417 O(NewMixedArray, ONE(IVA), NOV, ONE(CV), NF) \
418 O(NewDictArray, ONE(IVA), NOV, ONE(CV), NF) \
419 O(NewLikeArrayL, TWO(LA,IVA), NOV, ONE(CV), NF) \
420 O(NewPackedArray, ONE(IVA), CMANY, ONE(CV), NF) \
421 O(NewStructArray, ONE(VSA), SMANY, ONE(CV), NF) \
422 O(NewStructDArray, ONE(VSA), SMANY, ONE(CV), NF) \
423 O(NewStructDict, ONE(VSA), SMANY, ONE(CV), NF) \
424 O(NewVecArray, ONE(IVA), CMANY, ONE(CV), NF) \
425 O(NewKeysetArray, ONE(IVA), CMANY, ONE(CV), NF) \
426 O(NewVArray, ONE(IVA), CMANY, ONE(CV), NF) \
427 O(NewDArray, ONE(IVA), NOV, ONE(CV), NF) \
428 O(AddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
429 O(AddElemV, NA, THREE(VV,CV,CV), ONE(CV), NF) \
430 O(AddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
431 O(AddNewElemV, NA, TWO(VV,CV), ONE(CV), NF) \
432 O(NewCol, ONE(OA(CollectionType)), \
433 NOV, ONE(CV), NF) \
434 O(NewPair, NA, TWO(CV,CV), ONE(CV), NF) \
435 O(ColFromArray, ONE(OA(CollectionType)), \
436 ONE(CV), ONE(CV), NF) \
437 O(Cns, ONE(SA), NOV, ONE(CV), NF) \
438 O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
439 O(CnsU, TWO(SA,SA), NOV, ONE(CV), NF) \
440 O(ClsCns, TWO(SA,CAR), NOV, ONE(CV), NF) \
441 O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
442 O(ClsRefName, ONE(CAR), NOV, ONE(CV), NF) \
443 O(File, NA, NOV, ONE(CV), NF) \
444 O(Dir, NA, NOV, ONE(CV), NF) \
445 O(Method, NA, NOV, ONE(CV), NF) \
446 O(Concat, NA, TWO(CV,CV), ONE(CV), NF) \
447 O(ConcatN, ONE(IVA), CMANY, ONE(CV), NF) \
448 O(Add, NA, TWO(CV,CV), ONE(CV), NF) \
449 O(Sub, NA, TWO(CV,CV), ONE(CV), NF) \
450 O(Mul, NA, TWO(CV,CV), ONE(CV), NF) \
451 O(AddO, NA, TWO(CV,CV), ONE(CV), NF) \
452 O(SubO, NA, TWO(CV,CV), ONE(CV), NF) \
453 O(MulO, NA, TWO(CV,CV), ONE(CV), NF) \
454 O(Div, NA, TWO(CV,CV), ONE(CV), NF) \
455 O(Mod, NA, TWO(CV,CV), ONE(CV), NF) \
456 O(Pow, NA, TWO(CV,CV), ONE(CV), NF) \
457 O(Xor, NA, TWO(CV,CV), ONE(CV), NF) \
458 O(Not, NA, ONE(CV), ONE(CV), NF) \
459 O(Same, NA, TWO(CV,CV), ONE(CV), NF) \
460 O(NSame, NA, TWO(CV,CV), ONE(CV), NF) \
461 O(Eq, NA, TWO(CV,CV), ONE(CV), NF) \
462 O(Neq, NA, TWO(CV,CV), ONE(CV), NF) \
463 O(Lt, NA, TWO(CV,CV), ONE(CV), NF) \
464 O(Lte, NA, TWO(CV,CV), ONE(CV), NF) \
465 O(Gt, NA, TWO(CV,CV), ONE(CV), NF) \
466 O(Gte, NA, TWO(CV,CV), ONE(CV), NF) \
467 O(Cmp, NA, TWO(CV,CV), ONE(CV), NF) \
468 O(BitAnd, NA, TWO(CV,CV), ONE(CV), NF) \
469 O(BitOr, NA, TWO(CV,CV), ONE(CV), NF) \
470 O(BitXor, NA, TWO(CV,CV), ONE(CV), NF) \
471 O(BitNot, NA, ONE(CV), ONE(CV), NF) \
472 O(Shl, NA, TWO(CV,CV), ONE(CV), NF) \
473 O(Shr, NA, TWO(CV,CV), ONE(CV), NF) \
474 O(CastBool, NA, ONE(CV), ONE(CV), NF) \
475 O(CastInt, NA, ONE(CV), ONE(CV), NF) \
476 O(CastDouble, NA, ONE(CV), ONE(CV), NF) \
477 O(CastString, NA, ONE(CV), ONE(CV), NF) \
478 O(CastArray, NA, ONE(CV), ONE(CV), NF) \
479 O(CastObject, NA, ONE(CV), ONE(CV), NF) \
480 O(CastDict, NA, ONE(CV), ONE(CV), NF) \
481 O(CastKeyset, NA, ONE(CV), ONE(CV), NF) \
482 O(CastVec, NA, ONE(CV), ONE(CV), NF) \
483 O(CastVArray, NA, ONE(CV), ONE(CV), NF) \
484 O(CastDArray, NA, ONE(CV), ONE(CV), NF) \
485 O(InstanceOf, NA, TWO(CV,CV), ONE(CV), NF) \
486 O(InstanceOfD, ONE(SA), ONE(CV), ONE(CV), NF) \
487 O(IsTypeStruct, ONE(AA), ONE(CV), ONE(CV), NF) \
488 O(AsTypeStruct, ONE(AA), ONE(CV), ONE(CV), NF) \
489 O(Print, NA, ONE(CV), ONE(CV), NF) \
490 O(Clone, NA, ONE(CV), ONE(CV), NF) \
491 O(Exit, NA, ONE(CV), ONE(CV), TF) \
492 O(Fatal, ONE(OA(FatalOp)), ONE(CV), NOV, TF) \
493 O(Jmp, ONE(BA), NOV, NOV, CF_TF) \
494 O(JmpNS, ONE(BA), NOV, NOV, CF_TF) \
495 O(JmpZ, ONE(BA), ONE(CV), NOV, CF) \
496 O(JmpNZ, ONE(BA), ONE(CV), NOV, CF) \
497 O(Switch, THREE(OA(SwitchKind),I64A,BLA), \
498 ONE(CV), NOV, CF_TF) \
499 O(SSwitch, ONE(SLA), ONE(CV), NOV, CF_TF) \
500 O(RetC, NA, ONE(CV), NOV, CF_TF) \
501 O(RetV, NA, ONE(VV), NOV, CF_TF) \
502 O(RetM, ONE(IVA), CMANY, NOV, CF_TF) \
503 O(Unwind, NA, NOV, NOV, TF) \
504 O(Throw, NA, ONE(CV), NOV, TF) \
505 O(CGetL, ONE(LA), NOV, ONE(CV), NF) \
506 O(CGetQuietL, ONE(LA), NOV, ONE(CV), NF) \
507 O(CUGetL, ONE(LA), NOV, ONE(CUV), NF) \
508 O(CGetL2, ONE(LA), NOV, INS_1(CV), NF) \
509 O(PushL, ONE(LA), NOV, ONE(CV), NF) \
510 O(CGetN, NA, ONE(CV), ONE(CV), NF) \
511 O(CGetQuietN, NA, ONE(CV), ONE(CV), NF) \
512 O(CGetG, NA, ONE(CV), ONE(CV), NF) \
513 O(CGetQuietG, NA, ONE(CV), ONE(CV), NF) \
514 O(CGetS, ONE(CAR), ONE(CV), ONE(CV), NF) \
515 O(VGetL, ONE(LA), NOV, ONE(VV), NF) \
516 O(VGetN, NA, ONE(CV), ONE(VV), NF) \
517 O(VGetG, NA, ONE(CV), ONE(VV), NF) \
518 O(VGetS, ONE(CAR), ONE(CV), ONE(VV), NF) \
519 O(ClsRefGetC, ONE(CAW), ONE(CV), NOV, NF) \
520 O(ClsRefGetL, TWO(LA,CAW), NOV, NOV, NF) \
521 O(GetMemoKeyL, ONE(LA), NOV, ONE(CV), NF) \
522 O(AKExists, NA, TWO(CV,CV), ONE(CV), NF) \
523 O(IssetL, ONE(LA), NOV, ONE(CV), NF) \
524 O(IssetN, NA, ONE(CV), ONE(CV), NF) \
525 O(IssetG, NA, ONE(CV), ONE(CV), NF) \
526 O(IssetS, ONE(CAR), ONE(CV), ONE(CV), NF) \
527 O(EmptyL, ONE(LA), NOV, ONE(CV), NF) \
528 O(EmptyN, NA, ONE(CV), ONE(CV), NF) \
529 O(EmptyG, NA, ONE(CV), ONE(CV), NF) \
530 O(EmptyS, ONE(CAR), ONE(CV), ONE(CV), NF) \
531 O(IsTypeC, ONE(OA(IsTypeOp)),ONE(CV), ONE(CV), NF) \
532 O(IsTypeL, TWO(LA, \
533 OA(IsTypeOp)), NOV, ONE(CV), NF) \
534 O(IsUninit, NA, ONE(CUV), TWO(CUV,CV),NF) \
535 O(AssertRATL, TWO(LA,RATA), NOV, NOV, NF) \
536 O(AssertRATStk, TWO(IVA,RATA), NOV, NOV, NF) \
537 O(SetL, ONE(LA), ONE(CV), ONE(CV), NF) \
538 O(SetN, NA, TWO(CV,CV), ONE(CV), NF) \
539 O(SetG, NA, TWO(CV,CV), ONE(CV), NF) \
540 O(SetS, ONE(CAR), TWO(CV,CV), ONE(CV), NF) \
541 O(SetOpL, TWO(LA, \
542 OA(SetOpOp)), ONE(CV), ONE(CV), NF) \
543 O(SetOpN, ONE(OA(SetOpOp)), TWO(CV,CV), ONE(CV), NF) \
544 O(SetOpG, ONE(OA(SetOpOp)), TWO(CV,CV), ONE(CV), NF) \
545 O(SetOpS, TWO(OA(SetOpOp),CAR), \
546 TWO(CV,CV), ONE(CV), NF) \
547 O(IncDecL, TWO(LA, \
548 OA(IncDecOp)), NOV, ONE(CV), NF) \
549 O(IncDecN, ONE(OA(IncDecOp)),ONE(CV), ONE(CV), NF) \
550 O(IncDecG, ONE(OA(IncDecOp)),ONE(CV), ONE(CV), NF) \
551 O(IncDecS, TWO(OA(IncDecOp),CAR), \
552 ONE(CV), ONE(CV), NF) \
553 O(BindL, ONE(LA), ONE(VV), ONE(VV), NF) \
554 O(BindN, NA, TWO(VV,CV), ONE(VV), NF) \
555 O(BindG, NA, TWO(VV,CV), ONE(VV), NF) \
556 O(BindS, ONE(CAR), TWO(VV,CV), ONE(VV), NF) \
557 O(UnsetL, ONE(LA), NOV, NOV, NF) \
558 O(UnsetN, NA, ONE(CV), NOV, NF) \
559 O(UnsetG, NA, ONE(CV), NOV, NF) \
561 O(FPushFunc, TWO(IVA,I32LA), ONE(CV), NOV, PF) \
562 O(FPushFuncD, TWO(IVA,SA), NOV, NOV, PF) \
563 O(FPushFuncU, THREE(IVA,SA,SA), NOV, NOV, PF) \
564 O(FPushObjMethod, THREE(IVA, \
565 OA(ObjMethodOp), \
566 I32LA), TWO(CV,CV), NOV, PF) \
567 O(FPushObjMethodD, THREE(IVA,SA, \
568 OA(ObjMethodOp)), ONE(CV), NOV, PF) \
569 O(FPushClsMethod, THREE(IVA,CAR,I32LA), \
570 ONE(CV), NOV, PF) \
571 O(FPushClsMethodS, THREE(IVA,OA(SpecialClsRef),I32LA), \
572 ONE(CV), NOV, PF) \
573 O(FPushClsMethodSD,THREE(IVA,OA(SpecialClsRef),SA), \
574 NOV, NOV, PF) \
575 O(FPushClsMethodD, THREE(IVA,SA,SA), NOV, NOV, PF) \
576 O(FPushCtor, TWO(IVA,CAR), NOV, ONE(CV), PF) \
577 O(FPushCtorD, TWO(IVA,SA), NOV, ONE(CV), PF) \
578 O(FPushCtorI, TWO(IVA,IVA), NOV, ONE(CV), PF) \
579 O(FPushCtorS, TWO(IVA,OA(SpecialClsRef)), \
580 NOV, ONE(CV), PF) \
581 O(FPushCufIter, TWO(IVA,IA), NOV, NOV, PF) \
582 O(FPassC, TWO(IVA,OA(FPassHint)), \
583 ONE(CV), ONE(FV), FF) \
584 O(FPassCW, TWO(IVA,OA(FPassHint)), \
585 ONE(CV), ONE(FV), FF) \
586 O(FPassCE, TWO(IVA,OA(FPassHint)), \
587 ONE(CV), ONE(FV), FF) \
588 O(FPassV, TWO(IVA,OA(FPassHint)), \
589 ONE(VV), ONE(FV), FF) \
590 O(FPassVNop, TWO(IVA,OA(FPassHint)), \
591 ONE(VV), ONE(FV), FF) \
592 O(FPassR, TWO(IVA,OA(FPassHint)), \
593 ONE(RV), ONE(FV), FF) \
594 O(FPassL, THREE(IVA,LA,OA(FPassHint)), \
595 NOV, ONE(FV), FF) \
596 O(FPassN, TWO(IVA,OA(FPassHint)), \
597 ONE(CV), ONE(FV), FF) \
598 O(FPassG, TWO(IVA,OA(FPassHint)), \
599 ONE(CV), ONE(FV), FF) \
600 O(FPassS, THREE(IVA,CAR,OA(FPassHint)), \
601 ONE(CV), ONE(FV), FF) \
602 O(RaiseFPassWarning, THREE(OA(FPassHint),SA,IVA), \
603 NOV, NOV, NF) \
604 O(FCall, ONE(IVA), FMANY, ONE(RV), CF_FF) \
605 O(FCallM, TWO(IVA,IVA), UFMANY, CMANY, CF_FF) \
606 O(FCallDM, FOUR(IVA,IVA,SA,SA),UFMANY, CMANY, CF_FF) \
607 O(FCallUnpackM, TWO(IVA,IVA), UFMANY, CMANY, CF_FF) \
608 O(FCallAwait, THREE(IVA,SA,SA), FMANY, ONE(CV), CF_FF) \
609 O(FCallD, THREE(IVA,SA,SA), FMANY, ONE(RV), CF_FF) \
610 O(FCallUnpack, ONE(IVA), FMANY, ONE(RV), CF_FF) \
611 O(FCallBuiltin, THREE(IVA,IVA,SA),CVUMANY, ONE(RV), NF) \
612 O(IterInit, THREE(IA,BA,LA), ONE(CV), NOV, CF) \
613 O(MIterInit, THREE(IA,BA,LA), ONE(VV), NOV, CF) \
614 O(WIterInit, THREE(IA,BA,LA), ONE(CV), NOV, CF) \
615 O(IterInitK, FOUR(IA,BA,LA,LA),ONE(CV), NOV, CF) \
616 O(MIterInitK, FOUR(IA,BA,LA,LA),ONE(VV), NOV, CF) \
617 O(WIterInitK, FOUR(IA,BA,LA,LA),ONE(CV), NOV, CF) \
618 O(IterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
619 O(MIterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
620 O(WIterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
621 O(IterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
622 O(MIterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
623 O(WIterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
624 O(DecodeCufIter, TWO(IA,BA), ONE(CV), NOV, CF) \
625 O(IterFree, ONE(IA), NOV, NOV, NF) \
626 O(MIterFree, ONE(IA), NOV, NOV, NF) \
627 O(CIterFree, ONE(IA), NOV, NOV, NF) \
628 O(IterBreak, TWO(BA,ILA), NOV, NOV, CF_TF) \
629 O(Incl, NA, ONE(CV), ONE(CV), CF) \
630 O(InclOnce, NA, ONE(CV), ONE(CV), CF) \
631 O(Req, NA, ONE(CV), ONE(CV), CF) \
632 O(ReqOnce, NA, ONE(CV), ONE(CV), CF) \
633 O(ReqDoc, NA, ONE(CV), ONE(CV), CF) \
634 O(Eval, NA, ONE(CV), ONE(CV), CF) \
635 O(DefFunc, ONE(IVA), NOV, NOV, NF) \
636 O(DefCls, ONE(IVA), NOV, NOV, NF) \
637 O(DefClsNop, ONE(IVA), NOV, NOV, NF) \
638 O(AliasCls, TWO(SA,SA), ONE(CV), ONE(CV), NF) \
639 O(DefCns, ONE(SA), ONE(CV), ONE(CV), NF) \
640 O(DefTypeAlias, ONE(IVA), NOV, NOV, NF) \
641 O(This, NA, NOV, ONE(CV), NF) \
642 O(BareThis, ONE(OA(BareThisOp)), \
643 NOV, ONE(CV), NF) \
644 O(CheckThis, NA, NOV, NOV, NF) \
645 O(InitThisLoc, ONE(LA), NOV, NOV, NF) \
646 O(StaticLocCheck, TWO(LA,SA), NOV, ONE(CV), NF) \
647 O(StaticLocDef, TWO(LA,SA), ONE(CV), NOV, NF) \
648 O(StaticLocInit, TWO(LA,SA), ONE(CV), NOV, NF) \
649 O(Catch, NA, NOV, ONE(CV), NF) \
650 O(ChainFaults, NA, TWO(CV,CV), ONE(CV), NF) \
651 O(OODeclExists, ONE(OA(OODeclExistsOp)), \
652 TWO(CV,CV), ONE(CV), NF) \
653 O(VerifyOutType, ONE(IVA), ONE(CV), ONE(CV), NF) \
654 O(VerifyParamType, ONE(LA), NOV, NOV, NF) \
655 O(VerifyRetTypeC, NA, ONE(CV), ONE(CV), NF) \
656 O(VerifyRetTypeV, NA, ONE(VV), ONE(VV), NF) \
657 O(VerifyRetNonNullC, NA, ONE(CV), ONE(CV), NF) \
658 O(Self, ONE(CAW), NOV, NOV, NF) \
659 O(Parent, ONE(CAW), NOV, NOV, NF) \
660 O(LateBoundCls, ONE(CAW), NOV, NOV, NF) \
661 O(NativeImpl, NA, NOV, NOV, CF_TF) \
662 O(CreateCl, TWO(IVA,IVA), CVUMANY, ONE(CV), NF) \
663 O(CreateCont, NA, NOV, ONE(CV), CF) \
664 O(ContEnter, NA, ONE(CV), ONE(CV), CF) \
665 O(ContRaise, NA, ONE(CV), ONE(CV), CF) \
666 O(Yield, NA, ONE(CV), ONE(CV), CF) \
667 O(YieldK, NA, TWO(CV,CV), ONE(CV), CF) \
668 O(ContAssignDelegate, \
669 ONE(IA), ONE(CV), NOV, NF) \
670 O(ContEnterDelegate, \
671 NA, ONE(CV), NOV, CF) \
672 O(YieldFromDelegate, \
673 TWO(IA,BA), NOV, ONE(CV), CF) \
674 O(ContUnsetDelegate, TWO(OA(CudOp),IA), NOV, NOV, NF) \
675 O(ContCheck, ONE(OA(ContCheckOp)), NOV, NOV, NF) \
676 O(ContValid, NA, NOV, ONE(CV), NF) \
677 O(ContStarted, NA, NOV, ONE(CV), NF) \
678 O(ContKey, NA, NOV, ONE(CV), NF) \
679 O(ContCurrent, NA, NOV, ONE(CV), NF) \
680 O(ContGetReturn, NA, NOV, ONE(CV), NF) \
681 O(WHResult, NA, ONE(CV), ONE(CV), NF) \
682 O(Await, NA, ONE(CV), ONE(CV), CF) \
683 O(AwaitAll, ONE(LAR), NOV, ONE(CV), CF) \
684 O(IncStat, TWO(IVA,IVA), NOV, NOV, NF) \
685 O(Idx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
686 O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
687 O(CheckProp, ONE(SA), NOV, ONE(CV), NF) \
688 O(InitProp, TWO(SA, \
689 OA(InitPropOp)),ONE(CV), NOV, NF) \
690 O(Silence, TWO(LA,OA(SilenceOp)), \
691 NOV, NOV, NF) \
692 O(BaseNC, TWO(IVA, OA(MOpMode)), \
693 NOV, NOV, NF) \
694 O(BaseNL, TWO(LA, OA(MOpMode)), \
695 NOV, NOV, NF) \
696 O(BaseGC, TWO(IVA, OA(MOpMode)), \
697 NOV, NOV, NF) \
698 O(BaseGL, TWO(LA, OA(MOpMode)), \
699 NOV, NOV, NF) \
700 O(BaseSC, TWO(IVA, CAR), NOV, NOV, NF) \
701 O(BaseSL, TWO(LA, CAR), NOV, NOV, NF) \
702 O(BaseL, TWO(LA, OA(MOpMode)), \
703 NOV, NOV, NF) \
704 O(BaseC, ONE(IVA), NOV, NOV, NF) \
705 O(BaseR, ONE(IVA), NOV, NOV, NF) \
706 O(BaseH, NA, NOV, NOV, NF) \
707 O(FPassBaseNC, TWO(IVA, IVA), \
708 NOV, NOV, FF) \
709 O(FPassBaseNL, TWO(IVA, LA), \
710 NOV, NOV, FF) \
711 O(FPassBaseGC, TWO(IVA, IVA), \
712 NOV, NOV, FF) \
713 O(FPassBaseGL, TWO(IVA, LA), \
714 NOV, NOV, FF) \
715 O(FPassBaseL, TWO(IVA, LA), \
716 NOV, NOV, FF) \
717 O(Dim, TWO(OA(MOpMode), KA), \
718 NOV, NOV, NF) \
719 O(FPassDim, TWO(IVA, KA), NOV, NOV, FF) \
720 O(QueryM, THREE(IVA, OA(QueryMOp), KA), \
721 MFINAL, ONE(CV), NF) \
722 O(VGetM, TWO(IVA, KA), MFINAL, ONE(VV), NF) \
723 O(FPassM, FOUR(IVA,IVA,KA,OA(FPassHint)), \
724 F_MFINAL, ONE(FV), FF) \
725 O(SetM, TWO(IVA, KA), C_MFINAL, ONE(CV), NF) \
726 O(IncDecM, THREE(IVA, OA(IncDecOp), KA), \
727 MFINAL, ONE(CV), NF) \
728 O(SetOpM, THREE(IVA, OA(SetOpOp), KA), \
729 C_MFINAL, ONE(CV), NF) \
730 O(BindM, TWO(IVA, KA), V_MFINAL, ONE(VV), NF) \
731 O(UnsetM, TWO(IVA, KA), MFINAL, NOV, NF) \
732 O(SetWithRefLML, TWO(LA,LA), NOV, NOV, NF) \
733 O(SetWithRefRML, ONE(LA), ONE(RV), NOV, NF) \
734 O(MemoGet, TWO(IVA, LAR), MFINAL, ONE(CUV), NF) \
735 O(MemoSet, TWO(IVA, LAR), C_MFINAL, ONE(CV), NF) \
736 O(MaybeMemoType, NA, ONE(CV), ONE(CV), NF) \
737 O(IsMemoType, NA, ONE(CV), ONE(CV), NF)
739 enum class Op : uint16_t {
740 #define O(name, ...) name,
741 OPCODES
742 #undef O
745 #define O(...) + 1
746 constexpr size_t Op_count = OPCODES;
747 #undef O
750 * Also put Op* in the enclosing namespace, to avoid having to change every
751 * existing usage site of the enum values.
753 #define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
754 OPCODES
755 #undef O
757 // These are comparable by default under MSVC.
758 #ifndef _MSC_VER
759 inline constexpr bool operator<(Op a, Op b) { return size_t(a) < size_t(b); }
760 inline constexpr bool operator>(Op a, Op b) { return size_t(a) > size_t(b); }
761 inline constexpr bool operator<=(Op a, Op b) {
762 return size_t(a) <= size_t(b);
764 inline constexpr bool operator>=(Op a, Op b) {
765 return size_t(a) >= size_t(b);
767 #endif
769 constexpr bool isValidOpcode(Op op) {
770 return size_t(op) < Op_count;
773 inline MOpMode getQueryMOpMode(QueryMOp op) {
774 switch (op) {
775 case QueryMOp::CGet: return MOpMode::Warn;
776 case QueryMOp::CGetQuiet:
777 case QueryMOp::Isset:
778 case QueryMOp::Empty: return MOpMode::None;
779 case QueryMOp::InOut: return MOpMode::InOut;
781 always_assert(false);
784 enum AcoldOp {
785 OpAcoldStart = Op_count-1,
786 #define O(name, imm, pop, push, flags) OpAcold##name,
787 OPCODES
788 #undef O
789 OpAcoldCount
792 #define HIGH_OPCODES \
793 O(FuncPrologue) \
794 O(TraceletGuard)
796 enum HighOp {
797 OpHighStart = OpAcoldCount-1,
798 #define O(name) Op##name,
799 HIGH_OPCODES
800 #undef O
803 struct StrVecItem {
804 Id str;
805 Offset dest;
808 struct ImmVector {
809 explicit ImmVector() : m_start(0) {}
811 explicit ImmVector(const uint8_t* start,
812 int32_t length,
813 int32_t numStack)
814 : m_length(length)
815 , m_numStack(numStack)
816 , m_start(start)
820 * Returns an ImmVector from a pointer to the immediate vector
821 * itself. Use getImmVector() if you want to get it from an Opcode*
822 * that points to the opcode.
824 static ImmVector createFromStream(const uint8_t* opcode) {
825 int32_t size = reinterpret_cast<const int32_t*>(opcode)[0];
826 int32_t stackCount = reinterpret_cast<const int32_t*>(opcode)[1];
827 const uint8_t* start = opcode + sizeof(int32_t) + sizeof(int32_t);
828 return ImmVector(start, size, stackCount);
832 * Returns an ImmVector of 32-bit ints from a pointer to the
833 * immediate vector itself.
835 static ImmVector createFromStream(const int32_t* stream) {
836 int32_t size = stream[0];
837 return ImmVector(reinterpret_cast<const uint8_t*>(stream + 1), size, 0);
840 bool isValid() const { return m_start != 0; }
842 const int32_t* vec32() const {
843 return reinterpret_cast<const int32_t*>(m_start);
845 folly::Range<const int32_t*> range32() const {
846 auto base = vec32();
847 return {base, base + size()};
849 const StrVecItem* strvec() const {
850 return reinterpret_cast<const StrVecItem*>(m_start);
854 * Returns the length of the immediate vector in bytes (for M
855 * vectors) or elements (for switch vectors)
857 int32_t size() const { return m_length; }
860 * Returns the number of elements on the execution stack that this vector
861 * will need to access.
863 int numStackValues() const { return m_numStack; }
865 private:
866 int32_t m_length;
867 int32_t m_numStack;
868 const uint8_t* m_start;
871 // Must be an opcode that actually has an ImmVector.
872 ImmVector getImmVector(PC opcode);
874 // Some decoding helper functions.
875 int numImmediates(Op opcode);
876 ArgType immType(Op opcode, int idx);
877 int immSize(PC opcode, int idx);
878 bool immIsVector(Op opcode, int idx);
879 bool hasImmVector(Op opcode);
880 int instrLen(PC opcode);
881 int numSuccs(PC opcode);
882 bool pushesActRec(Op opcode);
885 * The returned struct has normalized variable-sized immediates. u must be
886 * provided unless you know that the immediate is not of type KA.
888 * Don't use with RATA immediates.
890 ArgUnion getImm(PC opcode, int idx, const Unit* u = nullptr);
892 // Don't use this with variable-sized immediates!
893 ArgUnion* getImmPtr(PC opcode, int idx);
895 void staticStreamer(const TypedValue* tv, std::string& out);
897 std::string instrToString(PC it, Either<const Unit*, const UnitEmitter*> u);
898 void staticArrayStreamer(const ArrayData*, std::string&);
901 * Convert subopcodes or opcodes into strings.
903 const char* opcodeToName(Op op);
904 const char* subopToName(InitPropOp);
905 const char* subopToName(IsTypeOp);
906 const char* subopToName(FatalOp);
907 const char* subopToName(CollectionType);
908 const char* subopToName(SetOpOp);
909 const char* subopToName(IncDecOp);
910 const char* subopToName(BareThisOp);
911 const char* subopToName(SilenceOp);
912 const char* subopToName(OODeclExistsOp);
913 const char* subopToName(ObjMethodOp);
914 const char* subopToName(SwitchKind);
915 const char* subopToName(MOpMode);
916 const char* subopToName(QueryMOp);
917 const char* subopToName(ContCheckOp);
918 const char* subopToName(CudOp);
919 const char* subopToName(FPassHint);
920 const char* subopToName(SpecialClsRef);
923 * Returns true iff the given SubOp is in the valid range for its type.
925 template<class Subop>
926 bool subopValid(Subop);
929 * Try to parse a string into a subop name of a given type.
931 * Returns folly::none if the string is not recognized as that type of
932 * subop.
934 template<class SubOpType>
935 folly::Optional<SubOpType> nameToSubop(const char*);
937 // returns a pointer to the location within the bytecode containing the jump
938 // Offset, or NULL if the instruction cannot jump. Note that this offset is
939 // relative to the current instruction.
940 Offset* instrJumpOffset(PC instr);
942 // returns absolute address of target, or InvalidAbsoluteOffset if instruction
943 // cannot jump
944 Offset instrJumpTarget(PC instrs, Offset pos);
947 * Returns the set of bytecode offsets for the instructions that may
948 * be executed immediately after opc.
950 using OffsetSet = hphp_hash_set<Offset>;
951 OffsetSet instrSuccOffsets(PC opc, const Unit* unit);
953 struct StackTransInfo {
954 enum class Kind {
955 PushPop,
956 InsertMid
958 Kind kind;
959 int numPops; // only for PushPop
960 int numPushes; // only for PushPop
961 int pos; // only for InsertMid
965 * Some CF instructions can be treated as non-CF instructions for most analysis
966 * purposes, such as bytecode verification and HHBBC. These instructions change
967 * vmpc() to point somewhere in a different function, but the runtime
968 * guarantees that if excution ever returns to the original frame, it will be
969 * at the location immediately following the instruction in question. This
970 * creates the illusion that the instruction fell through normally to the
971 * instruction after it, within the context of its execution frame.
973 * The canonical example of this behavior is the FCall instruction, so we use
974 * "non-call control flow" to describe the set of CF instruction that do not
975 * exhibit this behavior. This function returns true if `opcode' is a non-call
976 * control flow instruction.
978 bool instrIsNonCallControlFlow(Op opcode);
980 bool instrAllowsFallThru(Op opcode);
981 bool instrReadsCurrentFpi(Op opcode);
983 constexpr InstrFlags instrFlagsData[] = {
984 #define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
985 OPCODES
986 #undef O
989 constexpr InstrFlags instrFlags(Op opcode) {
990 return instrFlagsData[size_t(opcode)];
993 constexpr bool instrIsControlFlow(Op opcode) {
994 return (instrFlags(opcode) & CF) != 0;
997 constexpr bool isUnconditionalJmp(Op opcode) {
998 return opcode == Op::Jmp || opcode == Op::JmpNS;
1001 constexpr bool isConditionalJmp(Op opcode) {
1002 return opcode == Op::JmpZ || opcode == Op::JmpNZ;
1005 constexpr bool isJmp(Op opcode) {
1006 return opcode >= Op::Jmp && opcode <= Op::JmpNZ;
1009 constexpr bool isFPush(Op opcode) {
1010 return (instrFlags(opcode) & PF) != 0;
1013 constexpr bool isFPushCufIter(Op opcode) {
1014 return opcode == OpFPushCufIter;
1017 constexpr bool isFPushClsMethod(Op opcode) {
1018 return
1019 opcode == OpFPushClsMethod ||
1020 opcode == OpFPushClsMethodS ||
1021 opcode == OpFPushClsMethodSD ||
1022 opcode == OpFPushClsMethodD;
1025 constexpr bool isFPushObjMethod(Op opcode) {
1026 return
1027 opcode == OpFPushObjMethod ||
1028 opcode == OpFPushObjMethodD;
1031 constexpr bool isFPushCtor(Op opcode) {
1032 return
1033 opcode == OpFPushCtor ||
1034 opcode == OpFPushCtorD ||
1035 opcode == OpFPushCtorI ||
1036 opcode == OpFPushCtorS;
1039 constexpr bool isFPushFunc(Op opcode) {
1040 return opcode >= OpFPushFunc && opcode <= OpFPushFuncU;
1043 inline bool isFCallStar(Op opcode) {
1044 switch (opcode) {
1045 case Op::FCall:
1046 case Op::FCallD:
1047 case Op::FCallAwait:
1048 case Op::FCallUnpack:
1049 case Op::FCallM:
1050 case Op::FCallDM:
1051 case Op::FCallUnpackM:
1052 return true;
1053 default:
1054 return false;
1058 inline bool isFPassStar(Op opcode) {
1059 switch (opcode) {
1060 case OpFPassC:
1061 case OpFPassCW:
1062 case OpFPassCE:
1063 case OpFPassV:
1064 case OpFPassR:
1065 case OpFPassL:
1066 case OpFPassN:
1067 case OpFPassG:
1068 case OpFPassS:
1069 case OpFPassM:
1070 return true;
1072 default:
1073 return false;
1077 constexpr bool isRet(Op op) {
1078 return op == OpRetC || op == OpRetV || op == OpRetM;
1081 constexpr bool isReturnish(Op op) {
1082 return isRet(op) || op == Op::NativeImpl;
1085 constexpr bool isSwitch(Op op) {
1086 return op == OpSwitch || op == OpSSwitch;
1089 constexpr bool isTypeAssert(Op op) {
1090 return op == OpAssertRATL || op == OpAssertRATStk;
1093 inline bool isMemberBaseOp(Op op) {
1094 switch (op) {
1095 case Op::BaseNC:
1096 case Op::BaseNL:
1097 case Op::BaseGC:
1098 case Op::BaseGL:
1099 case Op::FPassBaseNC:
1100 case Op::FPassBaseNL:
1101 case Op::FPassBaseGC:
1102 case Op::FPassBaseGL:
1103 case Op::BaseSC:
1104 case Op::BaseSL:
1105 case Op::BaseL:
1106 case Op::FPassBaseL:
1107 case Op::BaseC:
1108 case Op::BaseR:
1109 case Op::BaseH:
1110 return true;
1112 default:
1113 return false;
1117 inline bool isMemberDimOp(Op op) {
1118 switch (op) {
1119 case Op::Dim:
1120 case Op::FPassDim:
1121 return true;
1123 default:
1124 return false;
1128 inline bool isMemberFinalOp(Op op) {
1129 switch (op) {
1130 case Op::QueryM:
1131 case Op::VGetM:
1132 case Op::FPassM:
1133 case Op::SetM:
1134 case Op::IncDecM:
1135 case Op::SetOpM:
1136 case Op::BindM:
1137 case Op::UnsetM:
1138 case Op::SetWithRefLML:
1139 case Op::SetWithRefRML:
1140 case Op::MemoGet:
1141 case Op::MemoSet:
1142 return true;
1144 default:
1145 return false;
1149 inline bool isMemberOp(Op op) {
1150 return isMemberBaseOp(op) || isMemberDimOp(op) || isMemberFinalOp(op);
1153 inline MOpMode finalMemberOpMode(Op op) {
1154 switch(op){
1155 case Op::FPassM:
1156 case Op::MemoGet:
1157 return MOpMode::Warn;
1158 case Op::SetM:
1159 case Op::VGetM:
1160 case Op::IncDecM:
1161 case Op::SetOpM:
1162 case Op::BindM:
1163 case Op::SetWithRefLML:
1164 case Op::SetWithRefRML:
1165 case Op::MemoSet:
1166 return MOpMode::Define;
1167 case Op::UnsetM:
1168 return MOpMode::Unset;
1169 default:
1170 return MOpMode::None;
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 == OpRetV || op == OpNativeImpl ||
1177 op == OpAwait || op == OpAwaitAll || op == OpCreateCont ||
1178 op == OpYield || op == OpYieldK || op == OpRetM ||
1179 op == OpYieldFromDelegate;
1182 int instrNumPops(PC opcode);
1183 int instrNumPushes(PC opcode);
1184 FlavorDesc instrInputFlavor(PC op, uint32_t idx);
1185 StackTransInfo instrStackTransInfo(PC opcode);
1188 * Delta from FP to top pre-live ActRec.
1190 int instrFpToArDelta(const Func* func, PC opcode);
1194 //////////////////////////////////////////////////////////////////////
1196 namespace std {
1197 template<>
1198 struct hash<HPHP::Op> {
1199 size_t operator()(HPHP::Op op) const {
1200 return HPHP::hash_int64(size_t(op));
1205 //////////////////////////////////////////////////////////////////////
1207 #endif