Free generator locals at return / frame unwind.
[hiphop-php.git] / hphp / runtime / vm / jit / translator.h
blobbbbe6462a8f97dce772f1c3c30de47c611d6ae56
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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_TRANSLATOR_H_
17 #define incl_HPHP_TRANSLATOR_H_
19 #include <limits.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <assert.h>
23 #include <memory>
24 #include <map>
25 #include <vector>
26 #include <set>
28 #include <boost/dynamic_bitset.hpp>
30 #include "hphp/util/md5.h"
31 #include "hphp/util/hash.h"
32 #include "hphp/util/timer.h"
33 #include "hphp/util/hash-map-typedefs.h"
34 #include "hphp/runtime/base/execution-context.h"
35 #include "hphp/runtime/base/smart-containers.h"
36 #include "hphp/runtime/vm/bytecode.h"
37 #include "hphp/runtime/vm/jit/block.h"
38 #include "hphp/runtime/vm/jit/fixup.h"
39 #include "hphp/runtime/vm/jit/runtime-type.h"
40 #include "hphp/runtime/vm/jit/srcdb.h"
41 #include "hphp/runtime/vm/jit/translator-instrs.h"
42 #include "hphp/runtime/vm/jit/write-lease.h"
43 #include "hphp/runtime/vm/jit/prof-data.h"
44 #include "hphp/runtime/vm/jit/unique-stubs.h"
45 #include "hphp/runtime/vm/debugger-hook.h"
46 #include "hphp/runtime/vm/srckey.h"
48 /* Translator front-end. */
49 namespace HPHP {
50 namespace JIT {
51 struct HhbcTranslator;
52 struct IRTranslator;
54 namespace Debug {
55 struct DebugInfo;
57 namespace JIT {
60 static const uint32_t transCountersPerChunk = 1024 * 1024 / 8;
63 * DIRTY when the live register state is spread across the stack and m_fixup,
64 * CLEAN when it has been sync'ed into g_context.
66 enum class VMRegState {
67 CLEAN,
68 DIRTY
70 extern __thread VMRegState tl_regState;
72 struct NormalizedInstruction;
74 // A DynLocation is a Location-in-execution: a location, along with
75 // whatever is known about its runtime type.
76 struct DynLocation {
77 Location location;
78 RuntimeType rtt;
80 DynLocation(Location l, DataType t) : location(l), rtt(t) {}
82 DynLocation(Location l, RuntimeType t) : location(l), rtt(t) {}
84 DynLocation() : location(), rtt() {}
86 bool operator==(const DynLocation& r) const {
87 return rtt == r.rtt && location == r.location;
90 // Hash function
91 size_t operator()(const DynLocation &dl) const {
92 uint64_t rtthash = rtt(rtt);
93 uint64_t locHash = location(location);
94 return rtthash ^ locHash;
97 std::string pretty() const {
98 return Trace::prettyNode("DynLocation", location, rtt);
101 // Punch through a bunch of frequently called rtt and location methods.
102 // While this is unlovely here, we use DynLocation in bazillions of
103 // places in the translator, and constantly saying ".rtt" is worse.
104 bool isString() const {
105 return rtt.isString();
107 bool isInt() const {
108 return rtt.isInt();
110 bool isDouble() const {
111 return rtt.isDouble();
113 bool isBoolean() const {
114 return rtt.isBoolean();
116 bool isRef() const {
117 return rtt.isRef();
119 bool isRefToObject() const {
120 return rtt.isRef() && innerType() == KindOfObject;
122 bool isValue() const {
123 return rtt.isValue();
125 bool isNull() const {
126 return rtt.isNull();
128 bool isObject() const {
129 return rtt.isObject();
131 bool isArray() const {
132 return rtt.isArray();
134 DataType valueType() const {
135 return rtt.valueType();
137 DataType innerType() const {
138 return rtt.innerType();
140 DataType outerType() const {
141 return rtt.outerType();
144 bool isStack() const {
145 return location.isStack();
147 bool isLocal() const {
148 return location.isLocal();
150 bool isLiteral() const {
151 return location.isLiteral();
154 // Uses the runtime state. True if this dynLocation can be overwritten by
155 // SetG's and SetM's.
156 bool canBeAliased() const;
159 // Flags that summarize the plan for handling a given instruction.
160 enum TXFlags {
161 Interp = 0, // default; must be boolean false
162 Supported = 1, // Not interpreted, though possibly with C++
163 NonReentrant = 2, // Supported with no possibility of reentry.
164 MachineCode = 4, // Supported without C++ at all.
165 Simple = NonReentrant | Supported,
166 Native = MachineCode | Simple
169 struct Tracelet;
170 struct TraceletContext;
172 // Return a summary string of the bytecode in a tracelet.
173 std::string traceletShape(const Tracelet&);
175 struct TranslationFailedExc : std::runtime_error {
176 TranslationFailedExc(const char* file, int line)
177 : std::runtime_error(folly::format("TranslationFailedExc @ {}:{}",
178 file, line).str())
182 struct UnknownInputExc : std::runtime_error {
183 UnknownInputExc(const char* file, int line)
184 : std::runtime_error(folly::format("UnknownInputExc @ {}:{}",
185 file, line).str())
186 , m_file(file)
187 , m_line(line)
190 const char* m_file; // must be static
191 const int m_line;
194 struct ControlFlowFailedExc : std::runtime_error {
195 ControlFlowFailedExc(const char* file, int line)
196 : std::runtime_error(folly::format("ControlFlowFailedExc @ {}:{}",
197 file, line).str())
201 #define punt() do { \
202 throw JIT::TranslationFailedExc(__FILE__, __LINE__); \
203 } while(0)
205 #define throwUnknownInput() do { \
206 throw JIT::UnknownInputExc(__FILE__, __LINE__); \
207 } while(0);
209 struct GuardType {
210 explicit GuardType(DataType outer = KindOfAny,
211 DataType inner = KindOfNone);
212 explicit GuardType(const RuntimeType& rtt);
213 GuardType(const GuardType& other);
214 const DataType getOuterType() const;
215 const DataType getInnerType() const;
216 const Class* getSpecializedClass() const;
217 bool isSpecific() const;
218 bool isSpecialized() const;
219 bool isRelaxed() const;
220 bool isGeneric() const;
221 bool isCounted() const;
222 bool isMoreRefinedThan(const GuardType& other) const;
223 bool mayBeUninit() const;
224 GuardType getCountness() const;
225 GuardType getCountnessInit() const;
226 DataTypeCategory getCategory() const;
227 GuardType dropSpecialization() const;
228 RuntimeType getRuntimeType() const;
229 bool isEqual(GuardType other) const;
230 bool hasArrayKind() const;
231 ArrayData::ArrayKind getArrayKind() const;
233 private:
234 DataType outerType;
235 DataType innerType;
236 union {
237 const Class* klass;
238 struct {
239 bool arrayKindValid;
240 ArrayData::ArrayKind arrayKind;
245 typedef hphp_hash_map<Location,RuntimeType,Location> TypeMap;
246 typedef hphp_hash_set<Location, Location> LocationSet;
247 typedef hphp_hash_map<DynLocation*, GuardType> DynLocTypeMap;
248 typedef hphp_hash_map<RegionDesc::BlockId, Block*> BlockIdToIRBlockMap;
249 typedef hphp_hash_map<RegionDesc::BlockId,
250 RegionDesc::Block*> BlockIdToRegionBlockMap;
254 const char* getTransKindName(TransKind kind);
257 * Used to maintain a mapping from the bytecode to its corresponding x86.
259 struct TransBCMapping {
260 MD5 md5;
261 Offset bcStart;
262 TCA aStart;
263 TCA astubsStart;
267 * A record with various information about a translation.
269 struct TransRec {
270 TransID id;
271 TransKind kind;
272 SrcKey src;
273 MD5 md5;
274 Offset bcStopOffset;
275 std::vector<DynLocation>
276 dependencies;
277 TCA aStart;
278 uint32_t aLen;
279 TCA astubsStart;
280 uint32_t astubsLen;
281 std::vector<TransBCMapping>
282 bcMapping;
284 TransRec() {}
286 TransRec(SrcKey s,
287 MD5 _md5,
288 TransKind _kind,
289 TCA _aStart = 0,
290 uint32_t _aLen = 0,
291 TCA _astubsStart = 0,
292 uint32_t _astubsLen = 0) :
293 id(0), kind(_kind), src(s), md5(_md5), bcStopOffset(0),
294 aStart(_aStart), aLen(_aLen),
295 astubsStart(_astubsStart), astubsLen(_astubsLen)
298 TransRec(SrcKey s,
299 MD5 _md5,
300 TransKind _kind,
301 const Tracelet* t,
302 TCA _aStart = 0,
303 uint32_t _aLen = 0,
304 TCA _astubsStart = 0,
305 uint32_t _astubsLen = 0,
306 std::vector<TransBCMapping> _bcMapping =
307 std::vector<TransBCMapping>());
309 void setID(TransID newID) { id = newID; }
310 std::string print(uint64_t profCount) const;
313 struct TranslArgs {
314 TranslArgs(const SrcKey& sk, bool align)
315 : m_sk(sk)
316 , m_align(align)
317 , m_interp(false)
318 , m_setFuncBody(false)
319 , m_transId(InvalidID)
320 , m_region(nullptr)
323 TranslArgs& sk(const SrcKey& sk) {
324 m_sk = sk;
325 return *this;
327 TranslArgs& align(bool align) {
328 m_align = align;
329 return *this;
331 TranslArgs& interp(bool interp) {
332 m_interp = interp;
333 return *this;
335 TranslArgs& setFuncBody() {
336 m_setFuncBody = true;
337 return *this;
339 TranslArgs& transId(TransID transId) {
340 m_transId = transId;
341 return *this;
343 TranslArgs& region(JIT::RegionDescPtr region) {
344 m_region = region;
345 return *this;
348 SrcKey m_sk;
349 bool m_align;
350 bool m_interp;
351 bool m_setFuncBody;
352 TransID m_transId;
353 JIT::RegionDescPtr m_region;
356 class Translator;
357 extern Translator* tx;
360 * Translator annotates a tracelet with input/output locations/types.
362 struct Translator {
363 // kMaxInlineReturnDecRefs is the maximum ref-counted locals to
364 // generate an inline return for.
365 static const int kMaxInlineReturnDecRefs = 1;
367 static const int MaxJmpsTracedThrough = 5;
369 JIT::UniqueStubs uniqueStubs;
371 private:
372 friend struct TraceletContext;
374 void analyzeCallee(TraceletContext&,
375 Tracelet& parent,
376 NormalizedInstruction* fcall);
377 bool applyInputMetaData(Unit::MetaHandle&,
378 NormalizedInstruction* ni,
379 TraceletContext& tas,
380 InputInfos& ii);
381 void handleAssertionEffects(Tracelet&,
382 const NormalizedInstruction&,
383 TraceletContext&,
384 int currentStackOffset);
385 void getOutputs(Tracelet& t,
386 NormalizedInstruction* ni,
387 int& currentStackOffset,
388 bool& varEnvTaint);
389 void relaxDeps(Tracelet& tclet, TraceletContext& tctxt);
390 void constrainDep(const DynLocation* loc,
391 NormalizedInstruction* firstInstr,
392 GuardType specType,
393 GuardType& relxType);
394 DataTypeCategory getOperandConstraintCategory(NormalizedInstruction* instr,
395 size_t opndIdx,
396 const GuardType& specType);
397 GuardType getOperandConstraintType(NormalizedInstruction* instr,
398 size_t opndIdx,
399 const GuardType& specType);
401 void constrainOperandType(GuardType& relxType,
402 NormalizedInstruction* instr,
403 size_t opndIdx,
404 const GuardType& specType);
407 RuntimeType liveType(Location l, const Unit &u, bool specialize = false);
408 RuntimeType liveType(const Cell* outer,
409 const Location& l,
410 bool specialize = false);
412 void createBlockMaps(const RegionDesc& region,
413 BlockIdToIRBlockMap& blockIdToIRBlock,
414 BlockIdToRegionBlockMap& blockIdToRegionBlock);
416 void setSuccIRBlocks(const RegionDesc& region,
417 RegionDesc::BlockId srcBlockId,
418 const BlockIdToIRBlockMap& blockIdToIRBlock,
419 const BlockIdToRegionBlockMap& blockIdToRegionBlock);
421 void setIRBlock(RegionDesc::BlockId blockId,
422 const BlockIdToIRBlockMap& blockIdToIRBlock,
423 const BlockIdToRegionBlockMap& blockIdToRegionBlock);
425 public:
426 enum TranslateResult {
427 Failure,
428 Retry,
429 Success
431 static const char* translateResultName(TranslateResult r);
432 void traceStart(Offset initBcOffset, Offset initSpOffset, bool inGenerator,
433 const Func* func);
434 void traceEnd();
435 void traceFree();
437 void requestResetHighLevelTranslator();
439 public:
440 /* translateRegion reads from the RegionBlacklist to determine when
441 * to interpret an instruction, and adds failed instructions to the
442 * blacklist so they're interpreted on the next attempt. */
443 typedef hphp_hash_set<SrcKey, SrcKey::Hasher> RegionBlacklist;
444 TranslateResult translateRegion(const RegionDesc& region,
445 bool bcControlFlow,
446 RegionBlacklist& interp);
448 private:
449 typedef std::map<TCA, TransID> TransDB;
450 TransDB m_transDB;
451 std::vector<TransRec> m_translations;
452 std::vector<uint64_t*> m_transCounters;
454 int64_t m_createdTime;
456 std::unique_ptr<JIT::IRTranslator> m_irTrans;
458 public:
459 JIT::IRTranslator* irTrans() {
460 return m_irTrans.get();
463 private:
464 SrcDB m_srcDB;
466 static Lease s_writeLease;
468 public:
470 Translator();
472 static Lease& WriteLease() {
473 return s_writeLease;
475 static RuntimeType outThisObjectType();
477 const TransDB& getTransDB() const {
478 return m_transDB;
481 const TransRec* getTransRec(TCA tca) const {
482 if (!isTransDBEnabled()) return nullptr;
484 TransDB::const_iterator it = m_transDB.find(tca);
485 if (it == m_transDB.end()) {
486 return nullptr;
488 if (it->second >= m_translations.size()) {
489 return nullptr;
491 return &m_translations[it->second];
494 const TransRec* getTransRec(TransID transId) const {
495 if (!isTransDBEnabled()) return nullptr;
497 always_assert(transId < m_translations.size());
498 return &m_translations[transId];
501 TransID getCurrentTransID() const {
502 return m_translations.size();
505 uint64_t* getTransCounterAddr();
506 uint64_t getTransCounter(TransID transId) const;
508 void addTranslation(const TransRec& transRec);
510 // helpers for srcDB.
511 SrcRec* getSrcRec(SrcKey sk) {
512 // TODO: add a insert-or-find primitive to THM
513 if (SrcRec* r = m_srcDB.find(sk)) return r;
514 assert(s_writeLease.amOwner());
515 return m_srcDB.insert(sk);
518 const SrcDB& getSrcDB() const {
519 return m_srcDB;
523 * Create a Tracelet for the given SrcKey, which must actually be
524 * the current VM frame.
526 * XXX The analysis pass will inspect the live state of the VM stack
527 * as needed to determine the current types of in-flight values.
529 std::unique_ptr<Tracelet> analyze(SrcKey sk, const TypeMap& = TypeMap());
531 void postAnalyze(NormalizedInstruction* ni, SrcKey& sk,
532 Tracelet& t, TraceletContext& tas);
533 static bool liveFrameIsPseudoMain();
535 inline bool stateIsDirty() {
536 return tl_regState == VMRegState::DIRTY;
539 inline bool isTransDBEnabled() const {
540 return debug || RuntimeOption::EvalDumpTC;
543 private:
544 PCFilter m_dbgBLPC;
545 hphp_hash_set<SrcKey,SrcKey::Hasher> m_dbgBLSrcKey;
546 Mutex m_dbgBlacklistLock;
548 public:
549 bool isSrcKeyInBL(const SrcKey& sk);
551 private:
552 TransKind m_mode;
553 std::unique_ptr<ProfData> m_profData;
555 private:
556 int m_analysisDepth;
558 public:
559 void clearDbgBL();
560 bool addDbgBLPC(PC pc);
562 ProfData* profData() const {
563 return m_profData.get();
566 TransKind mode() const {
567 return m_mode;
569 void setMode(TransKind mode) {
570 m_mode = mode;
573 int analysisDepth() const {
574 assert(m_analysisDepth >= 0);
575 return m_analysisDepth;
578 // Start a new translation space. Returns true IFF this thread created
579 // a new space.
580 bool replace();
583 int getStackDelta(const NormalizedInstruction& ni);
584 int64_t getStackPopped(PC pc);
585 int64_t getStackPushed(PC pc);
587 enum class ControlFlowInfo {
588 None,
589 ChangesPC,
590 BreaksBB
593 inline ControlFlowInfo
594 opcodeControlFlowInfo(const Op instr) {
595 switch (instr) {
596 case Op::Jmp:
597 case Op::JmpNS:
598 case Op::JmpZ:
599 case Op::JmpNZ:
600 case Op::Switch:
601 case Op::SSwitch:
602 case Op::CreateCont:
603 case Op::ContSuspend:
604 case Op::ContSuspendK:
605 case Op::AsyncSuspend:
606 case Op::RetC:
607 case Op::RetV:
608 case Op::Exit:
609 case Op::Fatal:
610 case Op::IterNext:
611 case Op::IterNextK:
612 case Op::MIterNext:
613 case Op::MIterNextK:
614 case Op::WIterNext:
615 case Op::WIterNextK:
616 case Op::IterInit: // May branch to fail case.
617 case Op::IterInitK: // Ditto
618 case Op::MIterInit: // Ditto
619 case Op::MIterInitK: // Ditto
620 case Op::WIterInit: // Ditto
621 case Op::WIterInitK: // Ditto
622 case Op::DecodeCufIter: // Ditto
623 case Op::IterBreak:
624 case Op::Throw:
625 case Op::Unwind:
626 case Op::Eval:
627 case Op::NativeImpl:
628 case Op::BreakTraceHint:
629 return ControlFlowInfo::BreaksBB;
630 case Op::FCall:
631 case Op::FCallD:
632 case Op::FCallArray:
633 case Op::ContEnter:
634 case Op::ContRaise:
635 case Op::Incl:
636 case Op::InclOnce:
637 case Op::Req:
638 case Op::ReqOnce:
639 case Op::ReqDoc:
640 return ControlFlowInfo::ChangesPC;
641 default:
642 return ControlFlowInfo::None;
647 * opcodeChangesPC --
649 * Returns true if the instruction can potentially set PC to point
650 * to something other than the next instruction in the bytecode
652 inline bool
653 opcodeChangesPC(const Op instr) {
654 return opcodeControlFlowInfo(instr) >= ControlFlowInfo::ChangesPC;
658 * opcodeBreaksBB --
660 * Returns true if the instruction always breaks a tracelet. Most
661 * instructions that change PC will break the tracelet, though some
662 * do not (ex. FCall).
664 inline bool
665 opcodeBreaksBB(const Op instr) {
666 return opcodeControlFlowInfo(instr) == ControlFlowInfo::BreaksBB;
670 * instrBreaksProfileBB --
672 * Similar to opcodeBreaksBB but more strict. We break profiling blocks after
673 * any instruction that can side exit, including instructions with predicted
674 * output.
676 bool instrBreaksProfileBB(const NormalizedInstruction* instr);
679 * If this returns true, we dont generate guards for any of the inputs
680 * to this instruction (this is essentially to avoid generating guards
681 * on behalf of interpreted instructions).
683 bool dontGuardAnyInputs(Op op);
684 bool outputDependsOnInput(const Op instr);
686 extern bool tc_dump();
689 * This routine attempts to find the Func* that will be called for a
690 * given target Class and function name, from a given context. This
691 * function determines if a given Func* will be called in a
692 * request-insensitive way (i.e. suitable for burning into the TC as a
693 * pointer). The class we are targeting is assumed to be a subclass
694 * of `cls', not exactly `cls'.
696 * This function should not be used in a context where the call may
697 * involve late static binding (i.e. FPushClsMethod), since it assumes
698 * static functions will be resolved as targeting on cls regardless of
699 * whether they are overridden.
701 * Returns nullptr if we can't be sure this would always call this
702 * function.
704 const Func* lookupImmutableMethod(const Class* cls, const StringData* name,
705 bool& magicCall, bool staticLookup,
706 Class* ctx);
708 // This is used to check that return types of builtins are not simple
709 // types. This is different from IS_REFCOUNTED_TYPE because builtins
710 // can return Variants, and we use KindOfUnknown to denote these
711 // return types.
712 static inline bool isCppByRef(DataType t) {
713 return t != KindOfBoolean && t != KindOfInt64 &&
714 t != KindOfNull && t != KindOfDouble;
717 // return true if type is passed in/out of C++ as String&/Array&/Object&
718 static inline bool isSmartPtrRef(DataType t) {
719 return t == KindOfString || t == KindOfStaticString ||
720 t == KindOfArray || t == KindOfObject ||
721 t == KindOfResource;
724 void populateImmediates(NormalizedInstruction&);
725 void preInputApplyMetaData(Unit::MetaHandle, NormalizedInstruction*);
726 enum class MetaMode {
727 Normal,
728 Legacy,
730 void readMetaData(Unit::MetaHandle&, NormalizedInstruction&, HhbcTranslator&,
731 bool profiling, MetaMode m = MetaMode::Normal);
732 bool instrMustInterp(const NormalizedInstruction&);
734 typedef std::function<Type(int)> LocalTypeFn;
735 void getInputs(SrcKey startSk, NormalizedInstruction& inst, InputInfos& infos,
736 const Func* func, const LocalTypeFn& localType);
737 void getInputsImpl(SrcKey startSk, NormalizedInstruction* inst,
738 int& currentStackOffset, InputInfos& inputs,
739 const Func* func, const LocalTypeFn& localType);
740 bool outputIsPredicted(NormalizedInstruction& inst);
741 bool callDestroysLocals(const NormalizedInstruction& inst,
742 const Func* caller);
743 int locPhysicalOffset(Location l, const Func* f = nullptr);
744 bool shouldAnalyzeCallee(const NormalizedInstruction*, const FPIEnt*,
745 const Op, const int);
747 namespace InstrFlags {
748 enum OutTypeConstraints {
749 OutNull,
750 OutNullUninit,
751 OutString,
752 OutStringImm, // String w/ precisely known immediate.
753 OutDouble,
754 OutBoolean,
755 OutBooleanImm,
756 OutInt64,
757 OutArray,
758 OutArrayImm,
759 OutObject,
760 OutResource,
761 OutThisObject, // Object from current environment
762 OutFDesc, // Blows away the current function desc
764 OutUnknown, // Not known at tracelet compile-time
765 OutPred, // Unknown, but give prediction a whirl.
766 OutCns, // Constant; may be known at compile-time
767 OutVUnknown, // type is V(unknown)
769 OutSameAsInput, // type is the same as the first stack inpute
770 OutCInput, // type is C(input)
771 OutVInput, // type is V(input)
772 OutCInputL, // type is C(type) of local input
773 OutVInputL, // type is V(type) of local input
774 OutFInputL, // type is V(type) of local input if current param is
775 // by ref, else type is C(type) of local input
776 OutFInputR, // Like FInputL, but for R's on the stack.
778 OutArith, // For Add, Sub, Mul
779 OutArithO, // For AddO, SubO, MulO
780 OutBitOp, // For BitAnd, BitOr, BitXor
781 OutSetOp, // For SetOpL
782 OutIncDec, // For IncDecL
783 OutStrlen, // OpStrLen
784 OutClassRef, // KindOfClass
785 OutFPushCufSafe, // FPushCufSafe pushes two values of different
786 // types and an ActRec
787 OutAsyncAwait, // AwaitHandle pushes its input and then a bool
789 OutNone,
793 * Input codes indicate what an instruction reads, and some other
794 * things about their behavior. The order these show up in the inputs
795 * vector is given in getInputs(), and is relevant in a few cases
796 * (e.g. instructions taking both stack inputs and MVectors).
798 enum Operands {
799 None = 0,
800 Stack3 = 1 << 0,
801 Stack2 = 1 << 1,
802 Stack1 = 1 << 2,
803 StackIns1 = 1 << 3, // Insert an element under top of stack
804 StackIns2 = 1 << 4, // Insert an element under top 2 of stack
805 FuncdRef = 1 << 5, // Input to FPass*
806 FStack = 1 << 6, // output of FPushFuncD and friends
807 Local = 1 << 7, // Writes to a local
808 MVector = 1 << 8, // Member-vector input
809 Iter = 1 << 9, // Iterator in imm[0]
810 AllLocals = 1 << 10, // All locals (used by RetC)
811 DontGuardStack1 = 1 << 11, // Dont force a guard on behalf of stack1 input
812 IgnoreInnerType = 1 << 12, // Instruction doesnt care about the inner types
813 DontGuardAny = 1 << 13, // Dont force a guard for any input
814 This = 1 << 14, // Input to CheckThis
815 StackN = 1 << 15, // pop N cells from stack; n = imm[0].u_IVA
816 BStackN = 1 << 16, // consume N cells from stack for builtin call;
817 // n = imm[0].u_IVA
818 StackTop2 = Stack1 | Stack2,
819 StackTop3 = Stack1 | Stack2 | Stack3,
822 inline Operands operator|(const Operands& l, const Operands& r) {
823 return Operands(int(r) | int(l));
827 struct InstrInfo {
828 InstrFlags::Operands in;
829 InstrFlags::Operands out;
830 InstrFlags::OutTypeConstraints type; // How are outputs related to inputs?
831 int numPushed;
834 const InstrInfo& getInstrInfo(Op op);
836 typedef const int COff; // Const offsets
838 } } // HPHP::JIT
840 #endif