Free generator locals at return / frame unwind.
[hiphop-php.git] / hphp / runtime / vm / jit / hhbc-translator.h
blob2d171a615f32ec41147dc56e808c48f602b4257f
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <vector>
21 #include <memory>
22 #include <stack>
23 #include <utility>
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"
37 namespace HPHP {
38 namespace JIT {
40 struct PropInfo;
42 enum class IRGenMode {
43 Trace,
44 CFG,
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
65 * made at this level.
67 struct HhbcTranslator {
68 HhbcTranslator(Offset startOffset,
69 uint32_t initialSpOffsetFromFp,
70 bool inGenerator,
71 const Func* func);
73 // Accessors.
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);
87 void end();
88 void end(Offset nextPc);
90 // Tracelet guards.
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,
94 bool outerOnly);
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,
107 Offset dest);
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,
114 const Func* target,
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,
130 InterpOneData& id);
131 std::string showStack() const;
132 bool hasExit() const {
133 return m_hasExit;
137 * An emit* function for each HHBC opcode.
140 void emitPrint();
141 void emitThis();
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);
150 void emitClone();
152 void emitArrayAdd();
153 void emitAddElemC();
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);
163 void emitConcat();
164 void emitDefCls(int id, Offset after);
165 void emitDefFunc(int id);
167 void emitLateBoundCls();
168 void emitSelf();
169 void emitParent();
171 void emitString(int strId);
172 void emitInt(int64_t val);
173 void emitDouble(double val);
174 void emitNullUninit();
175 void emitNull();
176 void emitTrue();
177 void emitFalse();
178 void emitCGetL(int32_t id);
179 void emitFPassL(int32_t id);
180 void emitPushL(uint32_t id);
181 void emitCGetL2(int32_t id);
182 void emitCGetS();
183 void emitCGetG();
184 void emitMInstr(const NormalizedInstruction& ni);
185 void emitVGetL(int32_t id);
186 void emitVGetS();
187 void emitVGetG();
188 void emitSetL(int32_t id);
189 void emitSetS();
190 void emitSetG();
191 void emitBindL(int32_t id);
192 void emitBindS();
193 void emitBindG();
194 void emitUnsetL(int32_t id);
195 void emitIssetL(int32_t id);
196 void emitIssetS();
197 void emitIssetG();
198 void emitEmptyL(int32_t id);
199 void emitEmptyS();
200 void emitEmptyG();
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);
206 void emitPopA();
207 void emitPopC();
208 void emitPopV();
209 void emitPopR();
210 void emitDup();
211 void emitUnboxR();
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); }
226 void emitFPassCOp();
227 void emitFPassR();
228 void emitFPassV();
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,
238 int32_t numParams);
239 void emitFPushFuncD(int32_t numParams, int32_t funcId);
240 void emitFPushFuncU(int32_t numParams,
241 int32_t funcId,
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,
255 int32_t numParams,
256 bool shouldFatal,
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,
263 SSATmp* obj,
264 const Func* func,
265 int32_t numParams);
266 void emitCreateCl(int32_t numParams, int32_t classNameStrId);
267 void emitFCallArray(const Offset pcOffset, const Offset after,
268 bool destroyLocals);
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);
275 void emitAKExists();
276 void emitAGetC();
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();
286 void emitNop() {}
287 void emitCastBool();
288 void emitCastInt();
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);
302 // miscelaneous ops
303 void emitFloor();
304 void emitCeil();
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);
314 // arithmetic ops
315 void emitAdd();
316 void emitSub();
317 void emitMul();
318 void emitBitAnd();
319 void emitBitOr();
320 void emitBitXor();
321 void emitBitNot();
322 void emitAbs();
323 void emitMod();
324 void emitDiv();
325 void emitSqrt();
326 void emitShl();
327 void emitShr();
328 void emitAddO();
329 void emitSubO();
330 void emitMulO();
332 // boolean ops
333 void emitXor();
334 void emitNot();
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);
345 // iterators
346 void emitIterInit(uint32_t iterId,
347 int targetOffset,
348 uint32_t valLocalId,
349 bool invertCond);
350 void emitIterInitK(uint32_t iterId,
351 int targetOffset,
352 uint32_t valLocalId,
353 uint32_t keyLocalId,
354 bool invertCond);
355 void emitIterNext(uint32_t iterId,
356 int targetOffset,
357 uint32_t valLocalId,
358 bool invertCond);
359 void emitIterNextK(uint32_t iterId,
360 int targetOffset,
361 uint32_t valLocalId,
362 uint32_t keyLocalId,
363 bool invertCond);
364 void emitMIterInit(uint32_t iterId, int targetOffset, uint32_t valLocalId);
365 void emitMIterInitK(uint32_t iterId,
366 int targetOffset,
367 uint32_t valLocalId,
368 uint32_t keyLocalId);
369 void emitMIterNext(uint32_t iterId, int targetOffset, uint32_t valLocalId);
370 void emitMIterNextK(uint32_t iterId,
371 int targetOffset,
372 uint32_t valLocalId,
373 uint32_t keyLocalId);
374 void emitWIterInit(uint32_t iterId,
375 int targetOffset,
376 uint32_t valLocalId,
377 bool invertCond);
378 void emitWIterInitK(uint32_t iterId,
379 int targetOffset,
380 uint32_t valLocalId,
381 uint32_t keyLocalId,
382 bool invertCond);
383 void emitWIterNext(uint32_t iterId,
384 int targetOffset,
385 uint32_t valLocalId,
386 bool invertCond);
387 void emitWIterNextK(uint32_t iterId,
388 int targetOffset,
389 uint32_t valLocalId,
390 uint32_t keyLocalId,
391 bool invertCond);
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);
400 // continuations
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();
408 void emitContKey();
409 void emitContCurrent();
410 void emitContStopped();
412 // async functions
413 void emitAsyncAwait();
414 void emitAsyncSuspendE(Offset resumeOffset, int iters);
415 void emitAsyncSuspendR(Offset resumeOffset);
417 void emitStrlen();
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();
428 void emitIdx();
429 void emitIdxCommon(Opcode opc, Block* catchBlock = nullptr);
430 void emitArrayIdx();
431 void emitIsTypeC(DataType t);
432 void emitIsTypeL(uint32_t id, DataType t);
434 private:
436 * MInstrTranslator is responsible for translating one of the vector
437 * instructions (CGetM, SetM, IssetM, etc..) into hhir.
439 class MInstrTranslator {
440 public:
441 MInstrTranslator(const NormalizedInstruction& ni,
442 HhbcTranslator& ht);
443 void emit();
445 private:
446 void checkMIState();
447 void emitMPre();
448 void emitFinalMOp();
449 void emitMPost();
450 void emitSideExits(SSATmp* catchSp, int nStack);
451 void emitMTrace();
453 // Bases
454 void emitBaseOp();
455 void emitBaseLCR();
456 void emitBaseH();
457 void emitBaseG();
458 void emitBaseN();
459 void emitBaseS();
461 // Intermediate Operations
462 void emitIntermediateOp();
463 void emitProp();
464 void emitPropGeneric();
465 void emitPropSpecialized(const MInstrAttr mia, PropInfo propInfo);
466 void emitElem();
467 void emitElemArray(SSATmp* key, bool warn);
468 void emitNewElem();
469 void emitRatchetRefs();
471 // Final Operations
472 # define MII(instr, ...) \
473 void emit##instr##Elem(); \
474 void emit##instr##Prop();
475 MINSTRS
476 # undef MII
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);
500 void emitMapIsset();
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.
510 Block* makeCatch() {
511 auto b = makeEmptyCatch();
512 m_failedVec.push_back(b);
513 return 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));
535 // Misc Helpers
536 void numberStackInputs();
537 void setNoMIState() { m_needMIS = false; }
538 SSATmp* genMisPtr();
539 SSATmp* getInput(unsigned i, TypeConstraint tc);
540 SSATmp* getBase(TypeConstraint tc);
541 SSATmp* getKey();
542 SSATmp* getValue();
543 SSATmp* getValAddr();
544 void constrainBase(TypeConstraint tc, SSATmp* value = nullptr);
545 SSATmp* checkInitProp(SSATmp* baseAsObj,
546 SSATmp* propAddr,
547 PropInfo propOffset,
548 bool warn,
549 bool define);
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
556 * if appropriate.
558 template<typename... Srcs>
559 SSATmp* genStk(Opcode op, Block* taken, Srcs... srcs);
561 /* Various predicates about the current instruction */
562 bool isSimpleBase();
563 bool isSingleMember();
565 enum class SimpleOp {
566 // the opcode is not in a simple form or not on a proper collection type
567 None,
568 // simple opcode on Array
569 Array,
570 // simple opcode on Packed Array
571 PackedArray,
572 // simple opcode on String
573 String,
574 // simple opcode on Vector* (c_Vector* or c_ImmVector*)
575 Vector,
576 // simple opcode on Map* (c_Map*)
577 Map,
578 // simple opcode on Map* (c_Pair*)
579 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;
602 IRBuilder& m_irb;
603 IRUnit& m_unit;
604 const MInstrInfo& m_mii;
605 const BCMarker m_marker;
606 hphp_hash_map<unsigned, unsigned> m_stackInputs;
608 unsigned m_mInd;
609 unsigned m_iInd;
611 bool m_needMIS;
613 /* The base for any accesses to the current MInstrState. */
614 SSATmp* m_misBase;
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
618 * progress. */
619 SSATmp* m_base;
621 /* The result of the vector instruction. nullptr if the current instruction
622 * doesn't produce a result. */
623 SSATmp* m_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
640 * operation */
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)...);
655 private:
657 * Emit helpers.
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,
663 bool& checkForInt);
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);
680 void updateMarker();
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*>(),
736 int64_t numPop = 0);
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.
757 DelayedMarker,
759 typedef std::function<SSATmp* ()> CustomExit;
760 Block* makeExitImpl(Offset targetBcOff, ExitFlag flag,
761 std::vector<SSATmp*>& spillValues, const CustomExit&);
763 public:
765 * Accessors for the current function being compiled and its
766 * class and unit.
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(),
773 inGenerator()); }
774 bool inGenerator() const { return m_bcStateStack.back().inGenerator; }
775 size_t spOffset() const;
776 Type topType(uint32_t i, TypeConstraint c = DataTypeSpecific) const;
778 private:
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
788 * tracelet or not).
790 SrcKey nextSrcKey() const {
791 SrcKey srcKey = curSrcKey();
792 srcKey.advance(curFunc()->unit());
793 return srcKey;
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);
852 private:
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);
858 public:
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);
864 private:
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.
868 struct BcState {
869 explicit BcState(Offset bcOff, bool inGenerator, const Func* func)
870 : bcOff(bcOff)
871 , inGenerator(inGenerator)
872 , func(func)
875 Offset bcOff;
876 bool inGenerator;
877 const Func* func;
880 private:
881 IRUnit m_unit;
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
890 // this tracelet.
891 bool m_lastBcOff;
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.
896 bool m_hasExit;
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;
917 IRGenMode m_mode;
920 //////////////////////////////////////////////////////////////////////
922 }} // namespace HPHP::JIT
924 #endif