2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
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"
35 //////////////////////////////////////////////////////////////////////
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
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.
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 */
89 #define ARGTYPE(name, type) name,
90 #define ARGTYPEVEC(name, type) name,
97 ArgUnion() : u_LA
{0} {}
99 #define ARGTYPE(name, type) type u_##name;
100 #define ARGTYPEVEC(name, type) type u_##name;
106 const Offset InvalidAbsoluteOffset
= -1;
112 RV
, // Return value (cell or var)
113 FV
, // Function parameter (cell or var)
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
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. */
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. */
137 /* Instruction uses current FPI. */
140 /* Instruction pushes an FPI */
143 /* Shorthand for common combinations. */
155 INCDEC_OP(PostIncO) \
157 INCDEC_OP(PostDecO) \
159 enum class IncDecOp : uint8_t {
160 #define INCDEC_OP(incDecOp) incDecOp,
165 inline bool isPre(IncDecOp op
) {
167 op
== IncDecOp::PreInc
|| op
== IncDecOp::PreIncO
||
168 op
== IncDecOp::PreDec
|| op
== IncDecOp::PreDecO
;
171 inline bool isInc(IncDecOp op
) {
173 op
== IncDecOp::PreInc
|| op
== IncDecOp::PreIncO
||
174 op
== IncDecOp::PostInc
|| op
== IncDecOp::PostIncO
;
177 inline bool isIncDecO(IncDecOp op
) {
179 op
== IncDecOp::PreIncO
|| op
== IncDecOp::PreDecO
||
180 op
== IncDecOp::PostIncO
|| op
== IncDecOp::PostDecO
;
201 enum class IsTypeOp
: uint8_t {
202 #define ISTYPE_OP(op) 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,
226 FATAL_OP(RuntimeOmitFrame)
228 enum class FatalOp
: uint8_t {
229 #define FATAL_OP(x) x,
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.
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,
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,
271 #define SILENCE_OPS \
275 enum class SilenceOp
: uint8_t {
276 #define SILENCE_OP(x) x,
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,
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,
302 #define SWITCH_KINDS \
306 enum class SwitchKind
: uint8_t {
317 /* InOut mode restricts allowed bases to the
318 array like types. */ \
321 enum class MOpMode
: uint8_t {
322 #define MODE(name) name,
327 #define QUERY_M_OPS \
334 enum class QueryMOp
: uint8_t {
335 #define OP(name) name,
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,
354 enum class CudOp
: uint8_t {
355 #define CUD_OP(name) name,
360 #define FPASS_HINT_OPS \
365 enum class FPassHint
: uint8_t {
366 #define OP(name) name,
371 #define SPECIAL_CLS_REFS \
376 enum class SpecialClsRef
: uint8_t {
377 #define REF(name) name,
382 constexpr uint32_t kMaxConcatN
= 4;
384 // name immediates inputs outputs flags
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)), \
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) \
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) \
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) \
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, \
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), \
571 O(FPushClsMethodS, THREE(IVA,OA(SpecialClsRef),I32LA), \
573 O(FPushClsMethodSD,THREE(IVA,OA(SpecialClsRef),SA), \
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)), \
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)), \
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), \
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)), \
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)), \
692 O(BaseNC, TWO(IVA, OA(MOpMode)), \
694 O(BaseNL, TWO(LA, OA(MOpMode)), \
696 O(BaseGC, TWO(IVA, OA(MOpMode)), \
698 O(BaseGL, TWO(LA, OA(MOpMode)), \
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)), \
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), \
709 O(FPassBaseNL, TWO(IVA, LA), \
711 O(FPassBaseGC, TWO(IVA, IVA), \
713 O(FPassBaseGL, TWO(IVA, LA), \
715 O(FPassBaseL, TWO(IVA, LA), \
717 O(Dim, TWO(OA(MOpMode), KA), \
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,
746 constexpr size_t Op_count
= OPCODES
;
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;
757 // These are comparable by default under MSVC.
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
);
769 constexpr bool isValidOpcode(Op op
) {
770 return size_t(op
) < Op_count
;
773 inline MOpMode
getQueryMOpMode(QueryMOp 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);
785 OpAcoldStart
= Op_count
-1,
786 #define O(name, imm, pop, push, flags) OpAcold##name,
792 #define HIGH_OPCODES \
797 OpHighStart
= OpAcoldCount
-1,
798 #define O(name) Op##name,
809 explicit ImmVector() : m_start(0) {}
811 explicit ImmVector(const uint8_t* start
,
815 , m_numStack(numStack
)
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 {
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
; }
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
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
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
{
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,
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
) {
1019 opcode
== OpFPushClsMethod
||
1020 opcode
== OpFPushClsMethodS
||
1021 opcode
== OpFPushClsMethodSD
||
1022 opcode
== OpFPushClsMethodD
;
1025 constexpr bool isFPushObjMethod(Op opcode
) {
1027 opcode
== OpFPushObjMethod
||
1028 opcode
== OpFPushObjMethodD
;
1031 constexpr bool isFPushCtor(Op opcode
) {
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
) {
1047 case Op::FCallAwait
:
1048 case Op::FCallUnpack
:
1051 case Op::FCallUnpackM
:
1058 inline bool isFPassStar(Op opcode
) {
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
) {
1099 case Op::FPassBaseNC
:
1100 case Op::FPassBaseNL
:
1101 case Op::FPassBaseGC
:
1102 case Op::FPassBaseGL
:
1106 case Op::FPassBaseL
:
1117 inline bool isMemberDimOp(Op op
) {
1128 inline bool isMemberFinalOp(Op op
) {
1138 case Op::SetWithRefLML
:
1139 case Op::SetWithRefRML
:
1149 inline bool isMemberOp(Op op
) {
1150 return isMemberBaseOp(op
) || isMemberDimOp(op
) || isMemberFinalOp(op
);
1153 inline MOpMode
finalMemberOpMode(Op op
) {
1157 return MOpMode::Warn
;
1163 case Op::SetWithRefLML
:
1164 case Op::SetWithRefRML
:
1166 return MOpMode::Define
;
1168 return MOpMode::Unset
;
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 //////////////////////////////////////////////////////////////////////
1198 struct hash
<HPHP::Op
> {
1199 size_t operator()(HPHP::Op op
) const {
1200 return HPHP::hash_int64(size_t(op
));
1205 //////////////////////////////////////////////////////////////////////