2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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_RUNTIME_VM_TRANSLATOR_HOPT_HHBCTRANSLATOR_H_
18 #define incl_HPHP_RUNTIME_VM_TRANSLATOR_HOPT_HHBCTRANSLATOR_H_
25 #include "folly/Optional.h"
27 #include "hphp/util/assertions.h"
28 #include "hphp/util/ringbuffer.h"
29 #include "hphp/runtime/vm/bytecode.h"
30 #include "hphp/runtime/vm/member-operations.h"
31 #include "hphp/runtime/vm/jit/guard-relaxation.h"
32 #include "hphp/runtime/vm/jit/ir-builder.h"
33 #include "hphp/runtime/vm/jit/runtime-type.h"
34 #include "hphp/runtime/vm/jit/translator.h"
35 #include "hphp/runtime/vm/srckey.h"
42 enum class IRGenMode
{
47 //////////////////////////////////////////////////////////////////////
50 * This module is responsible for determining high-level HHBC->IR
51 * compilation strategy.
53 * For each bytecode Foo in HHBC, there is a function in this class
54 * called emitFoo which handles translating it into HHIR.
56 * Additionally, while transating bytecode, this module manages a
57 * virtual execution stack modelling the state of the stack since the
58 * last time we emitted an IR instruction that materialized it
59 * (e.g. SpillStack or SpillFrame).
61 * HhbcTranslator is where we make optimiations that relate to overall
62 * knowledge of the runtime and HHBC. For example, decisions like
63 * whether to use IR instructions that have constant Class*'s (for a
64 * AttrUnique class) instead of loading a Class* from RDS are
67 struct HhbcTranslator
{
68 HhbcTranslator(Offset startOffset
,
69 uint32_t initialSpOffsetFromFp
,
74 IRBuilder
& irBuilder() const { return *m_irb
.get(); }
75 IRUnit
& unit() { return m_unit
; }
77 // In between each emit* call, irtranslator indicates the new
78 // bytecode offset (or whether we're finished) using this API.
79 void setBcOff(Offset newOff
, bool lastBcOff
);
81 void setGenMode(IRGenMode mode
);
82 IRGenMode
genMode() const { return m_mode
; }
84 // End a bytecode block and do the right thing with fallthrough.
85 void endBlock(Offset next
);
88 void end(Offset nextPc
);
91 void guardTypeStack(uint32_t stackIndex
, Type type
, bool outerOnly
);
92 void guardTypeLocal(uint32_t locId
, Type type
, bool outerOnly
);
93 void guardTypeLocation(const RegionDesc::Location
& loc
, Type type
,
95 void guardRefs(int64_t entryArDelta
,
96 const std::vector
<bool>& mask
,
97 const std::vector
<bool>& vals
);
99 // Interface to irtranslator for predicted and inferred types.
100 void assertTypeLocal(uint32_t localIndex
, Type type
);
101 void assertTypeStack(uint32_t stackIndex
, Type type
);
102 void checkTypeLocal(uint32_t localIndex
, Type type
, Offset dest
= -1);
103 void checkTypeStack(uint32_t idx
, Type type
, Offset dest
);
104 void checkTypeTopOfStack(Type type
, Offset nextByteCode
);
105 void assertType(const RegionDesc::Location
& loc
, Type type
);
106 void checkType(const RegionDesc::Location
& loc
, Type type
,
108 void assertClass(const RegionDesc::Location
& loc
, const Class
* cls
);
110 RuntimeType
rttFromLocation(const Location
& loc
);
112 // Inlining-related functions.
113 void beginInlining(unsigned numArgs
,
115 Offset returnBcOffset
,
116 Type retTypePred
= Type::Gen
);
117 bool isInlining() const;
118 int inliningDepth() const;
119 void profileFunctionEntry(const char* category
);
120 void profileInlineFunctionShape(const std::string
& str
);
121 void profileSmallFunctionShape(const std::string
& str
);
122 void profileFailedInlShape(const std::string
& str
);
124 // Other public functions for irtranslator.
125 void setThisAvailable();
126 void emitInterpOne(const NormalizedInstruction
&);
127 void emitInterpOne(int popped
);
128 void emitInterpOne(Type t
, int popped
);
129 void emitInterpOne(folly::Optional
<Type
> t
, int popped
, int pushed
,
131 std::string
showStack() const;
132 bool hasExit() const {
137 * An emit* function for each HHBC opcode.
142 void emitCheckThis();
143 void emitBareThis(int notice
);
144 void emitInitThisLoc(int32_t id
);
145 void emitArray(int arrayId
);
146 void emitNewArray(int capacity
);
147 void emitNewPackedArray(int n
);
148 void emitNewStructArray(uint32_t n
, StringData
** keys
);
149 void emitNewCol(int capacity
);
154 void emitAddNewElemC();
155 void emitNewCol(int type
, int numElems
);
156 void emitColAddElemC();
157 void emitColAddNewElemC();
158 void emitDefCns(uint32_t id
);
159 void emitCnsCommon(uint32_t id
, uint32_t fallbackId
, bool error
);
160 void emitCns(uint32_t id
);
161 void emitCnsE(uint32_t id
);
162 void emitCnsU(uint32_t id
, uint32_t fallbackId
);
164 void emitDefCls(int id
, Offset after
);
165 void emitDefFunc(int id
);
167 void emitLateBoundCls();
171 void emitString(int strId
);
172 void emitInt(int64_t val
);
173 void emitDouble(double val
);
174 void emitNullUninit();
178 void emitCGetL(int32_t id
);
179 void emitFPassL(int32_t id
);
180 void emitPushL(uint32_t id
);
181 void emitCGetL2(int32_t id
);
184 void emitMInstr(const NormalizedInstruction
& ni
);
185 void emitVGetL(int32_t id
);
188 void emitSetL(int32_t id
);
191 void emitBindL(int32_t id
);
194 void emitUnsetL(int32_t id
);
195 void emitIssetL(int32_t id
);
198 void emitEmptyL(int32_t id
);
201 // The subOp param can be one of either
202 // Add, Sub, Mul, Div, Mod, Shl, Shr, Concat, BitAnd, BitOr, BitXor
203 void emitSetOpL(Op subOp
, uint32_t id
);
204 // the pre, inc, and over params encode the 8 possible sub opcodes
205 void emitIncDecL(bool pre
, bool inc
, bool over
, uint32_t id
);
212 void emitJmpZ(Offset taken
, Offset next
, bool bothPaths
);
213 void emitJmpNZ(Offset taken
, Offset next
, bool bothPaths
);
214 void emitJmp(int32_t offset
, bool breakTracelet
, Block
* catchBlock
);
215 void emitJmp(int32_t offset
, bool breakTracelet
, bool noSurprise
) {
216 emitJmp(offset
, breakTracelet
, noSurprise
? nullptr : makeCatch());
218 void emitGt() { emitCmp(Gt
); }
219 void emitGte() { emitCmp(Gte
); }
220 void emitLt() { emitCmp(Lt
); }
221 void emitLte() { emitCmp(Lte
); }
222 void emitEq() { emitCmp(Eq
); }
223 void emitNeq() { emitCmp(Neq
); }
224 void emitSame() { emitCmp(Same
); }
225 void emitNSame() { emitCmp(NSame
); }
229 void emitFPushCufIter(int32_t numParams
, int32_t itId
);
230 void emitFPushCufOp(Op op
, int32_t numArgs
);
231 bool emitFPushCufArray(SSATmp
* callable
, int32_t numParams
);
232 void emitFPushCufUnknown(Op op
, int32_t numArgs
);
233 void emitFPushActRec(SSATmp
* func
, SSATmp
* objOrClass
, int32_t numArgs
,
234 const StringData
* invName
= nullptr);
235 void emitFPushFuncCommon(const Func
* func
,
236 const StringData
* name
,
237 const StringData
* fallback
,
239 void emitFPushFuncD(int32_t numParams
, int32_t funcId
);
240 void emitFPushFuncU(int32_t numParams
,
242 int32_t fallbackFuncId
);
243 void emitFPushFunc(int32_t numParams
);
244 void emitFPushFuncObj(int32_t numParams
);
245 void emitFPushFuncArr(int32_t numParams
);
246 SSATmp
* genClsMethodCtx(const Func
* callee
, const Class
* cls
);
247 void emitFPushClsMethod(int32_t numParams
);
248 void emitFPushClsMethodD(int32_t numParams
,
249 int32_t methodNameStrId
,
250 int32_t clssNamedEntityPairId
);
251 void emitFPushObjMethodD(int32_t numParams
,
252 int32_t methodNameStrId
);
253 void emitFPushObjMethodCommon(SSATmp
* obj
,
254 const StringData
* methodName
,
257 SSATmp
* extraSpill
= nullptr);
258 void emitFPushClsMethodF(int32_t numParams
);
259 SSATmp
* emitAllocObjFast(const Class
* cls
);
260 void emitFPushCtorD(int32_t numParams
, int32_t classNameStrId
);
261 void emitFPushCtor(int32_t numParams
);
262 void emitFPushCtorCommon(SSATmp
* cls
,
266 void emitCreateCl(int32_t numParams
, int32_t classNameStrId
);
267 void emitFCallArray(const Offset pcOffset
, const Offset after
,
269 void emitFCall(uint32_t numParams
, Offset returnBcOffset
,
270 const Func
* callee
, bool destroyLocals
);
271 void emitFCallBuiltin(uint32_t numArgs
, uint32_t numNonDefault
,
272 int32_t funcId
, bool destroyLocals
);
273 void emitClsCnsD(int32_t cnsNameStrId
, int32_t clsNameStrId
, Type outPred
);
274 void emitClsCns(int32_t cnsNameStrId
);
277 void emitAGetL(int localId
);
278 void emitIsScalarL(int id
);
279 void emitIsScalarC();
280 void emitVerifyTypeImpl(int32_t id
);
281 void emitVerifyParamType(int32_t paramId
);
282 void emitVerifyRetTypeC();
283 void emitVerifyRetTypeV();
284 void emitInstanceOfD(int classNameStrId
);
285 void emitInstanceOf();
289 void emitCastDouble();
290 void emitCastString();
291 void emitCastArray();
292 void emitCastObject();
294 void emitSwitch(const ImmVector
&, int64_t base
, bool bounded
);
295 void emitSSwitch(const ImmVector
&);
297 // freeInline indicates whether we should be doing decrefs inlined in
298 // the TC, or using the generic decref helper.
299 void emitRetC(bool freeInline
);
300 void emitRetV(bool freeInline
);
305 void emitCheckProp(Id propId
);
306 void emitInitProp(Id propId
, InitPropOp op
);
307 void emitAssertTL(int32_t id
, AssertTOp
);
308 void emitAssertTStk(int32_t offset
, AssertTOp
);
309 void emitAssertObjL(int32_t id
, Id
, AssertObjOp
);
310 void emitAssertObjStk(int32_t offset
, Id
, AssertObjOp
);
311 void emitPredictTL(int32_t id
, AssertTOp
);
312 void emitPredictTStk(int32_t offset
, AssertTOp
);
335 void emitNativeImpl();
337 void emitClassExists();
338 void emitInterfaceExists();
339 void emitTraitExists();
341 void emitStaticLocInit(uint32_t varId
, uint32_t litStrId
);
342 void emitStaticLoc(uint32_t varId
, uint32_t litStrId
);
343 void emitReqDoc(const StringData
* name
);
346 void emitIterInit(uint32_t iterId
,
350 void emitIterInitK(uint32_t iterId
,
355 void emitIterNext(uint32_t iterId
,
359 void emitIterNextK(uint32_t iterId
,
364 void emitMIterInit(uint32_t iterId
, int targetOffset
, uint32_t valLocalId
);
365 void emitMIterInitK(uint32_t iterId
,
368 uint32_t keyLocalId
);
369 void emitMIterNext(uint32_t iterId
, int targetOffset
, uint32_t valLocalId
);
370 void emitMIterNextK(uint32_t iterId
,
373 uint32_t keyLocalId
);
374 void emitWIterInit(uint32_t iterId
,
378 void emitWIterInitK(uint32_t iterId
,
383 void emitWIterNext(uint32_t iterId
,
387 void emitWIterNextK(uint32_t iterId
,
393 void emitIterFree(uint32_t iterId
);
394 void emitMIterFree(uint32_t iterId
);
395 void emitDecodeCufIter(uint32_t iterId
, int targetOffset
);
396 void emitCIterFree(uint32_t iterId
);
397 void emitIterBreak(const ImmVector
& iv
, uint32_t offset
, bool breakTracelet
);
398 void emitVerifyParamType(uint32_t paramId
);
401 void emitCreateCont(Offset resumeOffset
);
402 void emitContReturnControl(Block
* catchBlock
);
403 void emitContSuspendImpl(Offset resumeOffset
);
404 void emitContSuspend(Offset resumeOffset
);
405 void emitContSuspendK(Offset resumeOffset
);
406 void emitContCheck(bool checkStarted
);
407 void emitContValid();
409 void emitContCurrent();
410 void emitContStopped();
413 void emitAsyncAwait();
414 void emitAsyncSuspendE(Offset resumeOffset
, int iters
);
415 void emitAsyncSuspendR(Offset resumeOffset
);
418 void emitIncStat(int32_t counter
, int32_t value
, bool force
);
419 void emitIncTransCounter();
420 void emitIncProfCounter(TransID transId
);
421 void emitCheckCold(TransID transId
);
422 void emitRB(Trace::RingBufferType t
, SrcKey sk
, int level
= 1);
423 void emitRB(Trace::RingBufferType t
, std::string msg
, int level
= 1) {
424 emitRB(t
, makeStaticString(msg
), level
);
426 void emitRB(Trace::RingBufferType t
, const StringData
* msg
, int level
= 1);
427 void emitDbgAssertRetAddr();
429 void emitIdxCommon(Opcode opc
, Block
* catchBlock
= nullptr);
431 void emitIsTypeC(DataType t
);
432 void emitIsTypeL(uint32_t id
, DataType t
);
436 * MInstrTranslator is responsible for translating one of the vector
437 * instructions (CGetM, SetM, IssetM, etc..) into hhir.
439 class MInstrTranslator
{
441 MInstrTranslator(const NormalizedInstruction
& ni
,
450 void emitSideExits(SSATmp
* catchSp
, int nStack
);
461 // Intermediate Operations
462 void emitIntermediateOp();
464 void emitPropGeneric();
465 void emitPropSpecialized(const MInstrAttr mia
, PropInfo propInfo
);
467 void emitElemArray(SSATmp
* key
, bool warn
);
469 void emitRatchetRefs();
472 # define MII(instr, ...) \
473 void emit##instr##Elem(); \
474 void emit##instr##Prop();
477 void emitIssetEmptyElem(bool isEmpty
);
478 void emitIssetEmptyProp(bool isEmpty
);
479 void emitNotSuppNewElem();
480 void emitVGetNewElem();
481 void emitSetNewElem();
482 void emitSetWithRefNewElem();
483 void emitSetOpNewElem();
484 void emitIncDecNewElem();
485 void emitBindNewElem();
486 void emitArraySet(SSATmp
* key
, SSATmp
* value
);
487 void emitArrayGet(SSATmp
* key
);
488 void emitArrayIsset();
489 void emitPackedArrayGet(SSATmp
* key
);
490 void emitPackedArrayIsset();
491 void emitStringGet(SSATmp
* key
);
492 void emitStringIsset();
493 void emitVectorSet(SSATmp
* key
, SSATmp
* value
);
494 void emitVectorGet(SSATmp
* key
);
495 void emitVectorIsset();
496 void emitPairGet(SSATmp
* key
);
497 void emitPairIsset();
498 void emitMapSet(SSATmp
* key
, SSATmp
* value
);
499 void emitMapGet(SSATmp
* key
);
502 // Generate a catch trace that does not perform any final DecRef operations
503 // on scratch space, and return its first block.
504 Block
* makeEmptyCatch() {
505 return m_ht
.makeCatch();
508 // Generate a catch trace that will contain DecRef instructions for tvRef
509 // and/or tvRef2 as required; return the first block.
511 auto b
= makeEmptyCatch();
512 m_failedVec
.push_back(b
);
516 // Generate a catch trace that will free any scratch space used and perform
517 // a side-exit from a failed set operation, return the first block.
518 Block
* makeCatchSet() {
519 assert(!m_failedSetBlock
);
520 m_failedSetBlock
= makeCatch();
522 // This catch trace will be modified in emitMPost to end with a side
523 // exit, and TryEndCatch will fall through to that side exit if an
524 // InvalidSetMException is thrown.
525 m_failedSetBlock
->back().setOpcode(TryEndCatch
);
526 return m_failedSetBlock
;
529 void prependToTraces(IRInstruction
* inst
) {
530 for (auto b
: m_failedVec
) {
531 b
->prepend(m_unit
.cloneInstruction(inst
));
536 void numberStackInputs();
537 void setNoMIState() { m_needMIS
= false; }
539 SSATmp
* getInput(unsigned i
, TypeConstraint tc
);
540 SSATmp
* getBase(TypeConstraint tc
);
543 SSATmp
* getValAddr();
544 void constrainBase(TypeConstraint tc
, SSATmp
* value
= nullptr);
545 SSATmp
* checkInitProp(SSATmp
* baseAsObj
,
550 Class
* contextClass() const;
553 * genStk is a wrapper around IRBuilder::gen() to deal with instructions
554 * that may modify the stack. It inspects the opcode and the types of the
555 * inputs, replacing the opcode with the version that returns a new StkPtr
558 template<typename
... Srcs
>
559 SSATmp
* genStk(Opcode op
, Block
* taken
, Srcs
... srcs
);
561 /* Various predicates about the current instruction */
563 bool isSingleMember();
565 enum class SimpleOp
{
566 // the opcode is not in a simple form or not on a proper collection type
568 // simple opcode on Array
570 // simple opcode on Packed Array
572 // simple opcode on String
574 // simple opcode on Vector* (c_Vector* or c_ImmVector*)
576 // simple opcode on Map* (c_Map*)
578 // simple opcode on Map* (c_Pair*)
581 SimpleOp
simpleCollectionOp();
582 void constrainCollectionOpBase();
584 bool generateMVal() const;
585 bool needFirstRatchet() const;
586 bool needFinalRatchet() const;
587 unsigned nLogicalRatchets() const;
588 int ratchetInd() const;
590 template<class... Args
>
591 SSATmp
* cns(Args
&&... args
) {
592 return m_unit
.cns(std::forward
<Args
>(args
)...);
595 template<class... Args
>
596 SSATmp
* gen(Args
&&... args
) {
597 return m_irb
.gen(std::forward
<Args
>(args
)...);
600 const NormalizedInstruction
& m_ni
;
601 HhbcTranslator
& m_ht
;
604 const MInstrInfo
& m_mii
;
605 const BCMarker m_marker
;
606 hphp_hash_map
<unsigned, unsigned> m_stackInputs
;
613 /* The base for any accesses to the current MInstrState. */
616 /* The value of the base for the next member operation. Starts as the base
617 * for the whole instruction and is updated as the translator makes
621 /* The result of the vector instruction. nullptr if the current instruction
622 * doesn't produce a result. */
625 /* If set, contains a value of type CountedStr|Nullptr. If a runtime test
626 * determines that the value is not Nullptr, we incorrectly predicted the
627 * output type of the instruction and must side exit. */
628 SSATmp
* m_strTestResult
;
630 /* If set, contains the catch target for the final set operation of this
631 * instruction. The operations that set this member may need to return an
632 * unexpected type, in which case they'll throw an InvalidSetMException. To
633 * handle this, emitMPost adds code to the catch trace to fish the correct
634 * value out of the exception and side exit. */
635 Block
* m_failedSetBlock
;
637 /* Contains a list of all catch blocks created in building the vector.
638 * Each block must be appended with cleanup tasks (generally just DecRef)
639 * to be performed if an exception occurs during the course of the vector
641 std::vector
<Block
*> m_failedVec
;
644 private: // forwarding utilities
645 template<class... Args
>
646 SSATmp
* cns(Args
&&... args
) {
647 return m_unit
.cns(std::forward
<Args
>(args
)...);
650 template<class... Args
>
651 SSATmp
* gen(Args
&&... args
) {
652 return m_irb
->gen(std::forward
<Args
>(args
)...);
659 void emitBindMem(SSATmp
* ptr
, SSATmp
* src
);
660 void emitEmptyMem(SSATmp
* ptr
);
661 void emitIncDecMem(bool pre
, bool inc
, SSATmp
* ptr
, Block
* exit
);
662 void checkStrictlyInteger(SSATmp
*& key
, KeyType
& keyType
,
664 Type
assertObjType(const StringData
*);
665 void destroyName(SSATmp
* name
);
666 SSATmp
* ldClsPropAddr(Block
* catchBlock
, SSATmp
* cls
, SSATmp
* name
);
667 void emitUnboxRAux();
668 void emitAGet(SSATmp
* src
, Block
* catchBlock
);
669 void emitRetFromInlined(Type type
);
670 void emitDecRefLocalsInline();
671 void emitRet(Type type
, bool freeInline
);
672 void emitCmp(Opcode opc
);
673 SSATmp
* emitJmpCondHelper(int32_t offset
, bool negate
, SSATmp
* src
);
674 void emitJmpHelper(int32_t taken
, int32_t next
, bool negate
,
675 bool bothPaths
, SSATmp
* src
);
676 SSATmp
* emitIncDec(bool pre
, bool inc
, bool over
, SSATmp
* src
);
677 template<class Lambda
>
678 SSATmp
* emitIterInitCommon(int offset
, Lambda genFunc
, bool invertCond
);
679 BCMarker
makeMarker(Offset bcOff
);
681 template<class Lambda
>
682 SSATmp
* emitMIterInitCommon(int offset
, Lambda genFunc
);
683 SSATmp
* staticTVCns(const TypedValue
*);
684 void emitJmpSurpriseCheck(Block
* catchBlock
);
685 void emitRetSurpriseCheck(SSATmp
* retVal
, Block
* catchBlock
,
686 bool suspendingResumed
);
687 void classExistsImpl(ClassKind
);
689 folly::Optional
<Type
> interpOutputType(const NormalizedInstruction
&,
690 folly::Optional
<Type
>&) const;
691 smart::vector
<InterpOneData::LocalType
>
692 interpOutputLocals(const NormalizedInstruction
&, bool& smashAll
,
693 folly::Optional
<Type
> pushedType
);
695 private: // Exit trace creation routines.
696 Block
* makeExit(Offset targetBcOff
= -1);
697 Block
* makeExit(Offset targetBcOff
, std::vector
<SSATmp
*>& spillValues
);
698 Block
* makeExitWarn(Offset targetBcOff
, std::vector
<SSATmp
*>& spillValues
,
699 const StringData
* warning
);
701 SSATmp
* promoteBool(SSATmp
* src
);
702 Opcode
promoteBinaryDoubles(Op op
, SSATmp
*& src1
, SSATmp
*& src2
);
704 void emitBinaryBitOp(Op op
);
705 void emitBinaryArith(Op op
);
708 * Create a custom side exit---that is, an exit that does some
709 * amount work before leaving the trace.
711 * The exit trace will spill things with for the current bytecode instruction.
713 * Then it will do an ExceptionBarrier, followed by whatever is done by the
714 * CustomExit() function. Any instructions emitted by the custom exit will go
715 * to the exit trace, and it may return an additional SSATmp* to spill on the
716 * stack. If there is no additional SSATmp*, it should return nullptr.
718 * TODO(#2447661): this should be way better than this, should allow
719 * using gen/push/spillStack/etc.
721 template<class ExitLambda
>
722 Block
* makeSideExit(Offset targetBcOff
, ExitLambda exit
);
725 * Generates an exit trace which will continue execution without HHIR.
726 * This should be used in situations that HHIR cannot handle -- ideally
727 * only in slow paths.
729 Block
* makeExitSlow();
730 Block
* makeExitOpt(TransID transId
);
732 template<typename Body
>
733 Block
* makeCatchImpl(Body body
);
734 Block
* makeCatch(std::vector
<SSATmp
*> extraSpill
=
735 std::vector
<SSATmp
*>(),
737 Block
* makeCatchNoSpill();
740 * Create a block for a branch target that will be generated later.
742 Block
* makeBlock(Offset offset
);
745 * Implementation for the above. Takes spillValues, target offset,
746 * and a flag for whether to make a no-IR exit.
748 * Also takes a CustomExit() function that may perform more operations and
749 * optionally return a single additional SSATmp* (otherwise nullptr) to spill
750 * on the stack before exiting.
752 enum class ExitFlag
{
753 Interp
, // will bail to the interpreter to execute at least one BC instr
754 JIT
, // will attempt to use the JIT to create a new translation
755 // DelayedMarker means to use the current instruction marker
756 // instead of one for targetBcOff.
759 typedef std::function
<SSATmp
* ()> CustomExit
;
760 Block
* makeExitImpl(Offset targetBcOff
, ExitFlag flag
,
761 std::vector
<SSATmp
*>& spillValues
, const CustomExit
&);
765 * Accessors for the current function being compiled and its
768 const Func
* curFunc() const { return m_bcStateStack
.back().func
; }
769 Class
* curClass() const { return curFunc()->cls(); }
770 Unit
* curUnit() const { return curFunc()->unit(); }
771 Offset
bcOff() const { return m_bcStateStack
.back().bcOff
; }
772 SrcKey
curSrcKey() const { return SrcKey(curFunc(), bcOff(),
774 bool inGenerator() const { return m_bcStateStack
.back().inGenerator
; }
775 size_t spOffset() const;
776 Type
topType(uint32_t i
, TypeConstraint c
= DataTypeSpecific
) const;
780 * Predicates for testing information about the relationship of a
781 * class to the current context class.
783 bool classIsUniqueOrCtxParent(const Class
*) const;
784 bool classIsPersistentOrCtxParent(const Class
*) const;
787 * Return the SrcKey for the next HHBC (whether it is in this
790 SrcKey
nextSrcKey() const {
791 SrcKey srcKey
= curSrcKey();
792 srcKey
.advance(curFunc()->unit());
797 * Return the bcOffset of the next instruction (whether it is in
798 * this tracelet or not).
800 Offset
nextBcOff() const { return nextSrcKey().offset(); }
803 * Helpers for resolving bytecode immediate ids.
805 ArrayData
* lookupArrayId(int arrId
);
806 StringData
* lookupStringId(int strId
);
807 Func
* lookupFuncId(int funcId
);
808 PreClass
* lookupPreClassId(int preClassId
);
809 const NamedEntityPair
& lookupNamedEntityPairId(int id
);
810 const NamedEntity
* lookupNamedEntityId(int id
);
813 * Eval stack helpers.
815 SSATmp
* push(SSATmp
* tmp
);
816 SSATmp
* pushIncRef(SSATmp
* tmp
, TypeConstraint tc
= DataTypeCountness
);
817 SSATmp
* pop(Type type
, TypeConstraint tc
= DataTypeSpecific
);
818 void popDecRef(Type type
, TypeConstraint tc
= DataTypeCountness
);
819 void discard(unsigned n
);
820 SSATmp
* popC(TypeConstraint tc
= DataTypeSpecific
) {
821 return pop(Type::Cell
, tc
);
823 SSATmp
* popV() { return pop(Type::BoxedCell
); }
824 SSATmp
* popR() { return pop(Type::Gen
); }
825 SSATmp
* popA() { return pop(Type::Cls
); }
826 SSATmp
* popF(TypeConstraint tc
= DataTypeSpecific
) {
827 return pop(Type::Gen
, tc
);
829 SSATmp
* top(TypeConstraint tc
, uint32_t offset
= 0) const;
830 SSATmp
* top(Type type
, uint32_t index
= 0,
831 TypeConstraint tc
= DataTypeSpecific
);
832 SSATmp
* topC(uint32_t i
= 0, TypeConstraint tc
= DataTypeSpecific
) {
833 return top(Type::Cell
, i
, tc
);
835 SSATmp
* topV(uint32_t i
= 0) { return top(Type::BoxedCell
, i
); }
836 SSATmp
* topR(uint32_t i
= 0) { return top(Type::Gen
, i
); }
837 std::vector
<SSATmp
*> peekSpillValues() const;
838 SSATmp
* emitSpillStack(SSATmp
* sp
,
839 const std::vector
<SSATmp
*>& spillVals
,
840 int64_t extraOffset
= 0);
841 SSATmp
* spillStack();
842 void exceptionBarrier();
843 SSATmp
* ldStackAddr(int32_t offset
, TypeConstraint tc
);
844 void extendStack(uint32_t index
, Type type
);
845 void replace(uint32_t index
, SSATmp
* tmp
);
848 * Local instruction helpers.
850 SSATmp
* ldLoc(uint32_t id
, TypeConstraint constraint
);
851 SSATmp
* ldLocAddr(uint32_t id
, TypeConstraint constraint
);
853 SSATmp
* ldLocInner(uint32_t id
, Block
* exit
,
854 TypeConstraint constraint
);
855 SSATmp
* ldLocInnerWarn(uint32_t id
, Block
* target
,
856 TypeConstraint constraint
,
857 Block
* catchBlock
= nullptr);
859 SSATmp
* pushStLoc(uint32_t id
, Block
* exit
, SSATmp
* newVal
);
860 SSATmp
* stLoc(uint32_t id
, Block
* exit
, SSATmp
* newVal
);
861 SSATmp
* stLocNRC(uint32_t id
, Block
* exit
, SSATmp
* newVal
);
862 SSATmp
* stLocImpl(uint32_t id
, Block
*, SSATmp
* newVal
, bool doRefCount
);
865 // Tracks information about the current bytecode offset and which
866 // function we are in. Goes in m_bcStateStack; we push and pop as
867 // we deal with inlined calls.
869 explicit BcState(Offset bcOff
, bool inGenerator
, const Func
* func
)
871 , inGenerator(inGenerator
)
882 std::unique_ptr
<IRBuilder
> const m_irb
;
884 std::vector
<BcState
> m_bcStateStack
;
886 // The first HHBC offset for this tracelet
887 const Offset m_startBcOff
;
889 // True if we're on the last HHBC opcode that will be emitted for
893 // True if we've emitted an instruction that already handled
894 // end-of-tracelet duties. (E.g. emitRetC, etc.) If it's not true,
895 // we'll create a generic ReqBindJmp instruction after we're done.
899 * The FPI stack is used for inlining---when we start inlining at an
900 * FCall, we look in here to find a definition of the StkPtr,offset
901 * that can be used after the inlined callee "returns".
903 std::stack
<std::pair
<SSATmp
*,int32_t>> m_fpiStack
;
906 * When we know that a call site is being inlined we add its StkPtr
907 * offset pair to this stack to prevent it from being erroneously
908 * popped during an FCall.
910 * XXX: There should be a better way to do this. We don't allow
911 * the tracelet to break during inlining so if we're careful it
912 * should be possible to make sure FPush* and FCall[Array|Builtin]
913 * is always matched with corresponding push()/pop().
915 std::stack
<std::pair
<SSATmp
*,int32_t>> m_fpiActiveStack
;
920 //////////////////////////////////////////////////////////////////////
922 }} // namespace HPHP::JIT