Supported enregistered string and int keys in the vector translator
[hiphop-php.git] / src / runtime / vm / translator / translator.h
blobc8b7bc7d7661092d5542d80f8a1c342a3694b03c
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <limits.h>
21 #include <string.h>
22 #include <stdio.h>
23 #include <assert.h>
25 #include <map>
26 #include <vector>
27 #include <set>
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. */
42 namespace HPHP {
43 namespace VM {
44 namespace Transl {
46 static const bool trustSigSegv = false;
48 static const uint32 transCountersPerChunk = 1024 * 1024 / 8;
50 class TranslatorX64;
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
57 * g_context.
59 enum VMRegState {
60 REGSTATE_CLEAN,
61 REGSTATE_DIRTY
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
69 * the same contents.
71 struct SrcKey {
72 Func::FuncId m_funcId;
73 Offset m_offset;
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.
85 #define CMP(field) \
86 if (field < r.field) return -1; \
87 if (field > r.field) return 1
88 CMP(m_funcId);
89 CMP(m_offset);
90 #undef CMP
91 return 0;
93 bool operator==(const SrcKey& r) const {
94 return cmp(r) == 0;
96 bool operator!=(const SrcKey& r) const {
97 return cmp(r) != 0;
99 bool operator<(const SrcKey& r) const {
100 return cmp(r) < 0;
102 bool operator>(const SrcKey& r) const {
103 return cmp(r) > 0;
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 {
110 return hash(sk);
112 static bool equal(const SrcKey& sk1, const SrcKey& sk2) {
113 return sk1 == 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) {
125 SrcKey k;
126 k.m_funcId = in >> 32;
127 k.m_offset = in & 0xffffffff;
128 return k;
131 void trace(const char *fmt, ...) const;
132 int offset() const {
133 return m_offset;
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.
148 struct DynLocation {
149 Location location;
150 RuntimeType rtt;
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;
163 // Hash function
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();
180 bool isInt() const {
181 return rtt.isInt();
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 {
196 return rtt.isNull();
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.
227 enum TXFlags {
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
237 // outputs.
238 class NormalizedInstruction {
239 public:
240 NormalizedInstruction* next;
241 NormalizedInstruction* prev;
243 SrcKey source;
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.
252 const Unit* m_unit;
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
259 // instruction
260 ArgUnion imm[3];
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.
280 int stackOff;
281 unsigned hasConstImm:1;
282 unsigned startsBB: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)
298 unsigned skipSync:1;
300 * grouped indicates that the tracelet should not be broken
301 * (eg by a side exit) between the preceding instruction and
302 * this one
304 unsigned grouped:1;
306 * guardedThis indicates that we know that ar->m_this is
307 * a valid $this. eg:
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)
326 unsigned noCtor:1;
328 * instruction is statically known to have no effect, e.g. unboxing a Cell
330 unsigned noOp:1;
332 * This is an FPush* that will be directly bound to a Func*
334 unsigned directCall:1;
336 ArgUnion constImm;
337 TXFlags m_txFlags;
339 Op op() const;
340 Op mInstrOp() const;
341 PC pc() const;
342 const Unit* unit() const;
343 Offset offset() const;
345 NormalizedInstruction() :
346 next(NULL),
347 prev(NULL),
348 source(),
349 inputs(),
350 outStack(NULL),
351 outLocal(NULL),
352 outStack2(NULL),
353 outStack3(NULL),
354 deadLocs(),
355 checkedInputs(0),
356 hasConstImm(false),
357 invertCond(false),
358 ignoreInnerType(false),
359 skipSync(false),
360 grouped(false),
361 guardedThis(false),
362 guardedCls(false),
363 noSurprise(false),
364 noCtor(false),
365 noOp(false),
366 directCall(false),
367 m_txFlags(Interp) {
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);
396 enum OutputUse {
397 OutputUsed,
398 OutputUnused,
399 OutputInferred,
400 OutputDoesntCare
402 OutputUse outputIsUsed(DynLocation* output) const;
404 std::string toString() const;
407 class TranslationFailedExc : public std::exception {
408 public:
409 const char* m_file; // must be static
410 const int m_line;
411 TranslationFailedExc(const char* file, int line) :
412 m_file(file), m_line(line) { }
415 class UnknownInputExc : public std::exception {
416 public:
417 const char* m_file; // must be static
418 const int m_line;
419 UnknownInputExc(const char* file, int line)
420 : m_file(file), m_line(line) { }
423 #define punt() do { \
424 throw TranslationFailedExc(__FILE__, __LINE__); \
425 } while(0)
427 #define throwUnknownInput() do { \
428 throw UnknownInputExc(__FILE__, __LINE__); \
429 } while(0);
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
434 * be executed.
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
437 * and output.
439 typedef hphp_hash_map<Location, DynLocation*, Location> ChangeMap;
440 typedef ChangeMap DepMap;
441 typedef hphp_hash_set<Location, Location> LocationSet;
443 struct InstrStream {
444 InstrStream() : first(NULL), last(NULL) {}
445 void append(NormalizedInstruction* ni);
446 void remove(NormalizedInstruction* ni);
447 NormalizedInstruction* first;
448 NormalizedInstruction* last;
451 struct RefDeps {
452 struct Record {
453 vector<bool> m_mask;
454 vector<bool> m_vals;
456 std::string pretty() const {
457 std::ostringstream out;
458 out << "mask=";
459 for (size_t i = 0; i < m_mask.size(); ++i) {
460 out << (m_mask[i] ? "1" : "0");
462 out << " vals=";
463 for (size_t i = 0; i < m_vals.size(); ++i) {
464 out << (m_vals[i] ? "1" : "0");
466 return out.str();
469 typedef hphp_hash_map<int64, Record, int64_hash> ArMap;
470 ArMap m_arMap;
472 RefDeps() {}
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();
493 struct ActRecState {
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;
515 enum State {
516 GUESSABLE, KNOWN, UNKNOWABLE
519 struct Record {
520 State m_state;
521 const Func* m_topFunc;
522 int m_entryArDelta; // delta at BB entry to guessed ActRec.
525 std::vector<Record> m_arStack;
527 ActRecState() {}
528 void pushFuncD(const Func* func);
529 void pushDynFunc();
530 void pop();
531 bool getReffiness(int argNum, int stackOffset, RefDeps* outRefDeps);
532 const Func* getCurrentFunc();
533 State getCurrentState();
536 struct Tracelet : private boost::noncopyable {
537 ChangeMap m_changes;
538 DepMap m_dependencies;
539 DepMap m_resolvedDeps; // dependencies resolved by static analysis
540 InstrStream m_instrStream;
541 int m_stackChange;
543 // SrcKey for the start of the Tracelet. This might be different
544 // from m_instrStream.first->source.
545 SrcKey m_sk;
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.
551 SrcKey m_nextSk;
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
559 int m_numOpcodes;
561 // Assumptions about entering actRec's reffiness.
562 ActRecState m_arState;
563 RefDeps m_refDeps;
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;
579 Tracelet() :
580 m_stackChange(0),
581 m_arState(),
582 m_analysisFailed(false) { }
584 NormalizedInstruction* newNormalizedInstruction();
585 DynLocation* newDynLocation(Location l, DataType t);
586 DynLocation* newDynLocation(Location l, RuntimeType t);
587 DynLocation* newDynLocation();
589 void print();
592 struct TraceletContext {
593 Tracelet* m_t;
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;
599 bool m_aliasTaint;
600 bool m_varEnvTaint;
602 TraceletContext()
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);
610 void aliasTaint();
611 void varEnvTaint();
613 private:
614 static bool canBeAliased(const DynLocation* dl);
617 enum TransKind {
618 TransNormal = 0,
619 TransAnchor = 1,
620 TransProlog = 2,
623 const char* getTransKindName(TransKind kind);
626 * Used to maintain a mapping from the bytecode to its corresponding x86.
628 struct TransBCMapping {
629 Offset bcStart;
630 TCA aStart;
631 TCA astubsStart;
635 * A record with various information about a translation.
637 struct TransRec {
638 TransID id;
639 TransKind kind;
640 SrcKey src;
641 MD5 md5;
642 uint32 bcStopOffset;
643 vector<DynLocation> dependencies;
644 TCA aStart;
645 uint32 aLen;
646 TCA astubsStart;
647 uint32 astubsLen;
648 TCA counterStart;
649 uint8 counterLen;
650 vector<TransBCMapping> bcMapping;
652 static const TransID InvalidID = -1LL;
654 TransRec() {}
656 TransRec(SrcKey s,
657 MD5 _md5,
658 TransKind _kind,
659 TCA _aStart = 0,
660 uint32 _aLen = 0,
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) { }
668 TransRec(SrcKey s,
669 MD5 _md5,
670 const Tracelet& t,
671 TCA _aStart = 0,
672 uint32 _aLen = 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();
685 ++dep) {
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.
697 class Translator {
698 public:
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;
703 private:
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,
712 InputInfos& ii);
713 void getInputs(Tracelet& t,
714 NormalizedInstruction* ni,
715 int& currentStackOffset,
716 InputInfos& inputs);
717 void getOutputs(Tracelet& t,
718 NormalizedInstruction* ni,
719 int& currentStackOffset,
720 bool& varEnvTaint);
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,
728 Location loc);
730 void findImmable(ImmStack &stack, NormalizedInstruction* ni);
732 virtual void syncWork() = 0;
733 virtual void invalidateSrcKey(const SrcKey& sk) = 0;
735 protected:
736 void requestResetHighLevelTranslator();
738 TCA m_resumeHelper;
740 typedef std::map<TCA, TransID> TransDB;
741 TransDB m_transDB;
742 vector<TransRec> m_translations;
743 vector<uint64*> m_transCounters;
745 // For HHIR-based translation
746 bool m_useHHIR;
748 static Lease s_writeLease;
749 static volatile bool s_replaceInFlight;
751 public:
753 Translator();
754 virtual ~Translator();
755 static Translator* Get();
756 static Lease& WriteLease() {
757 return s_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 {
797 return m_transDB;
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()) {
805 return NULL;
807 if (it->second >= m_translations.size()) {
808 return NULL;
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;
847 return 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();
862 inline void sync() {
863 if (tl_regState == REGSTATE_CLEAN) return;
864 syncWork();
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; }
882 protected:
883 PCFilter m_dbgBLPC;
884 SrcKeySet m_dbgBLSrcKey;
885 Mutex m_dbgBlacklistLock;
886 bool isSrcKeyInBL(const Unit* unit, const SrcKey& sk);
888 public:
889 void clearDbgBL();
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 {
902 ControlFlowNone,
903 ControlFlowChangesPC,
904 ControlFlowBreaksBB
907 static inline ControlFlowInfo
908 opcodeControlFlowInfo(const Opcode instr) {
909 switch (instr) {
910 case OpJmp:
911 case OpJmpZ:
912 case OpJmpNZ:
913 case OpSwitch:
914 case OpRetC:
915 case OpRetV:
916 case OpRaise:
917 case OpExit:
918 case OpFatal:
919 case OpIterNext:
920 case OpIterInit: // May branch to fail case.
921 case OpIterInitM: // May branch to fail case.
922 case OpThrow:
923 case OpUnwind:
924 case OpEval:
925 case OpNativeImpl:
926 case OpContHandle:
927 return ControlFlowBreaksBB;
928 case OpFCall:
929 case OpFCallArray:
930 case OpIncl:
931 case OpInclOnce:
932 case OpReq:
933 case OpReqOnce:
934 case OpReqDoc:
935 case OpReqMod:
936 case OpReqSrc:
937 return ControlFlowChangesPC;
938 default:
939 return ControlFlowNone;
944 * opcodeChangesPC --
946 * Returns true if the instruction can potentially set PC to point
947 * to something other than the next instruction in the bytecode
949 static inline bool
950 opcodeChangesPC(const Opcode instr) {
951 return opcodeControlFlowInfo(instr) >= ControlFlowChangesPC;
955 * opcodeBreaksBB --
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).
961 static inline bool
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
976 #endif