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 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 */
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
= 4, // Return value (cell or var)
77 FV
= 5, // Function parameter (cell or var)
78 CVV
= 6, // Cell or Var argument
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
91 // Base is the object stored in a local, a cell, or $this
96 // Base is the global name referred to by a cell or a local.
100 // Base is the name of a local, given by a cell or the value of a
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.
114 // Base is a function return value.
118 InvalidLocationCode
= NumLocationCodes
121 inline int numLocationCodeImms(LocationCode lc
) {
123 case LL
: case LGL
: case LNL
: case LSL
:
125 case LC
: case LH
: case LGC
: case LNC
: case LSC
: case LR
:
132 inline int numLocationCodeStackVals(LocationCode lc
) {
134 case LL
: case LH
: case LGL
: case LNL
:
136 case LC
: case LGC
: case LNC
: case LSL
: case LR
:
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
);
156 // Element and property, consuming a cell from the stack.
160 // Element and property, using an immediate local id.
164 // Element and property, using a string immediate
168 // Element, using an int64 immediate
171 // New element operation. (No real stack element.)
175 InvalidMemberCode
= NumMemberCodes
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.
194 #ifdef HHVM_MORE_WARNINGS
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
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)
227 #define MII(instr, attrs, bS, iS, vC, fN) \
235 MInstrAttr m_baseOps
[NumLocationCodes
];
236 MInstrAttr m_intermediateOps
[NumMemberCodes
];
242 MInstr
instr() const {
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 {
260 bool newElem() const {
264 bool finalGet() const {
268 const char* name() const {
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
) {
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*);
303 #define INCDEC_OP(incDecOp) incDecOp,
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.
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)
332 #define SETOP_OP(setOpOp, bcOp) SetOp##setOpOp,
338 // name immediates inputs outputs flags
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,
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;
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
) {
607 assert(isValidOpcode(op
));
611 const MInstrInfo
& getMInstrInfo(Op op
);
614 OpAstubStart
= Op_count
-1,
615 #define O(name, imm, pop, push, flags) OpAstub##name,
621 #define HIGH_OPCODES \
624 O(NativeTrampoline) \
634 OpHighStart
= OpAstubCount
-1,
635 #define O(name) Op##name,
646 explicit ImmVector() : m_start(0) {}
648 explicit ImmVector(const uint8_t* start
,
652 , m_numStack(numStack
)
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
,
714 int64_t* strIdOut
= nullptr) const;
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
{
730 bool hasImm() const {
731 auto count
= numLocationCodeImms(lcode
);
732 assert(count
== 0 || count
== 1);
736 MInstrLocation
getMLocation(const Op
* opcode
);
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);
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
);
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
809 Offset
instrJumpTarget(const Op
* instrs
, Offset pos
);
811 struct StackTransInfo
{
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
) {
842 inline bool isFPassStar(Op opcode
) {
861 inline bool isLiteral(Op op
) {
878 inline bool isThisSelfOrParent(Op op
) {
890 inline bool isRet(Op op
) {
901 inline bool isSwitch(Op op
) {
912 inline bool isSwitch(Opcode op
) {
913 return isSwitch(toOp(op
));
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
));
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
);
944 mcodeIsLiteral(MemberCode mcode
) {
945 return mcode
== MET
|| mcode
== MEI
|| mcode
== MPT
;
949 mcodeMaybePropName(MemberCode mcode
) {
950 return mcode
== MPC
|| mcode
== MPL
|| mcode
== MPT
;
954 mcodeMaybeArrayOrMapKey(MemberCode mcode
) {
955 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MET
|| mcode
== MEI
;
959 mcodeMaybeArrayStringKey(MemberCode mcode
) {
960 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MET
;
964 mcodeMaybeArrayIntKey(MemberCode mcode
) {
965 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MEI
;
969 mcodeMaybeVectorKey(MemberCode mcode
) {
970 return mcode
== MEC
|| mcode
== MEL
|| mcode
== MEI
;
975 namespace std
{ namespace tr1
{
977 struct hash
<HPHP::Op
> {
978 size_t operator()(HPHP::Op op
) const {
979 return HPHP::hash_int64(uint8_t(op
));