2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2013 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 "hphp/runtime/base/complex-types.h"
26 // Variable-size immediates are implemented as follows. To determine which size
27 // the immediate is, examine the first byte where the immediate is expected, and
28 // examine its low-order bit. If it is zero, it's a 1-byte immediate; otherwise,
29 // it's 4 bytes. The immediate has to be logical-shifted to the right by one to
30 // get rid of the flag bit.
32 // The types in this macro for MA, BLA, and SLA are meaningless since
33 // they are never read out of ArgUnion (they use ImmVector and
36 ARGTYPE(NA, void*) /* unused */ \
37 ARGTYPEVEC(MA, int32_t) /* Member vector immediate */ \
38 ARGTYPEVEC(BLA, Offset) /* Bytecode offset vector immediate */ \
39 ARGTYPEVEC(SLA, Id) /* String id/offset pair vector */ \
40 ARGTYPEVEC(ILA, Id) /* IterKind/IterId pair vector */ \
41 ARGTYPE(IVA, int32_t) /* Variable size: 8 or 32-bit integer */ \
42 ARGTYPE(I64A, int64_t) /* 64-bit Integer */ \
43 ARGTYPE(LA, int32_t) /* Local variable ID: 8 or 32-bit int */ \
44 ARGTYPE(IA, int32_t) /* Iterator ID: 8 or 32-bit int */ \
45 ARGTYPE(DA, double) /* Double */ \
46 ARGTYPE(SA, Id) /* Static string ID */ \
47 ARGTYPE(AA, Id) /* Static array ID */ \
48 ARGTYPE(BA, Offset) /* Bytecode offset */ \
49 ARGTYPE(OA, unsigned char) /* Sub-opcode */ \
50 ARGTYPEVEC(VSA, Id) /* Vector of static string IDs */
53 #define ARGTYPE(name, type) name,
54 #define ARGTYPEVEC(name, type) name,
62 #define ARGTYPE(name, type) type u_##name;
63 #define ARGTYPEVEC(name, type) type u_##name;
69 const Offset InvalidAbsoluteOffset
= -1;
76 RV
, // Return value (cell or var)
77 FV
, // Function parameter (cell or var)
79 CVV
, // Cell or Var argument
80 CVUV
, // Cell, Var, or Uninit argument
85 TF
= 0x1, // Next instruction is not reachable via fall through or the
86 // callee returning control
87 CF
= 0x2, // Control flow instruction (branch, call, return, throw, etc)
88 FF
= 0x4, // Instruction uses current FPI
94 // Base is the object stored in a local, a cell, or $this
99 // Base is the global name referred to by a cell or a local.
103 // Base is the name of a local, given by a cell or the value of a
109 * Base is a static property member of a class. The S-vector takes
110 * two things to define a base. The classref portion comes at the
111 * end of the M-vector, and the property name can be defined by
112 * either a cell or a local immediate.
117 // Base is a function return value.
121 InvalidLocationCode
= NumLocationCodes
124 inline int numLocationCodeImms(LocationCode lc
) {
126 case LL
: case LGL
: case LNL
: case LSL
:
128 case LC
: case LH
: case LGC
: case LNC
: case LSC
: case LR
:
135 inline int numLocationCodeStackVals(LocationCode lc
) {
137 case LL
: case LH
: case LGL
: case LNL
:
139 case LC
: case LGC
: case LNC
: case LSL
: case LR
:
148 // Returns string representation of `lc'. (Pointer to internal static
149 // data, does not need to be freed.)
150 const char* locationCodeString(LocationCode lc
);
152 // Grok a LocationCode from a string---if the string doesn't represent
153 // a location code, returns InvalidLocationCode. This looks at at
154 // most the first two bytes in `s'---the parse will not fail if there
155 // is more junk after the first two bytes.
156 LocationCode
parseLocationCode(const char* s
);
159 // Element and property, consuming a cell from the stack.
163 // Element and property, using an immediate local id.
167 // Element and property, using a string immediate
171 // Element, using an int64 immediate
174 // New element operation. (No real stack element.)
178 InvalidMemberCode
= NumMemberCodes
188 MIA_final_get
= 0x20,
189 MIA_base
= MIA_warn
| MIA_define
,
190 MIA_intermediate
= MIA_warn
| MIA_define
| MIA_reffy
| MIA_unset
,
191 MIA_intermediate_prop
= MIA_warn
| MIA_define
| MIA_unset
,
192 MIA_final
= MIA_new
| MIA_final_get
,
194 // Some warnings may conditionally be built for Zend compatibility,
195 // but are off by default.
197 #ifdef HHVM_MORE_WARNINGS
204 // MII(instr, * in *M
205 // attrs, operation attributes
206 // bS, base operation suffix
207 // iS, intermediate operation suffix
208 // vC, final value count (0 or 1)
209 // fN) final new element operation name
211 MII(CGet, MIA_warn|MIA_final_get, W, W, 0, NotSuppNewElem) \
212 MII(VGet, MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
213 D, D, 0, VGetNewElem) \
214 MII(Isset, MIA_final_get, , , 0, NotSuppNewElem) \
215 MII(Empty, MIA_final_get, , , 0, NotSuppNewElem) \
216 MII(Set, MIA_define|MIA_new, D, D, 1, SetNewElem) \
217 MII(SetOp, MIA_more_warn|MIA_define|MIA_new|MIA_final_get, \
218 WD, WD, 1, SetOpNewElem) \
219 MII(IncDec, MIA_more_warn|MIA_define|MIA_new|MIA_final_get, \
220 WD, WD, 0, IncDecNewElem) \
221 MII(Bind, MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
222 D, D, 1, BindNewElem) \
223 MII(Unset, MIA_unset, , U, 0, NotSuppNewElem) \
224 MII(SetWithRefL,MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
225 D, D, 1, SetWithRefNewElem) \
226 MII(SetWithRefR,MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
227 D, D, 1, SetWithRefNewElem)
230 #define MII(instr, attrs, bS, iS, vC, fN) \
238 MInstrAttr m_baseOps
[NumLocationCodes
];
239 MInstrAttr m_intermediateOps
[NumMemberCodes
];
245 MInstr
instr() const {
249 const MInstrAttr
& getAttr(LocationCode lc
) const {
250 assert(lc
< NumLocationCodes
);
251 return m_baseOps
[lc
];
254 const MInstrAttr
& getAttr(MemberCode mc
) const {
255 assert(mc
< NumMemberCodes
);
256 return m_intermediateOps
[mc
];
259 unsigned valCount() const {
263 bool newElem() const {
267 bool finalGet() const {
271 const char* name() const {
276 inline bool memberCodeHasImm(MemberCode mc
) {
277 return mc
== MEL
|| mc
== MPL
|| mc
== MET
|| mc
== MPT
|| mc
== MEI
;
280 inline bool memberCodeImmIsLoc(MemberCode mc
) {
281 return mc
== MEL
|| mc
== MPL
;
284 inline bool memberCodeImmIsString(MemberCode mc
) {
285 return mc
== MET
|| mc
== MPT
;
288 inline bool memberCodeImmIsInt(MemberCode mc
) {
292 enum class MCodeImm
{ None
, Int
, String
, Local
};
293 inline MCodeImm
memberCodeImmType(MemberCode mc
) {
294 if (!memberCodeHasImm(mc
)) return MCodeImm::None
;
295 if (memberCodeImmIsLoc(mc
)) return MCodeImm::Local
;
296 if (memberCodeImmIsString(mc
)) return MCodeImm::String
;
297 if (memberCodeImmIsInt(mc
)) return MCodeImm::Int
;
302 inline int mcodeStackVals(MemberCode mc
) {
303 return !memberCodeHasImm(mc
) && mc
!= MW
? 1 : 0;
306 // Returns string representation of `mc'. (Pointer to internal static
307 // data, does not need to be freed.)
308 const char* memberCodeString(MemberCode mc
);
310 // Same semantics as parseLocationCode, but for member codes.
311 MemberCode
parseMemberCode(const char*);
320 #define INCDEC_OP(incDecOp) incDecOp,
326 #define IS_TYPE_OPS \
335 enum class IsTypeOp
: uint8_t {
336 #define IS_TYPE_OP(op) op,
341 // NB: right now hphp/hhbbc/abstract-interp.cpp depends on this enum
342 // being in order from smaller types to larger ones.
343 #define ASSERTT_OPS \
345 ASSERTT_OP(InitNull) \
354 ASSERTT_OP(OptBool) \
356 ASSERTT_OP(OptSStr) \
360 ASSERTT_OP(OptSArr) \
365 ASSERTT_OP(InitUnc) \
367 ASSERTT_OP(InitCell) \
371 enum class AssertTOp
: uint8_t {
372 #define ASSERTT_OP(op) op,
386 FATAL_OP(RuntimeOmitFrame)
388 enum class FatalOp
: uint8_t {
389 #define FATAL_OP(x) x,
394 // Each of the setop ops maps to a binary bytecode op. We have reasons
395 // for using distinct bitwise representations, though. This macro records
396 // their correspondence for mapping either direction.
398 SETOP_OP(PlusEqual, OpAdd) \
399 SETOP_OP(MinusEqual, OpSub) \
400 SETOP_OP(MulEqual, OpMul) \
401 SETOP_OP(ConcatEqual, OpConcat) \
402 SETOP_OP(DivEqual, OpDiv) \
403 SETOP_OP(ModEqual, OpMod) \
404 SETOP_OP(AndEqual, OpBitAnd) \
405 SETOP_OP(OrEqual, OpBitOr) \
406 SETOP_OP(XorEqual, OpBitXor) \
407 SETOP_OP(SlEqual, OpShl) \
408 SETOP_OP(SrEqual, OpShr)
411 #define SETOP_OP(setOpOp, bcOp) SetOp##setOpOp,
417 // name immediates inputs outputs flags
419 O(LowInvalid, NA, NOV, NOV, NF) \
420 O(Nop, NA, NOV, NOV, NF) \
421 O(BreakTraceHint, NA, NOV, NOV, NF) \
422 O(PopA, NA, ONE(AV), NOV, NF) \
423 O(PopC, NA, ONE(CV), NOV, NF) \
424 O(PopV, NA, ONE(VV), NOV, NF) \
425 O(PopR, NA, ONE(RV), NOV, NF) \
426 O(Dup, NA, ONE(CV), TWO(CV,CV), NF) \
427 O(Box, NA, ONE(CV), ONE(VV), NF) \
428 O(Unbox, NA, ONE(VV), ONE(CV), NF) \
429 O(BoxR, NA, ONE(RV), ONE(VV), NF) \
430 O(BoxRNop, NA, ONE(RV), ONE(VV), NF) \
431 O(UnboxR, NA, ONE(RV), ONE(CV), NF) \
432 O(UnboxRNop, NA, ONE(RV), ONE(CV), NF) \
433 O(Null, NA, NOV, ONE(CV), NF) \
434 O(NullUninit, NA, NOV, ONE(UV), NF) \
435 O(True, NA, NOV, ONE(CV), NF) \
436 O(False, NA, NOV, ONE(CV), NF) \
437 O(Int, ONE(I64A), NOV, ONE(CV), NF) \
438 O(Double, ONE(DA), NOV, ONE(CV), NF) \
439 O(String, ONE(SA), NOV, ONE(CV), NF) \
440 O(Array, ONE(AA), NOV, ONE(CV), NF) \
441 O(NewArray, NA, NOV, ONE(CV), NF) \
442 O(NewArrayReserve, ONE(IVA), NOV, ONE(CV), NF) \
443 O(NewPackedArray, ONE(IVA), CMANY, ONE(CV), NF) \
444 O(NewStructArray, ONE(VSA), SMANY, ONE(CV), NF) \
445 O(AddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
446 O(AddElemV, NA, THREE(VV,CV,CV), ONE(CV), NF) \
447 O(AddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
448 O(AddNewElemV, NA, TWO(VV,CV), ONE(CV), NF) \
449 O(NewCol, TWO(IVA,IVA), NOV, ONE(CV), NF) \
450 O(ColAddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
451 O(ColAddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
452 O(Cns, ONE(SA), NOV, ONE(CV), NF) \
453 O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
454 O(CnsU, TWO(SA,SA), NOV, ONE(CV), NF) \
455 O(ClsCns, ONE(SA), ONE(AV), ONE(CV), NF) \
456 O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
457 O(File, NA, NOV, ONE(CV), NF) \
458 O(Dir, NA, NOV, ONE(CV), NF) \
459 O(Concat, NA, TWO(CV,CV), ONE(CV), NF) \
460 O(Add, NA, TWO(CV,CV), ONE(CV), NF) \
461 O(Sub, NA, TWO(CV,CV), ONE(CV), NF) \
462 O(Mul, NA, TWO(CV,CV), ONE(CV), NF) \
463 O(Div, NA, TWO(CV,CV), ONE(CV), NF) \
464 O(Mod, NA, TWO(CV,CV), ONE(CV), NF) \
465 O(Sqrt, NA, ONE(CV), ONE(CV), NF) \
466 O(Xor, NA, TWO(CV,CV), ONE(CV), NF) \
467 O(Not, NA, ONE(CV), ONE(CV), NF) \
468 O(Same, NA, TWO(CV,CV), ONE(CV), NF) \
469 O(NSame, NA, TWO(CV,CV), ONE(CV), NF) \
470 O(Eq, NA, TWO(CV,CV), ONE(CV), NF) \
471 O(Neq, NA, TWO(CV,CV), ONE(CV), NF) \
472 O(Lt, NA, TWO(CV,CV), ONE(CV), NF) \
473 O(Lte, NA, TWO(CV,CV), ONE(CV), NF) \
474 O(Gt, NA, TWO(CV,CV), ONE(CV), NF) \
475 O(Gte, NA, TWO(CV,CV), ONE(CV), NF) \
476 O(BitAnd, NA, TWO(CV,CV), ONE(CV), NF) \
477 O(BitOr, NA, TWO(CV,CV), ONE(CV), NF) \
478 O(BitXor, NA, TWO(CV,CV), ONE(CV), NF) \
479 O(BitNot, NA, ONE(CV), ONE(CV), NF) \
480 O(Shl, NA, TWO(CV,CV), ONE(CV), NF) \
481 O(Shr, NA, TWO(CV,CV), ONE(CV), NF) \
482 O(CastBool, NA, ONE(CV), ONE(CV), NF) \
483 O(CastInt, NA, ONE(CV), ONE(CV), NF) \
484 O(CastDouble, NA, ONE(CV), ONE(CV), NF) \
485 O(CastString, NA, ONE(CV), ONE(CV), NF) \
486 O(CastArray, NA, ONE(CV), ONE(CV), NF) \
487 O(CastObject, NA, ONE(CV), ONE(CV), NF) \
488 O(InstanceOf, NA, TWO(CV,CV), ONE(CV), NF) \
489 O(InstanceOfD, ONE(SA), ONE(CV), ONE(CV), NF) \
490 O(Print, NA, ONE(CV), ONE(CV), NF) \
491 O(Clone, NA, ONE(CV), ONE(CV), NF) \
492 O(Exit, NA, ONE(CV), ONE(CV), NF) \
493 O(Fatal, ONE(OA), ONE(CV), NOV, CF_TF) \
494 O(Jmp, 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(BLA,I64A,IVA), \
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(Unwind, NA, NOV, NOV, CF_TF) \
503 O(Throw, NA, ONE(CV), NOV, CF_TF) \
504 O(CGetL, ONE(LA), NOV, ONE(CV), NF) \
505 O(CGetL2, ONE(LA), NOV, INS_1(CV), NF) \
506 O(CGetL3, ONE(LA), NOV, INS_2(CV), NF) \
507 O(PushL, ONE(LA), NOV, ONE(CV), NF) \
508 O(CGetN, NA, ONE(CV), ONE(CV), NF) \
509 O(CGetG, NA, ONE(CV), ONE(CV), NF) \
510 O(CGetS, NA, TWO(AV,CV), ONE(CV), NF) \
511 O(CGetM, ONE(MA), MMANY, ONE(CV), NF) \
512 O(VGetL, ONE(LA), NOV, ONE(VV), NF) \
513 O(VGetN, NA, ONE(CV), ONE(VV), NF) \
514 O(VGetG, NA, ONE(CV), ONE(VV), NF) \
515 O(VGetS, NA, TWO(AV,CV), ONE(VV), NF) \
516 O(VGetM, ONE(MA), MMANY, ONE(VV), NF) \
517 O(AGetC, NA, ONE(CV), ONE(AV), NF) \
518 O(AGetL, ONE(LA), NOV, ONE(AV), NF) \
519 O(AKExists, NA, TWO(CV,CV), ONE(CV), NF) \
520 O(IssetL, ONE(LA), NOV, ONE(CV), NF) \
521 O(IssetN, NA, ONE(CV), ONE(CV), NF) \
522 O(IssetG, NA, ONE(CV), ONE(CV), NF) \
523 O(IssetS, NA, TWO(AV,CV), ONE(CV), NF) \
524 O(IssetM, ONE(MA), MMANY, ONE(CV), NF) \
525 O(EmptyL, ONE(LA), NOV, ONE(CV), NF) \
526 O(EmptyN, NA, ONE(CV), ONE(CV), NF) \
527 O(EmptyG, NA, ONE(CV), ONE(CV), NF) \
528 O(EmptyS, NA, TWO(AV,CV), ONE(CV), NF) \
529 O(EmptyM, ONE(MA), MMANY, ONE(CV), NF) \
530 /* NB: isTypePred depends on this ordering. */ \
531 O(IsTypeC, ONE(OA), ONE(CV), ONE(CV), NF) \
532 O(IsTypeL, TWO(OA,LA), NOV, ONE(CV), NF) \
533 O(AssertTL, TWO(LA,OA), NOV, NOV, NF) \
534 O(AssertTStk, TWO(IVA,OA), NOV, NOV, NF) \
535 O(AssertObjL, THREE(LA,IVA,SA), NOV, NOV, NF) \
536 O(AssertObjStk, THREE(IVA,IVA,SA),NOV, NOV, NF) \
537 O(PredictTL, TWO(LA,OA), NOV, NOV, NF) \
538 O(PredictTStk, TWO(IVA,OA), NOV, NOV, NF) \
539 O(SetL, ONE(LA), ONE(CV), ONE(CV), NF) \
540 O(SetN, NA, TWO(CV,CV), ONE(CV), NF) \
541 O(SetG, NA, TWO(CV,CV), ONE(CV), NF) \
542 O(SetS, NA, THREE(CV,AV,CV), ONE(CV), NF) \
543 O(SetM, ONE(MA), C_MMANY, ONE(CV), NF) \
544 O(SetWithRefLM, TWO(MA,LA), MMANY, NOV, NF) \
545 O(SetWithRefRM, ONE(MA), R_MMANY, NOV, NF) \
546 O(SetOpL, TWO(LA,OA), ONE(CV), ONE(CV), NF) \
547 O(SetOpN, ONE(OA), TWO(CV,CV), ONE(CV), NF) \
548 O(SetOpG, ONE(OA), TWO(CV,CV), ONE(CV), NF) \
549 O(SetOpS, ONE(OA), THREE(CV,AV,CV), ONE(CV), NF) \
550 O(SetOpM, TWO(OA,MA), C_MMANY, ONE(CV), NF) \
551 O(IncDecL, TWO(LA,OA), NOV, ONE(CV), NF) \
552 O(IncDecN, ONE(OA), ONE(CV), ONE(CV), NF) \
553 O(IncDecG, ONE(OA), ONE(CV), ONE(CV), NF) \
554 O(IncDecS, ONE(OA), TWO(AV,CV), ONE(CV), NF) \
555 O(IncDecM, TWO(OA,MA), MMANY, ONE(CV), NF) \
556 O(BindL, ONE(LA), ONE(VV), ONE(VV), NF) \
557 O(BindN, NA, TWO(VV,CV), ONE(VV), NF) \
558 O(BindG, NA, TWO(VV,CV), ONE(VV), NF) \
559 O(BindS, NA, THREE(VV,AV,CV), ONE(VV), NF) \
560 O(BindM, ONE(MA), V_MMANY, ONE(VV), NF) \
561 O(UnsetL, ONE(LA), NOV, NOV, NF) \
562 O(UnsetN, NA, ONE(CV), NOV, NF) \
563 O(UnsetG, NA, ONE(CV), NOV, NF) \
564 O(UnsetM, ONE(MA), MMANY, NOV, NF) \
565 /* NOTE: isFPush below relies on the grouping of FPush* here */ \
566 O(FPushFunc, ONE(IVA), ONE(CV), NOV, NF) \
567 O(FPushFuncD, TWO(IVA,SA), NOV, NOV, NF) \
568 O(FPushFuncU, THREE(IVA,SA,SA), NOV, NOV, NF) \
569 O(FPushObjMethod, ONE(IVA), TWO(CV,CV), NOV, NF) \
570 O(FPushObjMethodD, TWO(IVA,SA), ONE(CV), NOV, NF) \
571 O(FPushClsMethod, ONE(IVA), TWO(AV,CV), NOV, NF) \
572 O(FPushClsMethodF, ONE(IVA), TWO(AV,CV), NOV, NF) \
573 O(FPushClsMethodD, THREE(IVA,SA,SA), NOV, NOV, NF) \
574 O(FPushCtor, ONE(IVA), ONE(AV), ONE(CV), NF) \
575 O(FPushCtorD, TWO(IVA,SA), NOV, ONE(CV), NF) \
576 O(FPushCufIter, TWO(IVA,IA), NOV, NOV, NF) \
577 O(FPushCuf, ONE(IVA), ONE(CV), NOV, NF) \
578 O(FPushCufF, ONE(IVA), ONE(CV), NOV, NF) \
579 O(FPushCufSafe, ONE(IVA), TWO(CV,CV), TWO(CV,CV), NF) \
580 O(FPassC, ONE(IVA), ONE(CV), ONE(FV), FF) \
581 O(FPassCW, ONE(IVA), ONE(CV), ONE(FV), FF) \
582 O(FPassCE, ONE(IVA), ONE(CV), ONE(FV), FF) \
583 O(FPassV, ONE(IVA), ONE(VV), ONE(FV), FF) \
584 O(FPassVNop, ONE(IVA), ONE(VV), ONE(FV), FF) \
585 O(FPassR, ONE(IVA), ONE(RV), ONE(FV), FF) \
586 O(FPassL, TWO(IVA,LA), NOV, ONE(FV), FF) \
587 O(FPassN, ONE(IVA), ONE(CV), ONE(FV), FF) \
588 O(FPassG, ONE(IVA), ONE(CV), ONE(FV), FF) \
589 O(FPassS, ONE(IVA), TWO(AV,CV), ONE(FV), FF) \
590 O(FPassM, TWO(IVA,MA), MMANY, ONE(FV), FF) \
591 O(FCall, ONE(IVA), FMANY, ONE(RV), CF_FF) \
592 O(FCallArray, NA, ONE(FV), ONE(RV), CF_FF) \
593 O(FCallBuiltin, THREE(IVA,IVA,SA),CVUMANY, ONE(RV), CF) \
594 O(CufSafeArray, NA, THREE(RV,CV,CV), ONE(CV), NF) \
595 O(CufSafeReturn, NA, THREE(RV,CV,CV), ONE(RV), NF) \
596 O(IterInit, THREE(IA,BA,LA), ONE(CV), NOV, CF) \
597 O(MIterInit, THREE(IA,BA,LA), ONE(VV), NOV, CF) \
598 O(WIterInit, THREE(IA,BA,LA), ONE(CV), NOV, CF) \
599 O(IterInitK, FOUR(IA,BA,LA,LA),ONE(CV), NOV, CF) \
600 O(MIterInitK, FOUR(IA,BA,LA,LA),ONE(VV), NOV, CF) \
601 O(WIterInitK, FOUR(IA,BA,LA,LA),ONE(CV), NOV, CF) \
602 O(IterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
603 O(MIterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
604 O(WIterNext, THREE(IA,BA,LA), NOV, NOV, CF) \
605 O(IterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
606 O(MIterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
607 O(WIterNextK, FOUR(IA,BA,LA,LA),NOV, NOV, CF) \
608 O(DecodeCufIter, TWO(IA,BA), ONE(CV), NOV, CF) \
609 O(IterFree, ONE(IA), NOV, NOV, NF) \
610 O(MIterFree, ONE(IA), NOV, NOV, NF) \
611 O(CIterFree, ONE(IA), NOV, NOV, NF) \
612 O(IterBreak, TWO(ILA,BA), NOV, NOV, CF_TF) \
613 O(Incl, NA, ONE(CV), ONE(CV), CF) \
614 O(InclOnce, NA, ONE(CV), ONE(CV), CF) \
615 O(Req, NA, ONE(CV), ONE(CV), CF) \
616 O(ReqOnce, NA, ONE(CV), ONE(CV), CF) \
617 O(ReqDoc, NA, ONE(CV), ONE(CV), CF) \
618 O(Eval, NA, ONE(CV), ONE(CV), CF) \
619 O(DefFunc, ONE(IVA), NOV, NOV, NF) \
620 O(DefCls, ONE(IVA), NOV, NOV, NF) \
621 O(NopDefCls, ONE(IVA), NOV, NOV, NF) \
622 O(DefCns, ONE(SA), ONE(CV), ONE(CV), NF) \
623 O(DefTypeAlias, ONE(IVA), NOV, NOV, NF) \
624 O(This, NA, NOV, ONE(CV), NF) \
625 O(BareThis, ONE(OA), NOV, ONE(CV), NF) \
626 O(CheckThis, NA, NOV, NOV, NF) \
627 O(InitThisLoc, ONE(IVA), NOV, NOV, NF) \
628 O(StaticLoc, TWO(IVA,SA), NOV, ONE(CV), NF) \
629 O(StaticLocInit, TWO(IVA,SA), ONE(CV), NOV, NF) \
630 O(Catch, NA, NOV, ONE(CV), NF) \
631 O(ClassExists, NA, TWO(CV,CV), ONE(CV), NF) \
632 O(InterfaceExists, NA, TWO(CV,CV), ONE(CV), NF) \
633 O(TraitExists, NA, TWO(CV,CV), ONE(CV), NF) \
634 O(VerifyParamType, ONE(IVA), NOV, NOV, NF) \
635 O(Self, NA, NOV, ONE(AV), NF) \
636 O(Parent, NA, NOV, ONE(AV), NF) \
637 O(LateBoundCls, NA, NOV, ONE(AV), NF) \
638 O(NativeImpl, NA, NOV, NOV, CF_TF) \
639 O(CreateCl, TWO(IVA,SA), CVMANY, ONE(CV), NF) \
640 O(CreateCont, NA, NOV, ONE(CV), NF) \
641 O(ContEnter, NA, ONE(CV), NOV, CF) \
642 O(UnpackCont, NA, NOV, TWO(CV,CV), NF) \
643 O(ContSuspend, ONE(IVA), ONE(CV), NOV, CF_TF) \
644 O(ContSuspendK, ONE(IVA), TWO(CV,CV), NOV, CF_TF) \
645 O(ContRetC, NA, ONE(CV), NOV, CF_TF) \
646 O(ContCheck, ONE(IVA), NOV, NOV, NF) \
647 O(ContRaise, NA, NOV, NOV, NF) \
648 O(ContValid, NA, NOV, ONE(CV), NF) \
649 O(ContKey, NA, NOV, ONE(CV), NF) \
650 O(ContCurrent, NA, NOV, ONE(CV), NF) \
651 O(ContStopped, NA, NOV, NOV, NF) \
652 O(ContHandle, NA, ONE(CV), NOV, CF_TF) \
653 O(AsyncAwait, NA, ONE(CV), TWO(CV,CV), NF) \
654 O(AsyncESuspend, TWO(IVA,IVA), ONE(CV), ONE(CV), NF) \
655 O(AsyncWrapResult, NA, ONE(CV), ONE(CV), NF) \
656 O(AsyncWrapException, NA, ONE(CV), ONE(CV), NF) \
657 O(Strlen, NA, ONE(CV), ONE(CV), NF) \
658 O(IncStat, TWO(IVA,IVA), NOV, NOV, NF) \
659 O(Abs, NA, ONE(CV), ONE(CV), NF) \
660 O(Idx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
661 O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
662 O(Floor, NA, ONE(CV), ONE(CV), NF) \
663 O(Ceil, NA, ONE(CV), ONE(CV), NF) \
664 O(HighInvalid, NA, NOV, NOV, NF) \
666 enum class Op : uint8_t {
667 #define O(name, ...) name,
671 auto constexpr Op_count
= uint8_t(Op::HighInvalid
) + 1;
673 /* Also put Op* in the enclosing namespace, to avoid having to change
674 * every existing usage site of the enum values. */
675 #define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
679 inline constexpr bool operator<(Op a
, Op b
) { return uint8_t(a
) < uint8_t(b
); }
680 inline constexpr bool operator>(Op a
, Op b
) { return uint8_t(a
) > uint8_t(b
); }
681 inline constexpr bool operator<=(Op a
, Op b
) {
682 return uint8_t(a
) <= uint8_t(b
);
684 inline constexpr bool operator>=(Op a
, Op b
) {
685 return uint8_t(a
) >= uint8_t(b
);
688 inline bool isValidOpcode(Op op
) {
689 return op
> OpLowInvalid
&& op
< OpHighInvalid
;
692 inline Op
toOp(Opcode o
) {
694 assert(isValidOpcode(op
));
698 const MInstrInfo
& getMInstrInfo(Op op
);
701 OpAstubStart
= Op_count
-1,
702 #define O(name, imm, pop, push, flags) OpAstub##name,
708 #define HIGH_OPCODES \
714 OpHighStart
= OpAstubCount
-1,
715 #define O(name) Op##name,
726 explicit ImmVector() : m_start(0) {}
728 explicit ImmVector(const uint8_t* start
,
732 , m_numStack(numStack
)
737 * Returns an ImmVector from a pointer to the immediate vector
738 * itself. Use getImmVector() if you want to get it from an Opcode*
739 * that points to the opcode.
741 static ImmVector
createFromStream(const uint8_t* opcode
) {
742 int32_t size
= reinterpret_cast<const int32_t*>(opcode
)[0];
743 int32_t stackCount
= reinterpret_cast<const int32_t*>(opcode
)[1];
744 const uint8_t* start
= opcode
+ sizeof(int32_t) + sizeof(int32_t);
745 return ImmVector(start
, size
, stackCount
);
749 * Returns an ImmVector of 32-bit ints from a pointer to the
750 * immediate vector itself.
752 static ImmVector
createFromStream(const int32_t* stream
) {
753 int32_t size
= stream
[0];
754 return ImmVector(reinterpret_cast<const uint8_t*>(stream
+ 1), size
, 0);
757 bool isValid() const { return m_start
!= 0; }
759 const uint8_t* vec() const { return m_start
; }
760 const int32_t* vec32() const {
761 return reinterpret_cast<const int32_t*>(m_start
);
763 const StrVecItem
* strvec() const {
764 return reinterpret_cast<const StrVecItem
*>(m_start
);
767 LocationCode
locationCode() const { return LocationCode(*vec()); }
770 * Returns the length of the immediate vector in bytes (for M
771 * vectors) or elements (for switch vectors)
773 int32_t size() const { return m_length
; }
776 * Returns the number of elements on the execution stack that this
777 * vector will need to access. (Includes stack elements for both
778 * the base and members.)
780 int numStackValues() const { return m_numStack
; }
783 * Returns a pointer to the last member code in the vector.
785 * Requires: isValid() && size() >= 1
787 const uint8_t* findLastMember() const;
790 * Decode the terminating string immediate, if any.
792 bool decodeLastMember(const Unit
*, StringData
*& sdOut
,
794 int64_t* strIdOut
= nullptr) const;
800 const uint8_t* m_start
;
803 // Must be an opcode that actually has an ImmVector.
804 ImmVector
getImmVector(const Op
* opcode
);
806 struct MInstrLocation
{
810 bool hasImm() const {
811 auto count
= numLocationCodeImms(lcode
);
812 assert(count
== 0 || count
== 1);
816 MInstrLocation
getMLocation(const Op
* opcode
);
822 bool hasImm() const {
823 return memberCodeHasImm(mcode
);
826 bool hasMVector(Op op
);
827 std::vector
<MVectorItem
> getMVector(const Op
* opcode
);
829 /* Some decoding helper functions. */
830 int numImmediates(Op opcode
);
831 ArgType
immType(Op opcode
, int idx
);
832 int immSize(const Op
* opcode
, int idx
);
833 bool immIsVector(Op opcode
, int idx
);
834 bool hasImmVector(Op opcode
);
835 inline bool isTypePred(const Op op
) {
836 return op
== OpIsTypeC
|| op
== OpIsTypeL
;
838 int instrLen(const Op
* opcode
);
839 int numSuccs(const Op
* opcode
);
840 bool pushesActRec(Op opcode
);
842 // The returned struct has normalized variable-sized immediates
843 ArgUnion
getImm(const Op
* opcode
, int idx
);
844 // Don't use this with variable-sized immediates!
845 ArgUnion
* getImmPtr(const Op
* opcode
, int idx
);
847 // Pass a pointer to the pointer to the immediate; this function will advance
848 // the pointer past the immediate
850 int32_t decodeVariableSizeImm(const unsigned char** immPtr
) {
851 const unsigned char small
= **immPtr
;
852 if (UNLIKELY(small
& 0x1)) {
853 const unsigned int large
= *((const unsigned int*)*immPtr
);
854 *immPtr
+= sizeof(large
);
855 return (int32_t)(large
>> 1);
857 *immPtr
+= sizeof(small
);
858 return (int32_t)(small
>> 1);
862 int64_t decodeMemberCodeImm(const unsigned char** immPtr
, MemberCode mcode
);
864 // Encodes a variable sized immediate for `val' into `buf'. Returns
865 // the number of bytes used taken. At most 4 bytes can be used.
866 size_t encodeVariableSizeImm(int32_t val
, unsigned char* buf
);
868 // Encodes a variable sized immediate to the end of vec.
869 void encodeIvaToVector(std::vector
<uchar
>& vec
, int32_t val
);
872 void encodeToVector(std::vector
<uchar
>& vec
, T val
) {
873 size_t currentLen
= vec
.size();
874 vec
.resize(currentLen
+ sizeof(T
));
875 memcpy(&vec
[currentLen
], &val
, sizeof(T
));
878 void staticStreamer(const TypedValue
* tv
, std::stringstream
& out
);
880 std::string
instrToString(const Op
* it
, const Unit
* u
= nullptr);
881 void staticArrayStreamer(ArrayData
*, std::ostream
&);
882 const char* opcodeToName(Op op
);
884 // returns a pointer to the location within the bytecode containing the jump
885 // Offset, or NULL if the instruction cannot jump. Note that this offset is
886 // relative to the current instruction.
887 Offset
* instrJumpOffset(Op
* instr
);
889 // returns absolute address of target, or InvalidAbsoluteOffset if instruction
891 Offset
instrJumpTarget(const Op
* instrs
, Offset pos
);
893 struct StackTransInfo
{
904 bool instrIsNonCallControlFlow(Op opcode
);
905 bool instrAllowsFallThru(Op opcode
);
906 bool instrReadsCurrentFpi(Op opcode
);
908 constexpr InstrFlags instrFlagsData
[] = {
909 #define O(unusedName, unusedImm, unusedPop, unusedPush, flags) flags,
914 constexpr inline InstrFlags
instrFlags(Op opcode
) {
915 return instrFlagsData
[uint8_t(opcode
)];
918 constexpr inline bool instrIsControlFlow(Op opcode
) {
919 return (instrFlags(opcode
) & CF
) != 0;
922 inline bool isFPush(Op opcode
) {
923 return opcode
>= OpFPushFunc
&& opcode
<= OpFPushCufSafe
;
926 inline bool isFCallStar(Op opcode
) {
937 inline bool isFPassStar(Op opcode
) {
956 inline bool isLiteral(Op op
) {
973 inline bool isThisSelfOrParent(Op op
) {
985 inline bool isRet(Op op
) {
996 inline bool isSwitch(Op op
) {
1007 inline bool isSwitch(Opcode op
) {
1008 return isSwitch(toOp(op
));
1011 template<typename L
>
1012 void foreachSwitchTarget(const Op
* op
, L func
) {
1013 assert(isSwitch(*op
));
1014 bool isStr
= readData
<Op
>(op
) == OpSSwitch
;
1015 int32_t size
= readData
<int32_t>(op
);
1016 for (int i
= 0; i
< size
; ++i
) {
1017 if (isStr
) readData
<Id
>(op
);
1018 func(readData
<Offset
>(op
));
1022 template<typename L
>
1023 void foreachSwitchString(Opcode
* op
, L func
) {
1024 assert(toOp(*op
) == OpSSwitch
);
1025 readData
<Opcode
>(op
);
1026 int32_t size
= readData
<int32_t>(op
) - 1; // the last item is the default
1027 for (int i
= 0; i
< size
; ++i
) {
1028 func(readData
<Id
>(op
));
1029 readData
<Offset
>(op
);
1033 int instrNumPops(const Op
* opcode
);
1034 int instrNumPushes(const Op
* opcode
);
1035 FlavorDesc
instrInputFlavor(const Op
* op
, uint32_t idx
);
1036 StackTransInfo
instrStackTransInfo(const Op
* opcode
);
1037 int instrSpToArDelta(const Op
* opcode
);
1040 mcodeIsLiteral(MemberCode mcode
) {
1041 return mcode
== MET
|| mcode
== MEI
|| mcode
== MPT
;
1045 mcodeMaybePropName(MemberCode mcode
) {
1046 return mcode
== MPC
|| mcode
== MPL
|| mcode
== MPT
;
1050 mcodeMaybeArrayOrMapKey(MemberCode mcode
) {
1051 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MET
|| mcode
== MEI
;
1055 mcodeMaybeArrayStringKey(MemberCode mcode
) {
1056 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MET
;
1060 mcodeMaybeArrayIntKey(MemberCode mcode
) {
1061 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MEI
;
1065 mcodeMaybeVectorKey(MemberCode mcode
) {
1066 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MEI
;
1073 struct hash
<HPHP::Op
> {
1074 size_t operator()(HPHP::Op op
) const {
1075 return HPHP::hash_int64(uint8_t(op
));