Convert IsTypeOp to an enum class
[hiphop-php.git] / hphp / runtime / vm / hhbc.h
blob865095a66efd181c3312246076db01a1b84f00d2
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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"
22 namespace HPHP {
24 struct Unit;
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
34 // ImmVectorO).
35 #define ARGTYPES \
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 */
52 enum ArgType {
53 #define ARGTYPE(name, type) name,
54 #define ARGTYPEVEC(name, type) name,
55 ARGTYPES
56 #undef ARGTYPE
57 #undef ARGTYPEVEC
60 union ArgUnion {
61 char bytes[0];
62 #define ARGTYPE(name, type) type u_##name;
63 #define ARGTYPEVEC(name, type) type u_##name;
64 ARGTYPES
65 #undef ARGTYPE
66 #undef ARGTYPEVEC
69 const Offset InvalidAbsoluteOffset = -1;
71 enum FlavorDesc {
72 NOV, // None
73 CV, // Cell
74 VV, // Var
75 AV, // Classref
76 RV, // Return value (cell or var)
77 FV, // Function parameter (cell or var)
78 UV, // Uninit
79 CVV, // Cell or Var argument
80 CVUV, // Cell, Var, or Uninit argument
83 enum InstrFlags {
84 NF = 0x0, // No flags
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
89 CF_TF = (CF | TF),
90 CF_FF = (CF | FF)
93 enum LocationCode {
94 // Base is the object stored in a local, a cell, or $this
95 LL,
96 LC,
97 LH,
99 // Base is the global name referred to by a cell or a local.
100 LGL,
101 LGC,
103 // Base is the name of a local, given by a cell or the value of a
104 // local.
105 LNL,
106 LNC,
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.
114 LSL,
115 LSC,
117 // Base is a function return value.
120 NumLocationCodes,
121 InvalidLocationCode = NumLocationCodes
124 inline int numLocationCodeImms(LocationCode lc) {
125 switch (lc) {
126 case LL: case LGL: case LNL: case LSL:
127 return 1;
128 case LC: case LH: case LGC: case LNC: case LSC: case LR:
129 return 0;
130 default:
131 not_reached();
135 inline int numLocationCodeStackVals(LocationCode lc) {
136 switch (lc) {
137 case LL: case LH: case LGL: case LNL:
138 return 0;
139 case LC: case LGC: case LNC: case LSL: case LR:
140 return 1;
141 case LSC:
142 return 2;
143 default:
144 not_reached();
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);
158 enum MemberCode {
159 // Element and property, consuming a cell from the stack.
160 MEC,
161 MPC,
163 // Element and property, using an immediate local id.
164 MEL,
165 MPL,
167 // Element and property, using a string immediate
168 MET,
169 MPT,
171 // Element, using an int64 immediate
172 MEI,
174 // New element operation. (No real stack element.)
177 NumMemberCodes,
178 InvalidMemberCode = NumMemberCodes
181 enum MInstrAttr {
182 MIA_none = 0x00,
183 MIA_warn = 0x01,
184 MIA_define = 0x02,
185 MIA_reffy = 0x04,
186 MIA_unset = 0x08,
187 MIA_new = 0x10,
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.
196 MIA_more_warn =
197 #ifdef HHVM_MORE_WARNINGS
198 MIA_warn
199 #else
200 MIA_none
201 #endif
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
210 #define MINSTRS \
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)
229 enum MInstr {
230 #define MII(instr, attrs, bS, iS, vC, fN) \
231 MI_##instr##M,
232 MINSTRS
233 #undef MII
236 struct MInstrInfo {
237 MInstr m_instr;
238 MInstrAttr m_baseOps[NumLocationCodes];
239 MInstrAttr m_intermediateOps[NumMemberCodes];
240 unsigned m_valCount;
241 bool m_newElem;
242 bool m_finalGet;
243 const char* m_name;
245 MInstr instr() const {
246 return m_instr;
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 {
260 return m_valCount;
263 bool newElem() const {
264 return m_newElem;
267 bool finalGet() const {
268 return m_finalGet;
271 const char* name() const {
272 return m_name;
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) {
289 return mc == MEI;
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;
298 not_reached();
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*);
313 #define INCDEC_OPS \
314 INCDEC_OP(PreInc) \
315 INCDEC_OP(PostInc) \
316 INCDEC_OP(PreDec) \
317 INCDEC_OP(PostDec)
319 enum IncDecOp {
320 #define INCDEC_OP(incDecOp) incDecOp,
321 INCDEC_OPS
322 #undef INCDEC_OP
323 IncDec_invalid
326 #define IS_TYPE_OPS \
327 IS_TYPE_OP(Null) \
328 IS_TYPE_OP(Bool) \
329 IS_TYPE_OP(Int) \
330 IS_TYPE_OP(Dbl) \
331 IS_TYPE_OP(Str) \
332 IS_TYPE_OP(Arr) \
333 IS_TYPE_OP(Obj)
335 enum class IsTypeOp : uint8_t {
336 #define IS_TYPE_OP(op) op,
337 IS_TYPE_OPS
338 #undef IS_TYPE_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 \
344 ASSERTT_OP(Uninit) \
345 ASSERTT_OP(InitNull) \
346 ASSERTT_OP(Null) \
347 ASSERTT_OP(Int) \
348 ASSERTT_OP(OptInt) \
349 ASSERTT_OP(Dbl) \
350 ASSERTT_OP(OptDbl) \
351 ASSERTT_OP(Res) \
352 ASSERTT_OP(OptRes) \
353 ASSERTT_OP(Bool) \
354 ASSERTT_OP(OptBool) \
355 ASSERTT_OP(SStr) \
356 ASSERTT_OP(OptSStr) \
357 ASSERTT_OP(Str) \
358 ASSERTT_OP(OptStr) \
359 ASSERTT_OP(SArr) \
360 ASSERTT_OP(OptSArr) \
361 ASSERTT_OP(Arr) \
362 ASSERTT_OP(OptArr) \
363 ASSERTT_OP(Obj) \
364 ASSERTT_OP(OptObj) \
365 ASSERTT_OP(InitUnc) \
366 ASSERTT_OP(Unc) \
367 ASSERTT_OP(InitCell) \
368 ASSERTT_OP(Cell) \
369 ASSERTT_OP(Ref)
371 enum class AssertTOp : uint8_t {
372 #define ASSERTT_OP(op) op,
373 ASSERTT_OPS
374 #undef ASSERTT_OP
377 enum IterKind {
378 KindOfIter = 0,
379 KindOfMIter = 1,
380 KindOfCIter = 2,
383 #define FATAL_OPS \
384 FATAL_OP(Runtime) \
385 FATAL_OP(Parse) \
386 FATAL_OP(RuntimeOmitFrame)
388 enum class FatalOp : uint8_t {
389 #define FATAL_OP(x) x,
390 FATAL_OPS
391 #undef FATAL_OP
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.
397 #define SETOP_OPS \
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)
410 enum SetOpOp {
411 #define SETOP_OP(setOpOp, bcOp) SetOp##setOpOp,
412 SETOP_OPS
413 #undef SETOP_OP
414 SetOp_invalid
417 // name immediates inputs outputs flags
418 #define OPCODES \
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,
668 OPCODES
669 #undef O
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;
676 OPCODES
677 #undef O
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) {
693 Op op = Op(o);
694 assert(isValidOpcode(op));
695 return op;
698 const MInstrInfo& getMInstrInfo(Op op);
700 enum AstubsOp {
701 OpAstubStart = Op_count-1,
702 #define O(name, imm, pop, push, flags) OpAstub##name,
703 OPCODES
704 #undef O
705 OpAstubCount
708 #define HIGH_OPCODES \
709 O(FuncPrologue) \
710 O(TraceletGuard) \
711 O(NativeTrampoline)
713 enum HighOp {
714 OpHighStart = OpAstubCount-1,
715 #define O(name) Op##name,
716 HIGH_OPCODES
717 #undef O
720 struct StrVecItem {
721 Id str;
722 Offset dest;
725 struct ImmVector {
726 explicit ImmVector() : m_start(0) {}
728 explicit ImmVector(const uint8_t* start,
729 int32_t length,
730 int32_t numStack)
731 : m_length(length)
732 , m_numStack(numStack)
733 , m_start(start)
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,
793 MemberCode& membOut,
794 int64_t* strIdOut = nullptr) const;
797 private:
798 int32_t m_length;
799 int32_t m_numStack;
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 {
807 LocationCode lcode;
808 int64_t imm;
810 bool hasImm() const {
811 auto count = numLocationCodeImms(lcode);
812 assert(count == 0 || count == 1);
813 return count;
816 MInstrLocation getMLocation(const Op* opcode);
818 struct MVectorItem {
819 MemberCode mcode;
820 int64_t imm;
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
849 ALWAYS_INLINE
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);
856 } else {
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);
871 template<typename T>
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
890 // cannot jump
891 Offset instrJumpTarget(const Op* instrs, Offset pos);
893 struct StackTransInfo {
894 enum class Kind {
895 PushPop,
896 InsertMid
898 Kind kind;
899 int numPops;
900 int numPushes;
901 int pos;
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,
910 OPCODES
911 #undef O
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) {
927 switch (opcode) {
928 case OpFCall:
929 case OpFCallArray:
930 return true;
932 default:
933 return false;
937 inline bool isFPassStar(Op opcode) {
938 switch (opcode) {
939 case OpFPassC:
940 case OpFPassCW:
941 case OpFPassCE:
942 case OpFPassV:
943 case OpFPassR:
944 case OpFPassL:
945 case OpFPassN:
946 case OpFPassG:
947 case OpFPassS:
948 case OpFPassM:
949 return true;
951 default:
952 return false;
956 inline bool isLiteral(Op op) {
957 switch (op) {
958 case OpNull:
959 case OpNullUninit:
960 case OpTrue:
961 case OpFalse:
962 case OpInt:
963 case OpDouble:
964 case OpString:
965 case OpArray:
966 return true;
968 default:
969 return false;
973 inline bool isThisSelfOrParent(Op op) {
974 switch (op) {
975 case OpThis:
976 case OpSelf:
977 case OpParent:
978 return true;
980 default:
981 return false;
985 inline bool isRet(Op op) {
986 switch (op) {
987 case OpRetC:
988 case OpRetV:
989 return true;
991 default:
992 return false;
996 inline bool isSwitch(Op op) {
997 switch (op) {
998 case OpSwitch:
999 case OpSSwitch:
1000 return true;
1002 default:
1003 return false;
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);
1039 inline bool
1040 mcodeIsLiteral(MemberCode mcode) {
1041 return mcode == MET || mcode == MEI || mcode == MPT;
1044 inline bool
1045 mcodeMaybePropName(MemberCode mcode) {
1046 return mcode == MPC || mcode == MPL || mcode == MPT;
1049 inline bool
1050 mcodeMaybeArrayOrMapKey(MemberCode mcode) {
1051 return mcode == MEC || mcode == MEL || mcode == MET || mcode == MEI;
1054 inline bool
1055 mcodeMaybeArrayStringKey(MemberCode mcode) {
1056 return mcode == MEC || mcode == MEL || mcode == MET;
1059 inline bool
1060 mcodeMaybeArrayIntKey(MemberCode mcode) {
1061 return mcode == MEC || mcode == MEL || mcode == MEI;
1064 inline bool
1065 mcodeMaybeVectorKey(MemberCode mcode) {
1066 return mcode == MEC || mcode == MEL || mcode == MEI;
1071 namespace std {
1072 template<>
1073 struct hash<HPHP::Op> {
1074 size_t operator()(HPHP::Op op) const {
1075 return HPHP::hash_int64(uint8_t(op));
1080 #endif