Add inlining support to the tracelet region selector
[hiphop-php.git] / hphp / runtime / vm / hhbc.h
blobfb4b5988fc084ae7da4bde08897f51a5a380a68a
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 address vector immediate */ \
39 ARGTYPEVEC(SLA,Id) /* litstrid/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(HA, int32_t) /* Local variable ID: 8 or 32-bit int */ \
44 /* TODO(jdelong): rename HA to LA */ \
45 ARGTYPE(IA, int32_t) /* Iterator variable ID: 8 or 32-bit int */ \
46 ARGTYPE(DA, double) /* Double */ \
47 ARGTYPE(SA, Id) /* litStr ID */ \
48 ARGTYPE(AA, Id) /* static array ID */ \
49 ARGTYPE(BA, Offset) /* Bytecode address */ \
50 ARGTYPE(OA, unsigned char) /* Opcode */
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 = 0, // None
73 CV = 1, // Cell
74 VV = 2, // Var
75 AV = 3, // Classref
76 RV = 4, // Return value (cell or var)
77 FV = 5, // Function parameter (cell or var)
78 CVV = 6, // Cell or Var argument
81 enum InstrFlags {
82 NF = 0x0, // No flags
83 TF = 0x1, // Next instruction is not reachable via fall through or return
84 CF = 0x2, // Control flow instruction (branch, call, return, throw, etc)
85 FF = 0x4, // Instruction uses current FPI
86 CF_TF = (CF | TF),
87 CF_FF = (CF | FF)
90 enum LocationCode {
91 // Base is the object stored in a local, a cell, or $this
92 LL,
93 LC,
94 LH,
96 // Base is the global name referred to by a cell or a local.
97 LGL,
98 LGC,
100 // Base is the name of a local, given by a cell or the value of a
101 // local.
102 LNL,
103 LNC,
106 * Base is a static property member of a class. The S-vector takes
107 * two things to define a base. The classref portion comes at the
108 * end of the M-vector, and the property name can be defined by
109 * either a cell or a local immediate.
111 LSL,
112 LSC,
114 // Base is a function return value.
117 NumLocationCodes,
118 InvalidLocationCode = NumLocationCodes
121 inline int numLocationCodeImms(LocationCode lc) {
122 switch (lc) {
123 case LL: case LGL: case LNL: case LSL:
124 return 1;
125 case LC: case LH: case LGC: case LNC: case LSC: case LR:
126 return 0;
127 default:
128 not_reached();
132 inline int numLocationCodeStackVals(LocationCode lc) {
133 switch (lc) {
134 case LL: case LH: case LGL: case LNL:
135 return 0;
136 case LC: case LGC: case LNC: case LSL: case LR:
137 return 1;
138 case LSC:
139 return 2;
140 default:
141 not_reached();
145 // Returns string representation of `lc'. (Pointer to internal static
146 // data, does not need to be freed.)
147 const char* locationCodeString(LocationCode lc);
149 // Grok a LocationCode from a string---if the string doesn't represent
150 // a location code, returns InvalidLocationCode. This looks at at
151 // most the first two bytes in `s'---the parse will not fail if there
152 // is more junk after the first two bytes.
153 LocationCode parseLocationCode(const char* s);
155 enum MemberCode {
156 // Element and property, consuming a cell from the stack.
157 MEC,
158 MPC,
160 // Element and property, using an immediate local id.
161 MEL,
162 MPL,
164 // Element and property, using a string immediate
165 MET,
166 MPT,
168 // Element, using an int64 immediate
169 MEI,
171 // New element operation. (No real stack element.)
174 NumMemberCodes,
175 InvalidMemberCode = NumMemberCodes
178 enum MInstrAttr {
179 MIA_none = 0x00,
180 MIA_warn = 0x01,
181 MIA_define = 0x02,
182 MIA_reffy = 0x04,
183 MIA_unset = 0x08,
184 MIA_new = 0x10,
185 MIA_final_get = 0x20,
186 MIA_base = MIA_warn | MIA_define,
187 MIA_intermediate = MIA_warn | MIA_define | MIA_reffy | MIA_unset,
188 MIA_intermediate_prop = MIA_warn | MIA_define | MIA_unset,
189 MIA_final = MIA_new | MIA_final_get,
191 // Some warnings may conditionally be built for Zend compatibility,
192 // but are off by default.
193 MIA_more_warn =
194 #ifdef HHVM_MORE_WARNINGS
195 MIA_warn
196 #else
197 MIA_none
198 #endif
201 // MII(instr, * in *M
202 // attrs, operation attributes
203 // bS, base operation suffix
204 // iS, intermediate operation suffix
205 // vC, final value count (0 or 1)
206 // fN) final new element operation name
207 #define MINSTRS \
208 MII(CGet, MIA_warn|MIA_final_get, W, W, 0, NotSuppNewElem) \
209 MII(VGet, MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
210 D, D, 0, VGetNewElem) \
211 MII(Isset, MIA_final_get, , , 0, NotSuppNewElem) \
212 MII(Empty, MIA_final_get, , , 0, NotSuppNewElem) \
213 MII(Set, MIA_define|MIA_new, D, D, 1, SetNewElem) \
214 MII(SetOp, MIA_more_warn|MIA_define|MIA_new|MIA_final_get, \
215 WD, WD, 1, SetOpNewElem) \
216 MII(IncDec, MIA_more_warn|MIA_define|MIA_new|MIA_final_get, \
217 WD, WD, 0, IncDecNewElem) \
218 MII(Bind, MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
219 D, D, 1, BindNewElem) \
220 MII(Unset, MIA_unset, , U, 0, NotSuppNewElem) \
221 MII(SetWithRefL,MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
222 D, D, 1, SetWithRefNewElem) \
223 MII(SetWithRefR,MIA_define|MIA_reffy|MIA_new|MIA_final_get, \
224 D, D, 1, SetWithRefNewElem)
226 enum MInstr {
227 #define MII(instr, attrs, bS, iS, vC, fN) \
228 MI_##instr##M,
229 MINSTRS
230 #undef MII
233 struct MInstrInfo {
234 MInstr m_instr;
235 MInstrAttr m_baseOps[NumLocationCodes];
236 MInstrAttr m_intermediateOps[NumMemberCodes];
237 unsigned m_valCount;
238 bool m_newElem;
239 bool m_finalGet;
240 const char* m_name;
242 MInstr instr() const {
243 return m_instr;
246 const MInstrAttr& getAttr(LocationCode lc) const {
247 assert(lc < NumLocationCodes);
248 return m_baseOps[lc];
251 const MInstrAttr& getAttr(MemberCode mc) const {
252 assert(mc < NumMemberCodes);
253 return m_intermediateOps[mc];
256 unsigned valCount() const {
257 return m_valCount;
260 bool newElem() const {
261 return m_newElem;
264 bool finalGet() const {
265 return m_finalGet;
268 const char* name() const {
269 return m_name;
273 inline bool memberCodeHasImm(MemberCode mc) {
274 return mc == MEL || mc == MPL || mc == MET || mc == MPT || mc == MEI;
277 inline bool memberCodeImmIsLoc(MemberCode mc) {
278 return mc == MEL || mc == MPL;
281 inline bool memberCodeImmIsString(MemberCode mc) {
282 return mc == MET || mc == MPT;
285 inline bool memberCodeImmIsInt(MemberCode mc) {
286 return mc == MEI;
289 // Returns string representation of `mc'. (Pointer to internal static
290 // data, does not need to be freed.)
291 const char* memberCodeString(MemberCode mc);
293 // Same semantics as parseLocationCode, but for member codes.
294 MemberCode parseMemberCode(const char*);
296 #define INCDEC_OPS \
297 INCDEC_OP(PreInc) \
298 INCDEC_OP(PostInc) \
299 INCDEC_OP(PreDec) \
300 INCDEC_OP(PostDec)
302 enum IncDecOp {
303 #define INCDEC_OP(incDecOp) incDecOp,
304 INCDEC_OPS
305 #undef INCDEC_OP
306 IncDec_invalid
309 enum IterKind {
310 KindOfIter = 0,
311 KindOfMIter = 1,
312 KindOfCIter = 2,
315 // Each of the setop ops maps to a binary bytecode op. We have reasons
316 // for using distinct bitwise representations, though. This macro records
317 // their correspondence for mapping either direction.
318 #define SETOP_OPS \
319 SETOP_OP(PlusEqual, OpAdd) \
320 SETOP_OP(MinusEqual, OpSub) \
321 SETOP_OP(MulEqual, OpMul) \
322 SETOP_OP(ConcatEqual, OpConcat) \
323 SETOP_OP(DivEqual, OpDiv) \
324 SETOP_OP(ModEqual, OpMod) \
325 SETOP_OP(AndEqual, OpBitAnd) \
326 SETOP_OP(OrEqual, OpBitOr) \
327 SETOP_OP(XorEqual, OpBitXor) \
328 SETOP_OP(SlEqual, OpShl) \
329 SETOP_OP(SrEqual, OpShr)
331 enum SetOpOp {
332 #define SETOP_OP(setOpOp, bcOp) SetOp##setOpOp,
333 SETOP_OPS
334 #undef SETOP_OP
335 SetOp_invalid
338 // name immediates inputs outputs flags
339 #define OPCODES \
340 O(LowInvalid, NA, NOV, NOV, NF) \
341 O(Nop, NA, NOV, NOV, NF) \
342 O(PopC, NA, ONE(CV), NOV, NF) \
343 O(PopV, NA, ONE(VV), NOV, NF) \
344 O(PopR, NA, ONE(RV), NOV, NF) \
345 O(Dup, NA, ONE(CV), TWO(CV,CV), NF) \
346 O(Box, NA, ONE(CV), ONE(VV), NF) \
347 O(Unbox, NA, ONE(VV), ONE(CV), NF) \
348 O(BoxR, NA, ONE(RV), ONE(VV), NF) \
349 O(UnboxR, NA, ONE(RV), ONE(CV), NF) \
350 O(Null, NA, NOV, ONE(CV), NF) \
351 O(NullUninit, NA, NOV, ONE(CV), NF) \
352 O(True, NA, NOV, ONE(CV), NF) \
353 O(False, NA, NOV, ONE(CV), NF) \
354 O(Int, ONE(I64A), NOV, ONE(CV), NF) \
355 O(Double, ONE(DA), NOV, ONE(CV), NF) \
356 O(String, ONE(SA), NOV, ONE(CV), NF) \
357 O(Array, ONE(AA), NOV, ONE(CV), NF) \
358 O(NewArray, NA, NOV, ONE(CV), NF) \
359 O(NewTuple, ONE(IVA), CMANY, ONE(CV), NF) \
360 O(AddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
361 O(AddElemV, NA, THREE(VV,CV,CV), ONE(CV), NF) \
362 O(AddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
363 O(AddNewElemV, NA, TWO(VV,CV), ONE(CV), NF) \
364 O(NewCol, TWO(IVA,IVA), NOV, ONE(CV), NF) \
365 O(ColAddElemC, NA, THREE(CV,CV,CV), ONE(CV), NF) \
366 O(ColAddNewElemC, NA, TWO(CV,CV), ONE(CV), NF) \
367 O(Cns, ONE(SA), NOV, ONE(CV), NF) \
368 O(CnsE, ONE(SA), NOV, ONE(CV), NF) \
369 O(CnsU, TWO(SA,SA), NOV, ONE(CV), NF) \
370 O(ClsCns, ONE(SA), ONE(AV), ONE(CV), NF) \
371 O(ClsCnsD, TWO(SA,SA), NOV, ONE(CV), NF) \
372 O(File, NA, NOV, ONE(CV), NF) \
373 O(Dir, NA, NOV, ONE(CV), NF) \
374 O(Concat, NA, TWO(CV,CV), ONE(CV), NF) \
375 O(Add, NA, TWO(CV,CV), ONE(CV), NF) \
376 O(Sub, NA, TWO(CV,CV), ONE(CV), NF) \
377 O(Mul, NA, TWO(CV,CV), ONE(CV), NF) \
378 O(Div, NA, TWO(CV,CV), ONE(CV), NF) \
379 O(Mod, NA, TWO(CV,CV), ONE(CV), NF) \
380 O(Sqrt, NA, ONE(CV), ONE(CV), NF) \
381 O(Xor, NA, TWO(CV,CV), ONE(CV), NF) \
382 O(Not, NA, ONE(CV), ONE(CV), NF) \
383 O(Same, NA, TWO(CV,CV), ONE(CV), NF) \
384 O(NSame, NA, TWO(CV,CV), ONE(CV), NF) \
385 O(Eq, NA, TWO(CV,CV), ONE(CV), NF) \
386 O(Neq, NA, TWO(CV,CV), ONE(CV), NF) \
387 O(Lt, NA, TWO(CV,CV), ONE(CV), NF) \
388 O(Lte, NA, TWO(CV,CV), ONE(CV), NF) \
389 O(Gt, NA, TWO(CV,CV), ONE(CV), NF) \
390 O(Gte, NA, TWO(CV,CV), ONE(CV), NF) \
391 O(BitAnd, NA, TWO(CV,CV), ONE(CV), NF) \
392 O(BitOr, NA, TWO(CV,CV), ONE(CV), NF) \
393 O(BitXor, NA, TWO(CV,CV), ONE(CV), NF) \
394 O(BitNot, NA, ONE(CV), ONE(CV), NF) \
395 O(Shl, NA, TWO(CV,CV), ONE(CV), NF) \
396 O(Shr, NA, TWO(CV,CV), ONE(CV), NF) \
397 O(CastBool, NA, ONE(CV), ONE(CV), NF) \
398 O(CastInt, NA, ONE(CV), ONE(CV), NF) \
399 O(CastDouble, NA, ONE(CV), ONE(CV), NF) \
400 O(CastString, NA, ONE(CV), ONE(CV), NF) \
401 O(CastArray, NA, ONE(CV), ONE(CV), NF) \
402 O(CastObject, NA, ONE(CV), ONE(CV), NF) \
403 O(InstanceOf, NA, TWO(CV,CV), ONE(CV), NF) \
404 O(InstanceOfD, ONE(SA), ONE(CV), ONE(CV), NF) \
405 O(Print, NA, ONE(CV), ONE(CV), NF) \
406 O(Clone, NA, ONE(CV), ONE(CV), NF) \
407 O(Exit, NA, ONE(CV), ONE(CV), NF) \
408 O(Fatal, ONE(IVA), ONE(CV), NOV, CF_TF) \
409 O(Jmp, ONE(BA), NOV, NOV, CF_TF) \
410 O(JmpZ, ONE(BA), ONE(CV), NOV, CF) \
411 O(JmpNZ, ONE(BA), ONE(CV), NOV, CF) \
412 O(Switch, THREE(BLA,I64A,IVA), \
413 ONE(CV), NOV, CF_TF) \
414 O(SSwitch, ONE(SLA), ONE(CV), NOV, CF_TF) \
415 O(RetC, NA, ONE(CV), NOV, CF_TF) \
416 O(RetV, NA, ONE(VV), NOV, CF_TF) \
417 O(Unwind, NA, NOV, NOV, CF_TF) \
418 O(Throw, NA, ONE(CV), NOV, CF_TF) \
419 O(CGetL, ONE(HA), NOV, ONE(CV), NF) \
420 O(CGetL2, ONE(HA), NOV, INS_1(CV), NF) \
421 O(CGetL3, ONE(HA), NOV, INS_2(CV), NF) \
422 O(CGetN, NA, ONE(CV), ONE(CV), NF) \
423 O(CGetG, NA, ONE(CV), ONE(CV), NF) \
424 O(CGetS, NA, TWO(AV,CV), ONE(CV), NF) \
425 O(CGetM, ONE(MA), LMANY(), ONE(CV), NF) \
426 O(VGetL, ONE(HA), NOV, ONE(VV), NF) \
427 O(VGetN, NA, ONE(CV), ONE(VV), NF) \
428 O(VGetG, NA, ONE(CV), ONE(VV), NF) \
429 O(VGetS, NA, TWO(AV,CV), ONE(VV), NF) \
430 O(VGetM, ONE(MA), LMANY(), ONE(VV), NF) \
431 O(AGetC, NA, ONE(CV), ONE(AV), NF) \
432 O(AGetL, ONE(HA), NOV, ONE(AV), NF) \
433 O(AKExists, NA, TWO(CV,CV), ONE(CV), NF) \
434 O(IssetL, ONE(HA), NOV, ONE(CV), NF) \
435 O(IssetN, NA, ONE(CV), ONE(CV), NF) \
436 O(IssetG, NA, ONE(CV), ONE(CV), NF) \
437 O(IssetS, NA, TWO(AV,CV), ONE(CV), NF) \
438 O(IssetM, ONE(MA), LMANY(), ONE(CV), NF) \
439 O(EmptyL, ONE(HA), NOV, ONE(CV), NF) \
440 O(EmptyN, NA, ONE(CV), ONE(CV), NF) \
441 O(EmptyG, NA, ONE(CV), ONE(CV), NF) \
442 O(EmptyS, NA, TWO(AV,CV), ONE(CV), NF) \
443 O(EmptyM, ONE(MA), LMANY(), ONE(CV), NF) \
444 /* NB: isTypePred depends on this ordering. */ \
445 O(IsNullC, NA, ONE(CV), ONE(CV), NF) \
446 O(IsBoolC, NA, ONE(CV), ONE(CV), NF) \
447 O(IsIntC, NA, ONE(CV), ONE(CV), NF) \
448 O(IsDoubleC, NA, ONE(CV), ONE(CV), NF) \
449 O(IsStringC, NA, ONE(CV), ONE(CV), NF) \
450 O(IsArrayC, NA, ONE(CV), ONE(CV), NF) \
451 O(IsObjectC, NA, ONE(CV), ONE(CV), NF) \
452 O(IsNullL, ONE(HA), NOV, ONE(CV), NF) \
453 O(IsBoolL, ONE(HA), NOV, ONE(CV), NF) \
454 O(IsIntL, ONE(HA), NOV, ONE(CV), NF) \
455 O(IsDoubleL, ONE(HA), NOV, ONE(CV), NF) \
456 O(IsStringL, ONE(HA), NOV, ONE(CV), NF) \
457 O(IsArrayL, ONE(HA), NOV, ONE(CV), NF) \
458 O(IsObjectL, ONE(HA), NOV, ONE(CV), NF) \
459 O(SetL, ONE(HA), ONE(CV), ONE(CV), NF) \
460 O(SetN, NA, TWO(CV,CV), ONE(CV), NF) \
461 O(SetG, NA, TWO(CV,CV), ONE(CV), NF) \
462 O(SetS, NA, THREE(CV,AV,CV), ONE(CV), NF) \
463 O(SetM, ONE(MA), C_LMANY(), ONE(CV), NF) \
464 O(SetWithRefLM, TWO(MA, HA), LMANY(), NOV, NF) \
465 O(SetWithRefRM, ONE(MA), R_LMANY(), NOV, NF) \
466 O(SetOpL, TWO(HA, OA), ONE(CV), ONE(CV), NF) \
467 O(SetOpN, ONE(OA), TWO(CV,CV), ONE(CV), NF) \
468 O(SetOpG, ONE(OA), TWO(CV,CV), ONE(CV), NF) \
469 O(SetOpS, ONE(OA), THREE(CV,AV,CV), ONE(CV), NF) \
470 O(SetOpM, TWO(OA,MA), C_LMANY(), ONE(CV), NF) \
471 O(IncDecL, TWO(HA,OA), NOV, ONE(CV), NF) \
472 O(IncDecN, ONE(OA), ONE(CV), ONE(CV), NF) \
473 O(IncDecG, ONE(OA), ONE(CV), ONE(CV), NF) \
474 O(IncDecS, ONE(OA), TWO(AV,CV), ONE(CV), NF) \
475 O(IncDecM, TWO(OA,MA), LMANY(), ONE(CV), NF) \
476 O(BindL, ONE(HA), ONE(VV), ONE(VV), NF) \
477 O(BindN, NA, TWO(VV,CV), ONE(VV), NF) \
478 O(BindG, NA, TWO(VV,CV), ONE(VV), NF) \
479 O(BindS, NA, THREE(VV,AV,CV), ONE(VV), NF) \
480 O(BindM, ONE(MA), V_LMANY(), ONE(VV), NF) \
481 O(UnsetL, ONE(HA), NOV, NOV, NF) \
482 O(UnsetN, NA, ONE(CV), NOV, NF) \
483 O(UnsetG, NA, ONE(CV), NOV, NF) \
484 O(UnsetM, ONE(MA), LMANY(), NOV, NF) \
485 /* NOTE: isFPush below relies on the grouping of FPush* here */ \
486 O(FPushFunc, ONE(IVA), ONE(CV), NOV, NF) \
487 O(FPushFuncD, TWO(IVA,SA), NOV, NOV, NF) \
488 O(FPushFuncU, THREE(IVA,SA,SA), NOV, NOV, NF) \
489 O(FPushObjMethod, ONE(IVA), TWO(CV,CV), NOV, NF) \
490 O(FPushObjMethodD, TWO(IVA,SA), ONE(CV), NOV, NF) \
491 O(FPushClsMethod, ONE(IVA), TWO(AV,CV), NOV, NF) \
492 O(FPushClsMethodF, ONE(IVA), TWO(AV,CV), NOV, NF) \
493 O(FPushClsMethodD, THREE(IVA,SA,SA), NOV, NOV, NF) \
494 O(FPushCtor, ONE(IVA), ONE(AV), ONE(CV), NF) \
495 O(FPushCtorD, TWO(IVA,SA), NOV, ONE(CV), NF) \
496 O(FPushCufIter, TWO(IVA,IA), NOV, NOV, NF) \
497 O(FPushCuf, ONE(IVA), ONE(CV), NOV, NF) \
498 O(FPushCufF, ONE(IVA), ONE(CV), NOV, NF) \
499 O(FPushCufSafe, ONE(IVA), TWO(CV,CV), TWO(CV,CV), NF) \
500 O(FPassC, ONE(IVA), ONE(CV), ONE(FV), FF) \
501 O(FPassCW, ONE(IVA), ONE(CV), ONE(FV), FF) \
502 O(FPassCE, ONE(IVA), ONE(CV), ONE(FV), FF) \
503 O(FPassV, ONE(IVA), ONE(VV), ONE(FV), FF) \
504 O(FPassR, ONE(IVA), ONE(RV), ONE(FV), FF) \
505 O(FPassL, TWO(IVA,HA), NOV, ONE(FV), FF) \
506 O(FPassN, ONE(IVA), ONE(CV), ONE(FV), FF) \
507 O(FPassG, ONE(IVA), ONE(CV), ONE(FV), FF) \
508 O(FPassS, ONE(IVA), TWO(AV,CV), ONE(FV), FF) \
509 O(FPassM, TWO(IVA,MA), LMANY(), ONE(FV), FF) \
510 O(FCall, ONE(IVA), FMANY, ONE(RV), CF_FF) \
511 O(FCallArray, NA, ONE(FV), ONE(RV), CF_FF) \
512 O(FCallBuiltin, THREE(IVA,IVA,SA),CVMANY, ONE(RV), CF) \
513 O(CufSafeArray, NA, THREE(RV,CV,CV), ONE(CV), NF) \
514 O(CufSafeReturn, NA, THREE(RV,CV,CV), ONE(RV), NF) \
515 O(IterInit, THREE(IA,BA,HA), ONE(CV), NOV, CF) \
516 O(MIterInit, THREE(IA,BA,HA), ONE(VV), NOV, CF) \
517 O(WIterInit, THREE(IA,BA,HA), ONE(CV), NOV, CF) \
518 O(IterInitK, FOUR(IA,BA,HA,HA),ONE(CV), NOV, CF) \
519 O(MIterInitK, FOUR(IA,BA,HA,HA),ONE(VV), NOV, CF) \
520 O(WIterInitK, FOUR(IA,BA,HA,HA),ONE(CV), NOV, CF) \
521 O(IterNext, THREE(IA,BA,HA), NOV, NOV, CF) \
522 O(MIterNext, THREE(IA,BA,HA), NOV, NOV, CF) \
523 O(WIterNext, THREE(IA,BA,HA), NOV, NOV, CF) \
524 O(IterNextK, FOUR(IA,BA,HA,HA),NOV, NOV, CF) \
525 O(MIterNextK, FOUR(IA,BA,HA,HA),NOV, NOV, CF) \
526 O(WIterNextK, FOUR(IA,BA,HA,HA),NOV, NOV, CF) \
527 O(DecodeCufIter, TWO(IA,BA), ONE(CV), NOV, CF) \
528 O(IterFree, ONE(IA), NOV, NOV, NF) \
529 O(MIterFree, ONE(IA), NOV, NOV, NF) \
530 O(CIterFree, ONE(IA), NOV, NOV, NF) \
531 O(IterBreak, TWO(ILA,BA), NOV, NOV, CF_TF) \
532 O(Incl, NA, ONE(CV), ONE(CV), CF) \
533 O(InclOnce, NA, ONE(CV), ONE(CV), CF) \
534 O(Req, NA, ONE(CV), ONE(CV), CF) \
535 O(ReqOnce, NA, ONE(CV), ONE(CV), CF) \
536 O(ReqDoc, NA, ONE(CV), ONE(CV), CF) \
537 O(Eval, NA, ONE(CV), ONE(CV), CF) \
538 O(DefFunc, ONE(IVA), NOV, NOV, NF) \
539 O(DefCls, ONE(IVA), NOV, NOV, NF) \
540 O(DefCns, ONE(SA), ONE(CV), ONE(CV), NF) \
541 O(DefTypedef, ONE(IVA), NOV, NOV, NF) \
542 O(This, NA, NOV, ONE(CV), NF) \
543 O(BareThis, ONE(OA), NOV, ONE(CV), NF) \
544 O(CheckThis, NA, NOV, NOV, NF) \
545 O(InitThisLoc, ONE(IVA), NOV, NOV, NF) \
546 O(StaticLoc, TWO(IVA,SA), NOV, ONE(CV), NF) \
547 O(StaticLocInit, TWO(IVA,SA), ONE(CV), NOV, NF) \
548 O(Catch, NA, NOV, ONE(CV), NF) \
549 O(ClassExists, NA, TWO(CV,CV), ONE(CV), NF) \
550 O(InterfaceExists, NA, TWO(CV,CV), ONE(CV), NF) \
551 O(TraitExists, NA, TWO(CV,CV), ONE(CV), NF) \
552 O(VerifyParamType, ONE(IVA), NOV, NOV, NF) \
553 O(Self, NA, NOV, ONE(AV), NF) \
554 O(Parent, NA, NOV, ONE(AV), NF) \
555 O(LateBoundCls, NA, NOV, ONE(AV), NF) \
556 O(NativeImpl, NA, NOV, NOV, CF_TF) \
557 O(CreateCl, TWO(IVA,SA), CVMANY, ONE(CV), NF) \
558 O(CreateCont, ONE(SA), NOV, ONE(CV), NF) \
559 O(ContEnter, NA, ONE(CV), NOV, CF) \
560 O(UnpackCont, NA, NOV, TWO(CV,CV), NF) \
561 O(ContSuspend, ONE(IVA), ONE(CV), NOV, CF) \
562 O(ContSuspendK, ONE(IVA), TWO(CV,CV), NOV, CF) \
563 O(ContRetC, NA, ONE(CV), NOV, CF_TF) \
564 O(ContCheck, ONE(IVA), NOV, NOV, NF) \
565 O(ContRaise, NA, NOV, NOV, NF) \
566 O(ContValid, NA, NOV, ONE(CV), NF) \
567 O(ContKey, NA, NOV, ONE(CV), NF) \
568 O(ContCurrent, NA, NOV, ONE(CV), NF) \
569 O(ContStopped, NA, NOV, NOV, NF) \
570 O(ContHandle, NA, ONE(CV), NOV, CF_TF) \
571 O(Strlen, NA, ONE(CV), ONE(CV), NF) \
572 O(IncStat, TWO(IVA,IVA), NOV, NOV, NF) \
573 O(Abs, NA, ONE(CV), ONE(CV), NF) \
574 O(ArrayIdx, NA, THREE(CV,CV,CV), ONE(CV), NF) \
575 O(Floor, NA, ONE(CV), ONE(CV), NF) \
576 O(Ceil, NA, ONE(CV), ONE(CV), NF) \
577 O(HighInvalid, NA, NOV, NOV, NF) \
579 enum class Op : uint8_t {
580 #define O(name, ...) name,
581 OPCODES
582 #undef O
584 auto constexpr Op_count = uint8_t(Op::HighInvalid) + 1;
586 /* Also put Op* in the enclosing namespace, to avoid having to change
587 * every existing usage site of the enum values. */
588 #define O(name, ...) UNUSED auto constexpr Op##name = Op::name;
589 OPCODES
590 #undef O
592 inline constexpr bool operator<(Op a, Op b) { return uint8_t(a) < uint8_t(b); }
593 inline constexpr bool operator>(Op a, Op b) { return uint8_t(a) > uint8_t(b); }
594 inline constexpr bool operator<=(Op a, Op b) {
595 return uint8_t(a) <= uint8_t(b);
597 inline constexpr bool operator>=(Op a, Op b) {
598 return uint8_t(a) >= uint8_t(b);
601 inline bool isValidOpcode(Op op) {
602 return op > OpLowInvalid && op < OpHighInvalid;
605 inline Op toOp(Opcode o) {
606 Op op = Op(o);
607 assert(isValidOpcode(op));
608 return op;
611 const MInstrInfo& getMInstrInfo(Op op);
613 enum AstubsOp {
614 OpAstubStart = Op_count-1,
615 #define O(name, imm, pop, push, flags) OpAstub##name,
616 OPCODES
617 #undef O
618 OpAstubCount
621 #define HIGH_OPCODES \
622 O(FuncPrologue) \
623 O(TraceletGuard) \
624 O(NativeTrampoline) \
625 O(ServiceRequest) \
626 O(DtorStub) \
627 O(SyncOutputs) \
628 O(RetFromInterp) \
629 O(ResumeHelper) \
630 O(RequireHelper) \
631 O(DefClsHelper) \
633 enum HighOp {
634 OpHighStart = OpAstubCount-1,
635 #define O(name) Op##name,
636 HIGH_OPCODES
637 #undef O
640 struct StrVecItem {
641 Id str;
642 Offset dest;
645 struct ImmVector {
646 explicit ImmVector() : m_start(0) {}
648 explicit ImmVector(const uint8_t* start,
649 int32_t length,
650 int32_t numStack)
651 : m_length(length)
652 , m_numStack(numStack)
653 , m_start(start)
657 * Returns an ImmVector from a pointer to the immediate vector
658 * itself. Use getImmVector() if you want to get it from an Opcode*
659 * that points to the opcode.
661 static ImmVector createFromStream(const uint8_t* opcode) {
662 int32_t size = reinterpret_cast<const int32_t*>(opcode)[0];
663 int32_t stackCount = reinterpret_cast<const int32_t*>(opcode)[1];
664 const uint8_t* start = opcode + sizeof(int32_t) + sizeof(int32_t);
665 return ImmVector(start, size, stackCount);
669 * Returns an ImmVector of 32-bit ints from a pointer to the
670 * immediate vector itself.
672 static ImmVector createFromStream(const int32_t* stream) {
673 int32_t size = stream[0];
674 return ImmVector(reinterpret_cast<const uint8_t*>(stream + 1), size, 0);
677 bool isValid() const { return m_start != 0; }
679 const uint8_t* vec() const { return m_start; }
680 const int32_t* vec32() const {
681 return reinterpret_cast<const int32_t*>(m_start);
683 const StrVecItem* strvec() const {
684 return reinterpret_cast<const StrVecItem*>(m_start);
687 LocationCode locationCode() const { return LocationCode(*vec()); }
690 * Returns the length of the immediate vector in bytes (for M
691 * vectors) or elements (for switch vectors)
693 int32_t size() const { return m_length; }
696 * Returns the number of elements on the execution stack that this
697 * vector will need to access. (Includes stack elements for both
698 * the base and members.)
700 int numStackValues() const { return m_numStack; }
703 * Returns a pointer to the last member code in the vector.
705 * Requires: isValid() && size() >= 1
707 const uint8_t* findLastMember() const;
710 * Decode the terminating string immediate, if any.
712 bool decodeLastMember(const Unit*, StringData*& sdOut,
713 MemberCode& membOut,
714 int64_t* strIdOut = nullptr) const;
717 private:
718 int32_t m_length;
719 int32_t m_numStack;
720 const uint8_t* m_start;
723 // Must be an opcode that actually has an ImmVector.
724 ImmVector getImmVector(const Op* opcode);
726 struct MInstrLocation {
727 LocationCode lcode;
728 int64_t imm;
730 bool hasImm() const {
731 auto count = numLocationCodeImms(lcode);
732 assert(count == 0 || count == 1);
733 return count;
736 MInstrLocation getMLocation(const Op* opcode);
738 struct MVectorItem {
739 MemberCode mcode;
740 int64_t imm;
742 bool hasImm() const {
743 return memberCodeHasImm(mcode);
746 std::vector<MVectorItem> getMVector(const Op* opcode);
748 /* Some decoding helper functions. */
749 int numImmediates(Op opcode);
750 ArgType immType(Op opcode, int idx);
751 int immSize(const Op* opcode, int idx);
752 bool immIsVector(Op opcode, int idx);
753 bool hasImmVector(Op opcode);
754 inline bool isTypePred(const Op op) {
755 return op >= OpIsNullC && op <= OpIsObjectL;
757 int instrLen(const Op* opcode);
758 InstrFlags instrFlags(Op opcode);
759 int numSuccs(const Op* opcode);
760 bool pushesActRec(Op opcode);
762 // The returned struct has normalized variable-sized immediates
763 ArgUnion getImm(const Op* opcode, int idx);
764 // Don't use this with variable-sized immediates!
765 ArgUnion* getImmPtr(const Op* opcode, int idx);
767 // Pass a pointer to the pointer to the immediate; this function will advance
768 // the pointer past the immediate
769 inline int32_t decodeVariableSizeImm(const unsigned char** immPtr) {
770 const unsigned char small = **immPtr;
771 if (UNLIKELY(small & 0x1)) {
772 const unsigned int large = *((const unsigned int*)*immPtr);
773 *immPtr += sizeof(large);
774 return (int32_t)(large >> 1);
775 } else {
776 *immPtr += sizeof(small);
777 return (int32_t)(small >> 1);
781 int64_t decodeMemberCodeImm(const unsigned char** immPtr, MemberCode mcode);
783 // Encodes a variable sized immediate for `val' into `buf'. Returns
784 // the number of bytes used taken. At most 4 bytes can be used.
785 size_t encodeVariableSizeImm(int32_t val, unsigned char* buf);
787 // Encodes a variable sized immediate to the end of vec.
788 void encodeIvaToVector(std::vector<uchar>& vec, int32_t val);
790 template<typename T>
791 void encodeToVector(std::vector<uchar>& vec, T val) {
792 size_t currentLen = vec.size();
793 vec.resize(currentLen + sizeof(T));
794 memcpy(&vec[currentLen], &val, sizeof(T));
797 void staticStreamer(const TypedValue* tv, std::stringstream& out);
799 std::string instrToString(const Op* it, const Unit* u = nullptr);
800 const char* opcodeToName(Op op);
802 // returns a pointer to the location within the bytecode containing the jump
803 // Offset, or NULL if the instruction cannot jump. Note that this offset is
804 // relative to the current instruction.
805 Offset* instrJumpOffset(Op* instr);
807 // returns absolute address of target, or InvalidAbsoluteOffset if instruction
808 // cannot jump
809 Offset instrJumpTarget(const Op* instrs, Offset pos);
811 struct StackTransInfo {
812 enum class Kind {
813 PushPop,
814 InsertMid
816 Kind kind;
817 int numPops;
818 int numPushes;
819 int pos;
822 bool instrIsControlFlow(Op opcode);
823 bool instrIsNonCallControlFlow(Op opcode);
824 bool instrAllowsFallThru(Op opcode);
825 bool instrReadsCurrentFpi(Op opcode);
827 inline bool isFPush(Op opcode) {
828 return opcode >= OpFPushFunc && opcode <= OpFPushCufSafe;
831 inline bool isFCallStar(Op opcode) {
832 switch (opcode) {
833 case OpFCall:
834 case OpFCallArray:
835 return true;
837 default:
838 return false;
842 inline bool isFPassStar(Op opcode) {
843 switch (opcode) {
844 case OpFPassC:
845 case OpFPassCW:
846 case OpFPassCE:
847 case OpFPassV:
848 case OpFPassR:
849 case OpFPassL:
850 case OpFPassN:
851 case OpFPassG:
852 case OpFPassS:
853 case OpFPassM:
854 return true;
856 default:
857 return false;
861 inline bool isLiteral(Op op) {
862 switch (op) {
863 case OpNull:
864 case OpNullUninit:
865 case OpTrue:
866 case OpFalse:
867 case OpInt:
868 case OpDouble:
869 case OpString:
870 case OpArray:
871 return true;
873 default:
874 return false;
878 inline bool isThisSelfOrParent(Op op) {
879 switch (op) {
880 case OpThis:
881 case OpSelf:
882 case OpParent:
883 return true;
885 default:
886 return false;
890 inline bool isRet(Op op) {
891 switch (op) {
892 case OpRetC:
893 case OpRetV:
894 return true;
896 default:
897 return false;
901 inline bool isSwitch(Op op) {
902 switch (op) {
903 case OpSwitch:
904 case OpSSwitch:
905 return true;
907 default:
908 return false;
912 inline bool isSwitch(Opcode op) {
913 return isSwitch(toOp(op));
916 template<typename L>
917 void foreachSwitchTarget(Op* op, L func) {
918 assert(isSwitch(*op));
919 bool isStr = readData<Op>(op) == OpSSwitch;
920 int32_t size = readData<int32_t>(op);
921 for (int i = 0; i < size; ++i) {
922 if (isStr) readData<Id>(op);
923 func(readData<Offset>(op));
927 template<typename L>
928 void foreachSwitchString(Opcode* op, L func) {
929 assert(toOp(*op) == OpSSwitch);
930 readData<Opcode>(op);
931 int32_t size = readData<int32_t>(op) - 1; // the last item is the default
932 for (int i = 0; i < size; ++i) {
933 func(readData<Id>(op));
934 readData<Offset>(op);
938 int instrNumPops(const Op* opcode);
939 int instrNumPushes(const Op* opcode);
940 StackTransInfo instrStackTransInfo(const Op* opcode);
941 int instrSpToArDelta(const Op* opcode);
943 inline bool
944 mcodeIsLiteral(MemberCode mcode) {
945 return mcode == MET || mcode == MEI || mcode == MPT;
948 inline bool
949 mcodeMaybePropName(MemberCode mcode) {
950 return mcode == MPC || mcode == MPL || mcode == MPT;
953 inline bool
954 mcodeMaybeArrayOrMapKey(MemberCode mcode) {
955 return mcode == MEC || mcode == MEL || mcode == MET || mcode == MEI;
958 inline bool
959 mcodeMaybeArrayStringKey(MemberCode mcode) {
960 return mcode == MEC || mcode == MEL || mcode == MET;
963 inline bool
964 mcodeMaybeArrayIntKey(MemberCode mcode) {
965 return mcode == MEC || mcode == MEL || mcode == MEI;
968 inline bool
969 mcodeMaybeVectorKey(MemberCode mcode) {
970 return mcode == MEC || mcode == MEL || mcode == MEI;
975 namespace std { namespace tr1 {
976 template<>
977 struct hash<HPHP::Op> {
978 size_t operator()(HPHP::Op op) const {
979 return HPHP::hash_int64(uint8_t(op));
984 #endif