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 +----------------------------------------------------------------------+
16 #ifndef incl_HPHP_TRANSLATOR_H_
17 #define incl_HPHP_TRANSLATOR_H_
28 #include <boost/dynamic_bitset.hpp>
29 #include <boost/ptr_container/ptr_vector.hpp>
31 #include "hphp/util/hash.h"
32 #include "hphp/util/timer.h"
33 #include "hphp/runtime/base/execution_context.h"
34 #include "hphp/runtime/vm/bytecode.h"
35 #include "hphp/runtime/vm/translator/immstack.h"
36 #include "hphp/runtime/vm/translator/runtime-type.h"
37 #include "hphp/runtime/vm/translator/fixup.h"
38 #include "hphp/runtime/vm/translator/writelease.h"
39 #include "hphp/runtime/vm/translator/trans-data.h"
40 #include "hphp/runtime/vm/debugger_hook.h"
41 #include "hphp/runtime/base/md5.h"
43 /* Translator front-end. */
47 static const bool trustSigSegv
= false;
49 static const uint32_t transCountersPerChunk
= 1024 * 1024 / 8;
52 extern TranslatorX64
* volatile nextTx64
;
53 extern __thread TranslatorX64
* tx64
;
56 * REGSTATE_DIRTY when the live register state is spread across the
57 * stack and m_fixup, REGSTATE_CLEAN when it has been sync'ed into
64 extern __thread VMRegState tl_regState
;
67 * A SrcKey is a logical source instruction, currently a unit/instruction pair.
68 * The units are identified by contents rather than Unit; Unit's are
69 * ephemeral, and we want to reuse SrcKey's when we encounter Unit's with
74 Func::FuncId m_funcId
;
79 SrcKey() : m_funcId(Func::InvalidId
), m_offset(0) { }
81 SrcKey(const Func
* f
, Offset off
) :
82 m_funcId(f
->getFuncId()), m_offset(off
) { }
84 SrcKey(const Func
* f
, const Opcode
* i
) :
85 m_funcId(f
->getFuncId()), m_offset(f
->unit()->offsetOf(i
)) { }
87 int cmp(const SrcKey
&r
) const {
88 // Can't use memcmp because of pad bytes. Frowny.
90 if (field < r.field) return -1; \
91 if (field > r.field) return 1
97 bool operator==(const SrcKey
& r
) const {
100 bool operator!=(const SrcKey
& r
) const {
103 bool operator<(const SrcKey
& r
) const {
106 bool operator>(const SrcKey
& r
) const {
109 // Hash function for both hash_map and tbb conventions.
110 static size_t hash(const SrcKey
&sk
) {
111 return HPHP::hash_int64_pair(sk
.getFuncId(), uint64_t(sk
.m_offset
));
113 size_t operator()(const SrcKey
& sk
) const {
116 static bool equal(const SrcKey
& sk1
, const SrcKey
& sk2
) {
120 // Packed representation of SrcKeys for use in contexts where we
121 // want atomicity. (SrcDB.)
122 typedef uint64_t AtomicInt
;
124 AtomicInt
toAtomicInt() const {
125 return uint64_t(getFuncId()) << 32 | uint64_t(m_offset
);
128 static SrcKey
fromAtomicInt(AtomicInt in
) {
130 k
.setFuncId(in
>> 32);
131 k
.m_offset
= in
& 0xffffffff;
135 void setFuncId(Func::FuncId id
) {
136 assert(id
!= Func::InvalidId
);
139 Func::FuncId
getFuncId() const {
140 assert(m_funcId
!= Func::InvalidId
);
144 void trace(const char *fmt
, ...) const;
145 void print(int ninstr
) const;
146 std::string
pretty() const;
150 void advance(const Unit
* u
) {
151 m_offset
+= instrLen(u
->at(offset()));
155 typedef hphp_hash_set
<SrcKey
, SrcKey
> SrcKeySet
;
156 #define SKTRACE(level, sk, ...) \
157 ONTRACE(level, (sk).trace(__VA_ARGS__))
159 struct NormalizedInstruction
;
161 // A DynLocation is a Location-in-execution: a location, along with
162 // whatever is known about its runtime type.
166 NormalizedInstruction
* source
;
168 DynLocation(Location l
, DataType t
) : location(l
), rtt(t
), source(nullptr) {}
170 DynLocation(Location l
, RuntimeType t
) : location(l
), rtt(t
), source(nullptr) {}
172 DynLocation() : location(), rtt(KindOfInvalid
), source(nullptr) {}
174 bool operator==(const DynLocation
& r
) const {
175 return rtt
== r
.rtt
&& location
== r
.location
;
179 size_t operator()(const DynLocation
&dl
) const {
180 uint64_t rtthash
= rtt(rtt
);
181 uint64_t locHash
= location(location
);
182 return rtthash
^ locHash
;
185 std::string
pretty() const {
186 return Trace::prettyNode("DynLocation", location
, rtt
);
189 // Punch through a bunch of frequently called rtt and location methods.
190 // While this is unlovely here, we use DynLocation in bazillions of
191 // places in the translator, and constantly saying ".rtt" is worse.
192 bool isString() const {
193 return rtt
.isString();
198 bool isDouble() const {
199 return rtt
.isDouble();
201 bool isBoolean() const {
202 return rtt
.isBoolean();
207 bool isValue() const {
208 return rtt
.isValue();
210 bool isNull() const {
213 bool isObject() const {
214 return rtt
.isObject();
216 bool isArray() const {
217 return rtt
.isArray();
219 DataType
valueType() const {
220 return rtt
.valueType();
222 DataType
innerType() const {
223 return rtt
.innerType();
225 DataType
outerType() const {
226 return rtt
.outerType();
229 bool isStack() const {
230 return location
.isStack();
232 bool isLocal() const {
233 return location
.isLocal();
235 bool isLiteral() const {
236 return location
.isLiteral();
239 // Uses the runtime state. True if this dynLocation can be overwritten by
240 // SetG's and SetM's.
241 bool canBeAliased() const;
244 // Flags that summarize the plan for handling a given instruction.
246 Interp
= 0, // default; must be boolean false
247 Supported
= 1, // Not interpreted, though possibly with C++
248 NonReentrant
= 2, // Supported with no possibility of reentry.
249 MachineCode
= 4, // Supported without C++ at all.
250 Simple
= NonReentrant
| Supported
,
251 Native
= MachineCode
| Simple
255 struct TraceletContext
;
257 // A NormalizedInstruction has been decorated with its typed inputs and
259 class NormalizedInstruction
{
261 NormalizedInstruction
* next
;
262 NormalizedInstruction
* prev
;
265 const Func
* funcd
; // The Func in the topmost AR on the stack. Guaranteed to
266 // be accurate. Don't guess about this. Note that this is
267 // *not* the function whose body the NI belongs to.
268 // Note that for an FPush* may be set to the (statically
269 // known Func* that /this/ instruction is pushing)
270 const StringData
* funcName
;
271 // For FCall's, an opaque identifier that is either null, or uniquely
272 // identifies the (functionName, -arity) pair of this call site.
274 vector
<DynLocation
*> inputs
;
275 DynLocation
* outStack
;
276 DynLocation
* outLocal
;
277 DynLocation
* outLocal2
; // Used for IterInitK, MIterInitK, IterNextK, and
279 DynLocation
* outStack2
; // Used for CGetL2
280 DynLocation
* outStack3
; // Used for CGetL3
281 vector
<Location
> deadLocs
; // locations that die at the end of this
284 ImmVector immVec
; // vector immediate; will have !isValid() if the
285 // instruction has no vector immediate
287 // The member codes for the M-vector.
288 std::vector
<MemberCode
> immVecM
;
291 * For property dims, if we know the Class* for the base when we'll
292 * be executing a given dim, it is stored here (at the index for the
293 * relevant member code minus 1, because the known class for the
294 * first member code is given by the base in inputs[]).
296 * Other entries here store null. See MetaInfo::MVecPropClass.
298 std::vector
<Class
*> immVecClasses
;
301 * On certain FCalls, we can inspect the callee and generate a
302 * tracelet with information about what happens over there.
304 * The HHIR translator uses this to possibly inline callees.
306 std::unique_ptr
<Tracelet
> calleeTrace
;
308 unsigned checkedInputs
;
309 // StackOff: logical delta at *start* of this instruction to
310 // stack at tracelet entry.
315 bool breaksTracelet
:1;
318 bool preppedByRef
:1; // For FPass*; indicates parameter reffiness
319 bool manuallyAllocInputs
:1;
321 bool outputPredicted
:1;
322 bool outputPredictionStatic
:1;
323 bool ignoreInnerType
:1;
326 * skipSync indicates that a previous instruction that should have
327 * adjusted the stack (eg FCall, Req*) didnt, because it could see
328 * that the next one was going to immediately adjust it again
329 * (ie at this point, rVmSp holds the "correct" value, rather
330 * than the value it had at the beginning of the tracelet)
335 * grouped indicates that the tracelet should not be broken
336 * (eg by a side exit) between the preceding instruction and
342 * guardedThis indicates that we know that ar->m_this is
345 * $this->foo = 1; # needs to check that $this is non-null
346 * $this->bar = 2; # can skip the check
347 * return 5; # can decRef ar->m_this unconditionally
352 * guardedCls indicates that we know the class exists
357 * dont check the surprise flag
362 noCtor is set on FPushCtorD to say that the ctor is
363 going to be skipped (so dont setup an actrec)
368 * instruction is statically known to have no effect, e.g. unboxing a Cell
373 * Used with HHIR. Instruction shoud be interpreted, because previous attempt
374 * to translate it has failed.
379 * This is an FPush* that will be directly bound to a Func*
384 * Indicates that a RetC/RetV should generate inlined return code
385 * rather than calling the shared stub.
389 // For returns, this tracks local ids that are statically known not
390 // to be reference counted at this point (i.e. won't require guards
392 boost::dynamic_bitset
<> nonRefCountedLocals
;
400 const Unit
* unit() const;
401 Offset
offset() const;
403 NormalizedInstruction()
414 , ignoreInnerType(false)
424 , inlineReturn(false)
427 memset(imm
, 0, sizeof(imm
));
430 bool isJmpNZ() const {
431 assert(op() == OpJmpNZ
|| op() == OpJmpZ
);
432 return (op() == OpJmpNZ
) != invertCond
;
435 bool isSupported() const {
436 return (m_txFlags
& Supported
) == Supported
;
439 bool isSimple() const {
440 return (m_txFlags
& Simple
) == Simple
;
443 bool isNative() const {
444 return (m_txFlags
& Native
) == Native
;
447 void markInputInferred(int i
) {
448 if (i
< 32) checkedInputs
|= 1u << i
;
451 bool inputWasInferred(int i
) const {
452 return i
< 32 && ((checkedInputs
>> i
) & 1);
455 bool wasGroupedWith(Op op
) const {
456 return grouped
&& prev
->op() == op
;
459 template<class... OpTypes
>
460 bool wasGroupedWith(Op op
, OpTypes
... ops
) const {
461 return wasGroupedWith(op
) || wasGroupedWith(ops
...);
470 OutputUse
getOutputUsage(DynLocation
* output
, bool ignorePops
= false) const;
472 std::string
toString() const;
475 // Return a summary string of the bytecode in a tracelet.
476 std::string
traceletShape(const Tracelet
&);
478 class TranslationFailedExc
: public std::exception
{
480 const char* m_file
; // must be static
482 TranslationFailedExc(const char* file
, int line
) :
483 m_file(file
), m_line(line
) { }
486 class UnknownInputExc
: public std::exception
{
488 const char* m_file
; // must be static
490 UnknownInputExc(const char* file
, int line
)
491 : m_file(file
), m_line(line
) { }
494 #define punt() do { \
495 throw TranslationFailedExc(__FILE__, __LINE__); \
498 #define throwUnknownInput() do { \
499 throw UnknownInputExc(__FILE__, __LINE__); \
504 explicit GuardType(DataType outer
= KindOfInvalid
,
505 DataType inner
= KindOfInvalid
);
506 explicit GuardType(const RuntimeType
& rtt
);
507 GuardType(const GuardType
& other
);
508 const DataType
getOuterType() const;
509 const DataType
getInnerType() const;
510 bool isSpecific() const;
511 bool isRelaxed() const;
512 bool isGeneric() const;
513 bool isCounted() const;
514 bool isMoreRefinedThan(const GuardType
& other
) const;
515 bool mayBeUninit() const;
516 GuardType
getCountness() const;
517 GuardType
getCountnessInit() const;
518 DataTypeCategory
getCategory() const;
526 * A tracelet is a unit of input to the back-end. It is a partially typed,
527 * non-maximal basic block, representing the next slice of the program to
529 * It is a consecutive set of instructions, only the last of which may be a
530 * transfer of control, annotated types and locations for each opcode's input
533 typedef hphp_hash_map
<Location
, DynLocation
*, Location
> ChangeMap
;
534 typedef hphp_hash_map
<Location
,RuntimeType
,Location
> TypeMap
;
535 typedef ChangeMap DepMap
;
536 typedef hphp_hash_set
<Location
, Location
> LocationSet
;
537 typedef hphp_hash_map
<DynLocation
*, GuardType
> DynLocTypeMap
;
540 InstrStream() : first(nullptr), last(nullptr) {}
541 void append(NormalizedInstruction
* ni
);
542 void remove(NormalizedInstruction
* ni
);
543 NormalizedInstruction
* first
;
544 NormalizedInstruction
* last
;
552 std::string
pretty() const {
553 std::ostringstream out
;
555 for (size_t i
= 0; i
< m_mask
.size(); ++i
) {
556 out
<< (m_mask
[i
] ? "1" : "0");
559 for (size_t i
= 0; i
< m_vals
.size(); ++i
) {
560 out
<< (m_vals
[i
] ? "1" : "0");
565 typedef hphp_hash_map
<int64_t, Record
, int64_hash
> ArMap
;
570 void addDep(int entryArDelta
, unsigned argNum
, bool isRef
) {
571 if (m_arMap
.find(entryArDelta
) == m_arMap
.end()) {
572 m_arMap
[entryArDelta
] = Record();
574 Record
& r
= m_arMap
[entryArDelta
];
575 if (argNum
>= r
.m_mask
.size()) {
576 assert(argNum
>= r
.m_vals
.size());
577 r
.m_mask
.resize(argNum
+ 1);
578 r
.m_vals
.resize(argNum
+ 1);
580 r
.m_mask
[argNum
] = true;
581 r
.m_vals
[argNum
] = isRef
;
584 size_t size() const {
585 return m_arMap
.size();
590 // State for tracking function param reffiness. m_topFunc is the function
591 // for the activation record that is closest to the top of the stack, or
592 // NULL if it is currently unknown. A tracelet can be in one of three
593 // epistemological states: GUESSABLE, KNOWN, and UNKNOWABLE. We start out in
594 // GUESSABLE, with m_topFunc == NULL (not yet guessed); when it's time to
595 // guess, we will use the ActRec seen on the top of stack at compilation
596 // time as a hint for refs going forward.
598 // The KNOWN state is a very strong guarantee. It means that no matter when
599 // this tracelet is executed, no matter what else has happened, the ActRec
600 // closest to the top of the stack WILL contain m_topFunc. This means: if that
601 // function is defined conditionally, or defined in some other module, you
602 // cannot correctly make that assertion. KNOWN indicates absolute certainty
603 // about all possible futures.
605 // This strange "not-guessed-yet-but-could" state is required by our
606 // VM design; at present, the ActRec is not easily recoverable from an
607 // arbitrary instruction boundary. However, it can be recovered from the
608 // instructions that need to do so.
609 static const int InvalidEntryArDelta
= INT_MAX
;
612 GUESSABLE
, KNOWN
, UNKNOWABLE
617 const Func
* m_topFunc
;
618 int m_entryArDelta
; // delta at BB entry to guessed ActRec.
621 std::vector
<Record
> m_arStack
;
624 void pushFuncD(const Func
* func
);
627 bool getReffiness(int argNum
, int stackOffset
, RefDeps
* outRefDeps
);
628 const Func
* getCurrentFunc();
629 State
getCurrentState();
632 struct Tracelet
: private boost::noncopyable
{
634 DepMap m_dependencies
;
635 DepMap m_resolvedDeps
; // dependencies resolved by static analysis
636 InstrStream m_instrStream
;
639 // SrcKey for the start of the Tracelet. This might be different
640 // from m_instrStream.first->source.
643 // After this Tracelet runs, this is the SrcKey for the next
644 // instruction that we should go to. Note that this can be
645 // different from m_instrStream.last->source.advance() if we removed
646 // the last instruction from the stream.
649 // numOpcodes is the number of raw opcode instructions, before optimization.
650 // The immediates optimization may both:
652 // 1. remove the first opcode, thus making
653 // sk.instr != instrs.first->source.instr
654 // 2. remove no longer needed instructions
657 // Assumptions about entering actRec's reffiness.
658 ActRecState m_arState
;
661 // Live range suport.
663 // Maintain a per-location last-read and last-written map. We don't need
664 // to remember the start of the live range, since we implicitly discover it
665 // at translation time. The entries in these maps are the sequence number
666 // of the instruction after which the location is no longer read/written.
667 typedef hphp_hash_map
<Location
, int, Location
> RangeMap
;
669 RangeMap m_liveDirtyEnd
;
672 * If we were unable to make sense of the instruction stream (e.g., it
673 * used instructions that the translator does not understand), then this
674 * tracelet is useful only for defining the boundaries of a basic block.
675 * The low-level translator can handle this by backing off to the
676 * bytecode interpreter.
678 bool m_analysisFailed
;
680 // Track which NormalizedInstructions and DynLocations are owned by this
681 // Tracelet; used for cleanup purposes
682 boost::ptr_vector
<NormalizedInstruction
> m_instrs
;
683 boost::ptr_vector
<DynLocation
> m_dynlocs
;
688 m_analysisFailed(false) { }
690 void constructLiveRanges();
691 bool isLiveAfterInstr(Location l
, const NormalizedInstruction
& i
) const;
692 bool isWrittenAfterInstr(Location l
, const NormalizedInstruction
& i
) const;
694 NormalizedInstruction
* newNormalizedInstruction();
695 DynLocation
* newDynLocation(Location l
, DataType t
);
696 DynLocation
* newDynLocation(Location l
, RuntimeType t
);
697 DynLocation
* newDynLocation();
699 /* These aren't merged into a single method with a default argument
700 * to make gdb happy. */
702 void print(std::ostream
& out
) const;
712 const char* getTransKindName(TransKind kind
);
715 * Used to maintain a mapping from the bytecode to its corresponding x86.
717 struct TransBCMapping
{
724 * A record with various information about a translation.
731 uint32_t bcStopOffset
;
732 vector
<DynLocation
> dependencies
;
739 vector
<TransBCMapping
> bcMapping
;
741 static const TransID InvalidID
= -1LL;
750 TCA _astubsStart
= 0,
751 uint32_t _astubsLen
= 0) :
752 id(0), kind(_kind
), src(s
), md5(_md5
), bcStopOffset(0),
753 aStart(_aStart
), aLen(_aLen
),
754 astubsStart(_astubsStart
), astubsLen(_astubsLen
),
755 counterStart(0), counterLen(0) { }
763 TCA _astubsStart
= 0,
764 uint32_t _astubsLen
= 0,
765 TCA _counterStart
= 0,
766 uint8_t _counterLen
= 0,
767 vector
<TransBCMapping
> _bcMapping
= vector
<TransBCMapping
>()) :
768 id(0), kind(_kind
), src(s
), md5(_md5
),
769 bcStopOffset(t
.m_nextSk
.offset()), aStart(_aStart
), aLen(_aLen
),
770 astubsStart(_astubsStart
), astubsLen(_astubsLen
),
771 counterStart(_counterStart
), counterLen(_counterLen
),
772 bcMapping(_bcMapping
) {
773 for (DepMap::const_iterator dep
= t
.m_dependencies
.begin();
774 dep
!= t
.m_dependencies
.end();
776 dependencies
.push_back(*dep
->second
);
780 void setID(TransID newID
) { id
= newID
; }
781 string
print(uint64_t profCount
) const;
785 TranslArgs(const SrcKey
& sk
, bool align
)
792 TranslArgs
& sk(const SrcKey
& sk
) {
796 TranslArgs
& src(TCA src
) {
800 TranslArgs
& align(bool align
) {
804 TranslArgs
& interp(bool interp
) {
816 * Translator annotates a tracelet with input/output locations/types.
819 static const int MaxJmpsTracedThrough
= 5;
822 // kMaxInlineReturnDecRefs is the maximum ref-counted locals to
823 // generate an inline return for.
824 static const int kMaxInlineReturnDecRefs
= 1;
827 friend struct TraceletContext
;
829 void analyzeSecondPass(Tracelet
& t
);
830 void analyzeCallee(TraceletContext
&,
832 NormalizedInstruction
* fcall
);
833 void preInputApplyMetaData(Unit::MetaHandle
, NormalizedInstruction
*);
834 bool applyInputMetaData(Unit::MetaHandle
&,
835 NormalizedInstruction
* ni
,
836 TraceletContext
& tas
,
838 void getInputs(Tracelet
& t
,
839 NormalizedInstruction
* ni
,
840 int& currentStackOffset
,
842 const TraceletContext
& tas
);
843 void getOutputs(Tracelet
& t
,
844 NormalizedInstruction
* ni
,
845 int& currentStackOffset
,
847 void relaxDeps(Tracelet
& tclet
, TraceletContext
& tctxt
);
848 void reanalizeConsumers(Tracelet
& tclet
, DynLocation
* depDynLoc
);
849 DataTypeCategory
getOperandConstraintCategory(NormalizedInstruction
* instr
,
851 GuardType
getOperandConstraintType(NormalizedInstruction
* instr
,
853 const GuardType
& specType
);
855 void constrainOperandType(GuardType
& relxType
,
856 NormalizedInstruction
* instr
,
858 const GuardType
& specType
);
861 RuntimeType
liveType(Location l
, const Unit
&u
);
862 RuntimeType
liveType(const Cell
* outer
, const Location
& l
);
864 void consumeStackEntry(Tracelet
* tlet
, NormalizedInstruction
* ni
);
865 void produceStackEntry(Tracelet
* tlet
, NormalizedInstruction
* ni
);
866 void produceDataRef(Tracelet
* tlet
, NormalizedInstruction
* ni
,
869 void findImmable(ImmStack
&stack
, NormalizedInstruction
* ni
);
871 virtual void syncWork() = 0;
872 virtual void invalidateSrcKey(SrcKey sk
) = 0;
875 void requestResetHighLevelTranslator();
878 TCA m_resumeHelperRet
;
880 typedef std::map
<TCA
, TransID
> TransDB
;
882 vector
<TransRec
> m_translations
;
883 vector
<uint64_t*> m_transCounters
;
885 int64_t m_createdTime
;
887 static Lease s_writeLease
;
888 static volatile bool s_replaceInFlight
;
893 virtual ~Translator();
894 static Translator
* Get();
895 static Lease
& WriteLease() {
898 static bool ReplaceInFlight() {
899 return s_replaceInFlight
;
901 static RuntimeType
outThisObjectType();
904 * Interface between the arch-dependent translator and outside world.
906 virtual void requestInit() = 0;
907 virtual void requestExit() = 0;
908 virtual void analyzeInstr(Tracelet
& t
, NormalizedInstruction
& i
) = 0;
909 virtual TCA
funcPrologue(Func
* f
, int nArgs
, ActRec
* ar
= nullptr) = 0;
910 virtual TCA
getCallToExit() = 0;
911 virtual TCA
getRetFromInterpretedFrame() = 0;
912 virtual std::string
getUsage() = 0;
913 virtual size_t getCodeSize() = 0;
914 virtual size_t getStubSize() = 0;
915 virtual size_t getTargetCacheSize() = 0;
916 virtual bool dumpTC(bool ignoreLease
= false) = 0;
917 virtual bool dumpTCCode(const char *filename
) = 0;
918 virtual bool dumpTCData() = 0;
919 virtual void protectCode() = 0;
920 virtual void unprotectCode() = 0;
921 virtual bool isValidCodeAddress(TCA
) const = 0;
923 const TransDB
& getTransDB() const {
927 const TransRec
* getTransRec(TCA tca
) const {
928 if (!isTransDBEnabled()) return nullptr;
930 TransDB::const_iterator it
= m_transDB
.find(tca
);
931 if (it
== m_transDB
.end()) {
934 if (it
->second
>= m_translations
.size()) {
937 return &m_translations
[it
->second
];
940 const TransRec
* getTransRec(TransID transId
) const {
941 if (!isTransDBEnabled()) return nullptr;
943 always_assert(transId
< m_translations
.size());
944 return &m_translations
[transId
];
947 TransID
getNumTrans() const {
948 return m_translations
.size();
951 TransID
getCurrentTransID() const {
952 return m_translations
.size();
955 uint64_t* getTransCounterAddr();
957 uint64_t getTransCounter(TransID transId
) const;
959 void setTransCounter(TransID transId
, uint64_t value
);
961 uint32_t addTranslation(const TransRec
& transRec
) {
962 if (Trace::moduleEnabledRelease(Trace::trans
, 1)) {
963 // Log the translation's size, creation time, SrcKey, and size
964 Trace::traceRelease("New translation: %lld %s %u %u %d\n",
965 Timer::GetCurrentTimeMicros() - m_createdTime
,
966 transRec
.src
.pretty().c_str(), transRec
.aLen
,
967 transRec
.astubsLen
, transRec
.kind
);
970 if (!isTransDBEnabled()) return -1u;
971 uint32_t id
= getCurrentTransID();
972 m_translations
.push_back(transRec
);
973 m_translations
[id
].setID(id
);
975 if (transRec
.aLen
> 0) {
976 m_transDB
[transRec
.aStart
] = id
;
978 if (transRec
.astubsLen
> 0) {
979 m_transDB
[transRec
.astubsStart
] = id
;
986 * Create a Tracelet for the given SrcKey, which must actually be
987 * the current VM frame.
989 * XXX The analysis pass will inspect the live state of the VM stack
990 * as needed to determine the current types of in-flight values.
992 std::unique_ptr
<Tracelet
> analyze(SrcKey sk
, const TypeMap
& = TypeMap());
994 void postAnalyze(NormalizedInstruction
* ni
, SrcKey
& sk
,
995 Tracelet
& t
, TraceletContext
& tas
);
996 void advance(Opcode
const **instrs
);
997 static int locPhysicalOffset(Location l
, const Func
* f
= nullptr);
998 static Location
tvToLocation(const TypedValue
* tv
, const TypedValue
* frame
);
999 static bool typeIsString(DataType type
) {
1000 return type
== KindOfString
|| type
== KindOfStaticString
;
1002 static bool liveFrameIsPseudoMain();
1004 inline void sync() {
1005 if (tl_regState
== REGSTATE_CLEAN
) return;
1009 inline bool stateIsDirty() {
1010 return tl_regState
== REGSTATE_DIRTY
;
1013 inline bool isTransDBEnabled() const {
1014 return debug
|| RuntimeOption::EvalDumpTC
;
1018 * If this returns true, we dont generate guards for any of the
1019 * inputs to this instruction (this is essentially to avoid
1020 * generating guards on behalf of interpreted instructions).
1022 virtual bool dontGuardAnyInputs(Opcode op
) { return false; }
1026 SrcKeySet m_dbgBLSrcKey
;
1027 Mutex m_dbgBlacklistLock
;
1028 bool isSrcKeyInBL(const Unit
* unit
, const SrcKey
& sk
);
1031 int m_analysisDepth
;
1035 bool addDbgBLPC(PC pc
);
1036 virtual bool addDbgGuards(const Unit
* unit
) = 0;
1037 virtual bool addDbgGuard(const Func
* func
, Offset offset
) = 0;
1039 TCA
getResumeHelper() {
1040 return m_resumeHelper
;
1042 TCA
getResumeHelperRet() {
1043 return m_resumeHelperRet
;
1046 int analysisDepth() const {
1047 assert(m_analysisDepth
>= 0);
1048 return m_analysisDepth
;
1052 int getStackDelta(const NormalizedInstruction
& ni
);
1054 enum ControlFlowInfo
{
1056 ControlFlowChangesPC
,
1060 static inline ControlFlowInfo
1061 opcodeControlFlowInfo(const Opcode instr
) {
1078 case OpIterInit
: // May branch to fail case.
1079 case OpIterInitK
: // Ditto
1080 case OpMIterInit
: // Ditto
1081 case OpMIterInitK
: // Ditto
1087 return ControlFlowBreaksBB
;
1096 return ControlFlowChangesPC
;
1098 return ControlFlowNone
;
1103 * opcodeChangesPC --
1105 * Returns true if the instruction can potentially set PC to point
1106 * to something other than the next instruction in the bytecode
1109 opcodeChangesPC(const Opcode instr
) {
1110 return opcodeControlFlowInfo(instr
) >= ControlFlowChangesPC
;
1116 * Returns true if the instruction always breaks a tracelet. Most
1117 * instructions that change PC will break the tracelet, though some
1118 * do not (ex. FCall).
1121 opcodeBreaksBB(const Opcode instr
) {
1122 return opcodeControlFlowInfo(instr
) == ControlFlowBreaksBB
;
1125 bool outputDependsOnInput(const Opcode instr
);
1127 extern bool tc_dump();
1128 const Func
* lookupImmutableMethod(const Class
* cls
, const StringData
* name
,
1129 bool& magicCall
, bool staticLookup
);
1131 // This is used to check that return types of builtins are not simple
1132 // types. This is different from IS_REFCOUNTED_TYPE because builtins
1133 // can return Variants, and we use KindOfUnknown to denote these
1135 static inline bool isCppByRef(DataType t
) {
1136 return t
!= KindOfBoolean
&& t
!= KindOfInt64
&& t
!= KindOfNull
;
1139 // return true if type is passed in/out of C++ as String&/Array&/Object&
1140 static inline bool isSmartPtrRef(DataType t
) {
1141 return t
== KindOfString
|| t
== KindOfStaticString
||
1142 t
== KindOfArray
|| t
== KindOfObject
;