2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010- 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 _TRANSLATOR_H_
18 #define _TRANSLATOR_H_
29 #include <boost/ptr_container/ptr_vector.hpp>
30 #include <util/hash.h>
31 #include <runtime/base/execution_context.h>
32 #include <runtime/vm/bytecode.h>
33 #include <runtime/vm/translator/immstack.h>
34 #include <runtime/vm/translator/runtime-type.h>
35 #include <runtime/vm/translator/fixup.h>
36 #include <runtime/vm/translator/writelease.h>
37 #include <runtime/vm/translator/trans-data.h>
38 #include <runtime/vm/debugger_hook.h>
39 #include <runtime/base/md5.h>
41 /* Translator front-end. */
46 static const bool trustSigSegv
= false;
48 static const uint32 transCountersPerChunk
= 1024 * 1024 / 8;
51 extern TranslatorX64
* volatile nextTx64
;
52 extern __thread TranslatorX64
* tx64
;
55 * REGSTATE_DIRTY when the live register state is spread across the
56 * stack and m_fixup, REGSTATE_CLEAN when it has been sync'ed into
63 extern __thread VMRegState tl_regState
;
66 * A SrcKey is a logical source instruction, currently a unit/instruction pair.
67 * The units are identified by contents rather than Unit; Unit's are
68 * ephemeral, and we want to reuse SrcKey's when we encounter Unit's with
72 Func::FuncId m_funcId
;
75 SrcKey() : m_funcId(Func::InvalidId
), m_offset(0) { }
77 SrcKey(const Func
* f
, Offset off
) :
78 m_funcId(f
->getFuncId()), m_offset(off
) { }
80 SrcKey(const Func
* f
, const Opcode
* i
) :
81 m_funcId(f
->getFuncId()), m_offset(f
->unit()->offsetOf(i
)) { }
83 int cmp(const SrcKey
&r
) const {
84 // Can't use memcmp because of pad bytes. Frowny.
86 if (field < r.field) return -1; \
87 if (field > r.field) return 1
93 bool operator==(const SrcKey
& r
) const {
96 bool operator!=(const SrcKey
& r
) const {
99 bool operator<(const SrcKey
& r
) const {
102 bool operator>(const SrcKey
& r
) const {
105 // Hash function for both hash_map and tbb conventions.
106 static size_t hash(const SrcKey
&sk
) {
107 return HPHP::hash_int64_pair(sk
.m_funcId
, uint64(sk
.m_offset
));
109 size_t operator()(const SrcKey
& sk
) const {
112 static bool equal(const SrcKey
& sk1
, const SrcKey
& sk2
) {
116 // Packed representation of SrcKeys for use in contexts where we
117 // want atomicity. (SrcDB.)
118 typedef uint64_t AtomicInt
;
120 AtomicInt
toAtomicInt() const {
121 return uint64_t(m_funcId
) << 32 | uint64_t(m_offset
);
124 static SrcKey
fromAtomicInt(AtomicInt in
) {
126 k
.m_funcId
= in
>> 32;
127 k
.m_offset
= in
& 0xffffffff;
131 void trace(const char *fmt
, ...) const;
135 void advance(const Unit
* u
) {
136 m_offset
+= instrLen(u
->at(offset()));
140 typedef hphp_hash_set
<SrcKey
, SrcKey
> SrcKeySet
;
141 #define SKTRACE(level, sk, ...) \
142 ONTRACE(level, (sk).trace(__VA_ARGS__))
144 class NormalizedInstruction
;
146 // A DynLocation is a Location-in-execution: a location, along with
147 // whatever is known about its runtime type.
151 NormalizedInstruction
* source
;
153 DynLocation(Location l
, DataType t
) : location(l
), rtt(t
), source(NULL
) {}
155 DynLocation(Location l
, RuntimeType t
) : location(l
), rtt(t
), source(NULL
) {}
157 DynLocation() : location(), rtt(KindOfInvalid
), source(NULL
) {}
159 bool operator==(const DynLocation
& r
) const {
160 return rtt
== r
.rtt
&& location
== r
.location
;
164 size_t operator()(const DynLocation
&dl
) const {
165 uint64 rtthash
= rtt(rtt
);
166 uint64 locHash
= location(location
);
167 return rtthash
^ locHash
;
170 std::string
pretty() const {
171 return Trace::prettyNode("DynLocation", location
, rtt
);
174 // Punch through a bunch of frequently called rtt and location methods.
175 // While this is unlovely here, we use DynLocation in bazillions of
176 // places in the translator, and constantly saying ".rtt" is worse.
177 bool isString() const {
178 return rtt
.isString();
183 bool isDouble() const {
184 return rtt
.isDouble();
186 bool isBoolean() const {
187 return rtt
.isBoolean();
189 bool isVariant() const {
190 return rtt
.isVariant();
192 bool isValue() const {
193 return rtt
.isValue();
195 bool isNull() const {
198 bool isObject() const {
199 return rtt
.isObject();
201 bool isArray() const {
202 return rtt
.isArray();
204 DataType
valueType() const {
205 return rtt
.valueType();
207 DataType
outerType() const {
208 return rtt
.outerType();
211 bool isStack() const {
212 return location
.isStack();
214 bool isLocal() const {
215 return location
.isLocal();
217 bool isLiteral() const {
218 return location
.isLiteral();
221 // Uses the runtime state. True if this dynLocation can be overwritten by
222 // SetG's and SetM's.
223 bool canBeAliased() const;
226 // Flags that summarize the plan for handling a given instruction.
228 Interp
= 0, // default; must be boolean false
229 Supported
= 1, // Not interpreted, though possibly with C++
230 NonReentrant
= 2, // Supported with no possibility of reentry.
231 MachineCode
= 4, // Supported without C++ at all.
232 Simple
= NonReentrant
| Supported
,
233 Native
= MachineCode
| Simple
236 // A NormalizedInstruction has been decorated with its typed inputs and
238 class NormalizedInstruction
{
240 NormalizedInstruction
* next
;
241 NormalizedInstruction
* prev
;
244 const Func
* funcd
; // The Func in the topmost AR on the stack. Guaranteed to
245 // be accurate. Don't guess about this. Note that this is
246 // *not* the function whose body the NI belongs to.
247 // Note that for an FPush* may be set to the (statically
248 // known Func* that /this/ instruction is pushing)
249 const StringData
* funcName
;
250 // For FCall's, an opaque identifier that is either null, or uniquely
251 // identifies the (functionName, -arity) pair of this call site.
253 vector
<DynLocation
*> inputs
;
254 DynLocation
* outStack
;
255 DynLocation
* outLocal
;
256 DynLocation
* outStack2
; // Used for CGetL2
257 DynLocation
* outStack3
; // Used for CGetL3
258 vector
<Location
> deadLocs
; // locations that die at the end of this
261 ImmVector immVec
; // vector immediate; will have !isValid() if the
262 // instruction has no vector immediate
264 // The member codes for the M-vector.
265 std::vector
<MemberCode
> immVecM
;
268 * For property dims, if we know the Class* for the base when we'll
269 * be executing a given dim, it is stored here (at the index for the
270 * relevant member code minus 1, because the known class for the
271 * first member code is given by the base in inputs[]).
273 * Other entries here store null. See MetaInfo::MVecPropClass.
275 std::vector
<Class
*> immVecClasses
;
277 unsigned checkedInputs
;
278 // StackOff: logical delta at *start* of this instruction to
279 // stack at tracelet entry.
281 unsigned hasConstImm
:1;
283 unsigned breaksTracelet
:1;
284 unsigned changesPC
:1;
285 unsigned fuseBranch
:1;
286 unsigned preppedByRef
:1; // For FPass*; indicates parameter reffiness
287 unsigned manuallyAllocInputs
:1;
288 unsigned invertCond
:1;
289 unsigned outputPredicted
:1;
290 unsigned ignoreInnerType
:1;
292 * skipSync indicates that a previous instruction that should have
293 * adjusted the stack (eg FCall, Req*) didnt, because it could see
294 * that the next one was going to immediately adjust it again
295 * (ie at this point, rVmSp holds the "correct" value, rather
296 * than the value it had at the beginning of the tracelet)
300 * grouped indicates that the tracelet should not be broken
301 * (eg by a side exit) between the preceding instruction and
306 * guardedThis indicates that we know that ar->m_this is
309 * $this->foo = 1; # needs to check that $this is non-null
310 * $this->bar = 2; # can skip the check
311 * return 5; # can decRef ar->m_this unconditionally
313 unsigned guardedThis
:1;
315 * guardedCls indicates that we know the class exists
317 unsigned guardedCls
:1;
319 * dont check the surprise flag
321 unsigned noSurprise
:1;
323 noCtor is set on FPushCtorD to say that the ctor is
324 going to be skipped (so dont setup an actrec)
328 * instruction is statically known to have no effect, e.g. unboxing a Cell
332 * This is an FPush* that will be directly bound to a Func*
334 unsigned directCall
:1;
342 const Unit
* unit() const;
343 Offset
offset() const;
345 NormalizedInstruction() :
358 ignoreInnerType(false),
368 memset(imm
, 0, sizeof(imm
));
371 bool isJmpNZ() const {
372 ASSERT(op() == OpJmpNZ
|| op() == OpJmpZ
);
373 return (op() == OpJmpNZ
) != invertCond
;
376 bool isSupported() const {
377 return (m_txFlags
& Supported
) == Supported
;
380 bool isSimple() const {
381 return (m_txFlags
& Simple
) == Simple
;
384 bool isNative() const {
385 return (m_txFlags
& Native
) == Native
;
388 void markInputInferred(int i
) {
389 if (i
< 32) checkedInputs
|= 1u << i
;
392 bool inputWasInferred(int i
) const {
393 return i
< 32 && ((checkedInputs
>> i
) & 1);
402 OutputUse
outputIsUsed(DynLocation
* output
) const;
404 std::string
toString() const;
407 class TranslationFailedExc
: public std::exception
{
409 const char* m_file
; // must be static
411 TranslationFailedExc(const char* file
, int line
) :
412 m_file(file
), m_line(line
) { }
415 class UnknownInputExc
: public std::exception
{
417 const char* m_file
; // must be static
419 UnknownInputExc(const char* file
, int line
)
420 : m_file(file
), m_line(line
) { }
423 #define punt() do { \
424 throw TranslationFailedExc(__FILE__, __LINE__); \
427 #define throwUnknownInput() do { \
428 throw UnknownInputExc(__FILE__, __LINE__); \
432 * A tracelet is a unit of input to the back-end. It is a partially typed,
433 * non-maximal basic block, representing the next slice of the program to
435 * It is a consecutive set of instructions, only the last of which may be a
436 * transfer of control, annotated types and locations for each opcode's input
439 typedef hphp_hash_map
<Location
, DynLocation
*, Location
> ChangeMap
;
440 typedef ChangeMap DepMap
;
441 typedef hphp_hash_set
<Location
, Location
> LocationSet
;
444 InstrStream() : first(NULL
), last(NULL
) {}
445 void append(NormalizedInstruction
* ni
);
446 void remove(NormalizedInstruction
* ni
);
447 NormalizedInstruction
* first
;
448 NormalizedInstruction
* last
;
456 std::string
pretty() const {
457 std::ostringstream out
;
459 for (size_t i
= 0; i
< m_mask
.size(); ++i
) {
460 out
<< (m_mask
[i
] ? "1" : "0");
463 for (size_t i
= 0; i
< m_vals
.size(); ++i
) {
464 out
<< (m_vals
[i
] ? "1" : "0");
469 typedef hphp_hash_map
<int64
, Record
, int64_hash
> ArMap
;
474 void addDep(int entryArDelta
, unsigned argNum
, bool isRef
) {
475 if (m_arMap
.find(entryArDelta
) == m_arMap
.end()) {
476 m_arMap
[entryArDelta
] = Record();
478 Record
& r
= m_arMap
[entryArDelta
];
479 if (argNum
>= r
.m_mask
.size()) {
480 ASSERT(argNum
>= r
.m_vals
.size());
481 r
.m_mask
.resize(argNum
+ 1);
482 r
.m_vals
.resize(argNum
+ 1);
484 r
.m_mask
[argNum
] = true;
485 r
.m_vals
[argNum
] = isRef
;
488 size_t size() const {
489 return m_arMap
.size();
494 // State for tracking function param reffiness. m_topFunc is the function
495 // for the activation record that is closest to the top of the stack, or
496 // NULL if it is currently unknown. A tracelet can be in one of three
497 // epistemological states: GUESSABLE, KNOWN, and UNKNOWABLE. We start out in
498 // GUESSABLE, with m_topFunc == NULL (not yet guessed); when it's time to
499 // guess, we will use the ActRec seen on the top of stack at compilation
500 // time as a hint for refs going forward.
502 // The KNOWN state is a very strong guarantee. It means that no matter when
503 // this tracelet is executed, no matter what else has happened, the ActRec
504 // closest to the top of the stack WILL contain m_topFunc. This means: if that
505 // function is defined conditionally, or defined in some other module, you
506 // cannot correctly make that assertion. KNOWN indicates absolute certainty
507 // about all possible futures.
509 // This strange "not-guessed-yet-but-could" state is required by our
510 // VM design; at present, the ActRec is not easily recoverable from an
511 // arbitrary instruction boundary. However, it can be recovered from the
512 // instructions that need to do so.
513 static const int InvalidEntryArDelta
= INT_MAX
;
516 GUESSABLE
, KNOWN
, UNKNOWABLE
521 const Func
* m_topFunc
;
522 int m_entryArDelta
; // delta at BB entry to guessed ActRec.
525 std::vector
<Record
> m_arStack
;
528 void pushFuncD(const Func
* func
);
531 bool getReffiness(int argNum
, int stackOffset
, RefDeps
* outRefDeps
);
532 const Func
* getCurrentFunc();
533 State
getCurrentState();
536 struct Tracelet
: private boost::noncopyable
{
538 DepMap m_dependencies
;
539 DepMap m_resolvedDeps
; // dependencies resolved by static analysis
540 InstrStream m_instrStream
;
543 // SrcKey for the start of the Tracelet. This might be different
544 // from m_instrStream.first->source.
547 // After this Tracelet runs, this is the SrcKey for the next
548 // instruction that we should go to. Note that this can be
549 // different from m_instrStream.last->source.advance() if we removed
550 // the last instruction from the stream.
553 // numOpcodes is the number of raw opcode instructions, before optimization.
554 // The immediates optimization may both:
556 // 1. remove the first opcode, thus making
557 // sk.instr != instrs.first->source.instr
558 // 2. remove no longer needed instructions
561 // Assumptions about entering actRec's reffiness.
562 ActRecState m_arState
;
566 * If we were unable to make sense of the instruction stream (e.g., it
567 * used instructions that the translator does not understand), then this
568 * tracelet is useful only for defining the boundaries of a basic block.
569 * The low-level translator can handle this by backing off to the
570 * bytecode interpreter.
572 bool m_analysisFailed
;
574 // Track which NormalizedInstructions and DynLocations are owned by this
575 // Tracelet; used for cleanup purposes
576 boost::ptr_vector
<NormalizedInstruction
> m_instrs
;
577 boost::ptr_vector
<DynLocation
> m_dynlocs
;
582 m_analysisFailed(false) { }
584 NormalizedInstruction
* newNormalizedInstruction();
585 DynLocation
* newDynLocation(Location l
, DataType t
);
586 DynLocation
* newDynLocation(Location l
, RuntimeType t
);
587 DynLocation
* newDynLocation();
592 struct TraceletContext
{
594 ChangeMap m_currentMap
;
595 DepMap m_dependencies
;
596 DepMap m_resolvedDeps
; // dependencies resolved by static analysis
597 LocationSet m_changeSet
;
598 LocationSet m_deletedSet
;
603 : m_t(NULL
), m_aliasTaint(false), m_varEnvTaint(false) {}
604 TraceletContext(Tracelet
* t
)
605 : m_t(t
), m_aliasTaint(false), m_varEnvTaint(false) {}
606 DynLocation
* recordRead(const InputInfo
& l
, bool useHHIR
,
607 DataType staticType
= KindOfInvalid
);
608 void recordWrite(DynLocation
* dl
, NormalizedInstruction
* source
);
609 void recordDelete(const Location
& l
);
614 static bool canBeAliased(const DynLocation
* dl
);
623 const char* getTransKindName(TransKind kind
);
626 * Used to maintain a mapping from the bytecode to its corresponding x86.
628 struct TransBCMapping
{
635 * A record with various information about a translation.
643 vector
<DynLocation
> dependencies
;
650 vector
<TransBCMapping
> bcMapping
;
652 static const TransID InvalidID
= -1LL;
661 TCA _astubsStart
= 0,
662 uint32 _astubsLen
= 0) :
663 id(0), kind(_kind
), src(s
), md5(_md5
), bcStopOffset(0),
664 aStart(_aStart
), aLen(_aLen
),
665 astubsStart(_astubsStart
), astubsLen(_astubsLen
),
666 counterStart(0), counterLen(0) { }
673 TCA _astubsStart
= 0,
674 uint32 _astubsLen
= 0,
675 TCA _counterStart
= 0,
676 uint8 _counterLen
= 0,
677 vector
<TransBCMapping
> _bcMapping
= vector
<TransBCMapping
>()) :
678 id(0), kind(TransNormal
), src(s
), md5(_md5
),
679 bcStopOffset(t
.m_nextSk
.offset()), aStart(_aStart
), aLen(_aLen
),
680 astubsStart(_astubsStart
), astubsLen(_astubsLen
),
681 counterStart(_counterStart
), counterLen(_counterLen
),
682 bcMapping(_bcMapping
) {
683 for (DepMap::const_iterator dep
= t
.m_dependencies
.begin();
684 dep
!= t
.m_dependencies
.end();
686 dependencies
.push_back(*dep
->second
);
690 void setID(TransID newID
) { id
= newID
; }
691 string
print(uint64 profCount
) const;
695 * Translator annotates a tracelet with input/output locations/types.
699 // kFewLocals is a magic value used to decide whether or not to
700 // generate specialized code for RetC
701 static const int kFewLocals
= 4;
704 friend struct TraceletContext
;
706 int stackFrameOffset
; // sp at current instr; used to normalize
708 void analyzeSecondPass(Tracelet
& t
);
709 bool applyInputMetaData(Unit::MetaHandle
&,
710 NormalizedInstruction
* ni
,
711 TraceletContext
& tas
,
713 void getInputs(Tracelet
& t
,
714 NormalizedInstruction
* ni
,
715 int& currentStackOffset
,
717 void getOutputs(Tracelet
& t
,
718 NormalizedInstruction
* ni
,
719 int& currentStackOffset
,
722 static RuntimeType
liveType(Location l
, const Unit
&u
);
723 static RuntimeType
liveType(const Cell
* outer
, const Location
& l
);
725 void consumeStackEntry(Tracelet
* tlet
, NormalizedInstruction
* ni
);
726 void produceStackEntry(Tracelet
* tlet
, NormalizedInstruction
* ni
);
727 void produceDataRef(Tracelet
* tlet
, NormalizedInstruction
* ni
,
730 void findImmable(ImmStack
&stack
, NormalizedInstruction
* ni
);
732 virtual void syncWork() = 0;
733 virtual void invalidateSrcKey(const SrcKey
& sk
) = 0;
736 void requestResetHighLevelTranslator();
740 typedef std::map
<TCA
, TransID
> TransDB
;
742 vector
<TransRec
> m_translations
;
743 vector
<uint64
*> m_transCounters
;
745 // For HHIR-based translation
748 static Lease s_writeLease
;
749 static volatile bool s_replaceInFlight
;
754 virtual ~Translator();
755 static Translator
* Get();
756 static Lease
& WriteLease() {
759 static bool ReplaceInFlight() {
760 return s_replaceInFlight
;
762 static RuntimeType
outThisObjectType();
765 * Interface between the arch-dependent translator and outside world.
767 virtual void requestInit() = 0;
768 virtual void requestExit() = 0;
769 virtual void analyzeInstr(Tracelet
& t
, NormalizedInstruction
& i
) = 0;
770 virtual TCA
funcPrologue(Func
* f
, int nArgs
) = 0;
771 virtual TCA
getCallToExit() = 0;
772 virtual TCA
getRetFromInterpretedFrame() = 0;
773 virtual void defineCns(StringData
* name
) = 0;
774 virtual std::string
getUsage() = 0;
775 virtual bool dumpTC(bool ignoreLease
= false) = 0;
776 virtual bool dumpTCCode(const char *filename
) = 0;
777 virtual bool dumpTCData() = 0;
778 virtual void protectCode() = 0;
779 virtual void unprotectCode() = 0;
780 virtual bool isValidCodeAddress(TCA
) const = 0;
783 * Resume is the main entry point for the translator from the
784 * bytecode interpreter (see enterVMWork). It operates on behalf of
785 * a given nested invocation of the intepreter (calling back into it
786 * as necessary for blocks that need to be interpreted).
788 virtual void resume(SrcKey sk
) = 0;
790 enum FuncPrologueFlags
{
791 FuncPrologueNormal
= 0,
792 FuncPrologueMagicCall
= 1,
793 FuncPrologueIntercepted
= 2,
796 const TransDB
& getTransDB() const {
800 const TransRec
* getTransRec(TCA tca
) const {
801 if (!isTransDBEnabled()) return NULL
;
803 TransDB::const_iterator it
= m_transDB
.find(tca
);
804 if (it
== m_transDB
.end()) {
807 if (it
->second
>= m_translations
.size()) {
810 return &m_translations
[it
->second
];
813 const TransRec
* getTransRec(TransID transId
) const {
814 if (!isTransDBEnabled()) return NULL
;
816 assert(transId
< m_translations
.size());
817 return &m_translations
[transId
];
820 TransID
getNumTrans() const {
821 return m_translations
.size();
824 TransID
getCurrentTransID() const {
825 return m_translations
.size();
828 uint64
* getTransCounterAddr();
830 uint64
getTransCounter(TransID transId
) const;
832 void setTransCounter(TransID transId
, uint64 value
);
834 uint32
addTranslation(const TransRec
& transRec
) {
835 if (!isTransDBEnabled()) return -1u;
836 uint32 id
= getCurrentTransID();
837 m_translations
.push_back(transRec
);
838 m_translations
[id
].setID(id
);
840 if (transRec
.aLen
> 0) {
841 m_transDB
[transRec
.aStart
] = id
;
843 if (transRec
.astubsLen
> 0) {
844 m_transDB
[transRec
.astubsStart
] = id
;
850 void postAnalyze(NormalizedInstruction
* ni
, SrcKey
& sk
,
851 int& currentStackOffset
, Tracelet
& t
,
852 TraceletContext
& tas
);
853 void analyze(const SrcKey
* sk
, Tracelet
& out
);
854 void advance(Opcode
const **instrs
);
855 static int locPhysicalOffset(Location l
, const Func
* f
= NULL
);
856 static Location
tvToLocation(const TypedValue
* tv
, const TypedValue
* frame
);
857 static bool typeIsString(DataType type
) {
858 return type
== KindOfString
|| type
== KindOfStaticString
;
860 static bool liveFrameIsPseudoMain();
863 if (tl_regState
== REGSTATE_CLEAN
) return;
867 inline bool stateIsDirty() {
868 return tl_regState
== REGSTATE_DIRTY
;
871 inline bool isTransDBEnabled() const {
872 return debug
|| RuntimeOption::EvalDumpTC
;
876 * If this returns true, we dont generate guards for any of the
877 * inputs to this instruction (this is essentially to avoid
878 * generating guards on behalf of interpreted instructions).
880 virtual bool dontGuardAnyInputs(Opcode op
) { return false; }
884 SrcKeySet m_dbgBLSrcKey
;
885 Mutex m_dbgBlacklistLock
;
886 bool isSrcKeyInBL(const Unit
* unit
, const SrcKey
& sk
);
890 bool addDbgBLPC(PC pc
);
891 virtual bool addDbgGuards(const Unit
* unit
) = 0;
892 virtual bool addDbgGuard(const Func
* func
, Offset offset
) = 0;
894 TCA
getResumeHelper() {
895 return m_resumeHelper
;
899 int getStackDelta(const NormalizedInstruction
& ni
);
901 enum ControlFlowInfo
{
903 ControlFlowChangesPC
,
907 static inline ControlFlowInfo
908 opcodeControlFlowInfo(const Opcode instr
) {
920 case OpIterInit
: // May branch to fail case.
921 case OpIterInitM
: // May branch to fail case.
927 return ControlFlowBreaksBB
;
937 return ControlFlowChangesPC
;
939 return ControlFlowNone
;
946 * Returns true if the instruction can potentially set PC to point
947 * to something other than the next instruction in the bytecode
950 opcodeChangesPC(const Opcode instr
) {
951 return opcodeControlFlowInfo(instr
) >= ControlFlowChangesPC
;
957 * Returns true if the instruction always breaks a tracelet. Most
958 * instructions that change PC will break the tracelet, though some
959 * do not (ex. FCall).
962 opcodeBreaksBB(const Opcode instr
) {
963 return opcodeControlFlowInfo(instr
) == ControlFlowBreaksBB
;
966 bool outputDependsOnInput(const Opcode instr
);
968 extern bool tc_dump();
969 const Func
* lookupImmutableMethod(const Class
* cls
, const StringData
* name
,
970 bool& magicCall
, bool staticLookup
);
972 bool freeLocalsInline();
974 } } } // HPHP::VM::Transl