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_RUNTIME_VM_TRANSLATOR_X64_H_
17 #define incl_RUNTIME_VM_TRANSLATOR_X64_H_
20 #include <boost/noncopyable.hpp>
22 #include <runtime/vm/bytecode.h>
23 #include <runtime/vm/translator/translator.h>
24 #include <runtime/vm/translator/asm-x64.h>
25 #include <runtime/vm/translator/srcdb.h>
26 #include <runtime/vm/translator/unwind-x64.h>
27 #include <runtime/vm/translator/regalloc.h>
28 #include <tbb/concurrent_hash_map.h>
29 #include <util/ringbuffer.h>
30 #include <runtime/vm/debug/debug.h>
31 #include <runtime/vm/translator/hopt/hhbctranslator.h>
32 #include "runtime/vm/translator/abi-x64.h"
36 class ExecutionContext
;
44 struct TraceletCounters
{
45 uint64_t m_numEntered
, m_numExecuted
;
48 struct TraceletCountersVec
{
50 TraceletCounters
*m_elms
;
53 TraceletCountersVec() : m_size(0), m_elms(NULL
), m_lock() { }
57 extern __thread TranslatorX64
* tx64
;
59 extern void* interpOneEntryPoints
[];
61 extern "C" TCA
funcBodyHelper(ActRec
* fp
);
63 class TranslatorX64
: public Translator
65 , boost::noncopyable
{
66 friend class SrcRec
; // so it can smash code.
67 friend class SrcDB
; // For write lock and code invalidation.
68 friend class ArgManager
;
69 friend class WithCounters
;
70 friend class DiamondGuard
;
71 friend class DiamondReturn
;
72 friend class RedirectSpillFill
;
73 friend class Tx64Reaper
;
74 friend class IRTranslator
;
75 friend class HPHP::VM::JIT::CodeGenerator
;
76 friend class HPHP::VM::JIT::HhbcTranslator
; // packBitVec()
77 friend TCA
funcBodyHelper(ActRec
* fp
);
78 template<int, int, int> friend class CondBlock
;
79 template<int> friend class JccBlock
;
80 template<int> friend class IfElseBlock
;
81 template<int> friend class UnlikelyIfBlock
;
82 typedef HPHP::DataType DataType
;
84 typedef tbb::concurrent_hash_map
<TCA
, TCA
> SignalStubMap
;
85 typedef void (*sigaction_t
)(int, siginfo_t
*, void*);
87 typedef X64Assembler Asm
;
88 typedef std::map
<int, int> ContParamMap
;
89 static const int kMaxInlineContLocals
= 10;
93 PointerMap trampolineMap
;
94 int m_numNativeTrampolines
;
95 size_t m_trampolineSize
; // size of each trampoline
96 // spillFillCode points to one of a or astubs. We need it to produce
97 // reconciliation code to the alternate buffer. Don't directly manipulate;
98 // use DiamondGuard instead.
102 SignalStubMap m_segvStubs
;
103 sigaction_t m_segvChain
;
106 TCA m_stackOverflowHelper
;
107 TCA m_dtorGenericStub
;
108 TCA m_dtorGenericStubRegs
;
109 TCA m_dtorStubs
[MaxNumDataTypes
];
110 TCA m_interceptHelper
;
112 TCA m_funcPrologueRedispatch
;
113 DataBlock m_globalData
;
115 size_t m_irAstubsUsage
;
117 // Data structures for HHIR-based translation
118 uint64_t m_numHHIRTrans
;
119 JIT::IRFactory
* m_irFactory
;
120 JIT::CSEHash
* m_constTable
;
121 JIT::TraceBuilder
* m_traceBuilder
;
122 JIT::HhbcTranslator
* m_hhbcTrans
;
123 IRTranslator
* m_irTrans
;
125 void hhirTraceStart(Offset bcStartOffset
);
126 void hhirTraceCodeGen();
127 void hhirTraceEnd(Offset bcSuccOffset
);
128 void hhirTraceFree();
131 struct SavedRegState
{
132 explicit SavedRegState(void* saver
, const RegAlloc
& state
)
137 void* saver
; // For debugging: ensure these are popped in the right order
142 std::stack
<SavedRegState
> m_savedRegMaps
;
143 volatile bool m_interceptsEnabled
;
145 UnwindRegMap m_unwindRegMap
;
146 UnwindInfoHandle m_unwindRegistrar
;
148 // Currently translating trace or instruction---only valid during
150 const Tracelet
* m_curTrace
;
151 const NormalizedInstruction
* m_curNI
;
153 struct PendingFixup
{
157 PendingFixup(TCA tca
, Fixup fixup
) :
158 m_tca(tca
), m_fixup(fixup
) { }
160 vector
<PendingFixup
> m_pendingFixups
;
161 UnwindRegInfo m_pendingUnwindRegInfo
;
163 void drawCFG(std::ofstream
& out
) const;
164 static vector
<PhysReg
> x64TranslRegs();
166 PhysReg
getReg(const Location
& loc
) {
167 return m_regMap
.getReg(loc
);
170 PhysReg
getReg(const DynLocation
& dl
) {
171 return m_regMap
.getReg(dl
.location
);
174 Asm
&getAsmFor(TCA addr
) { return Asm::Choose(a
, astubs
, addr
); }
175 void emitIncRef(PhysReg base
, DataType
);
176 void emitIncRefGenericRegSafe(PhysReg base
, int disp
, PhysReg tmp
);
177 void emitIncRefGeneric(PhysReg base
, int disp
= 0);
178 void emitDecRef(Asm
& a
, const NormalizedInstruction
& i
, PhysReg rDatum
,
180 void emitDecRef(const NormalizedInstruction
& i
, PhysReg rDatum
,
182 void emitDecRefGeneric(const NormalizedInstruction
& i
, PhysReg srcReg
,
184 void emitDecRefGenericReg(PhysReg rData
, PhysReg rType
);
185 void emitDecRefInput(Asm
& a
, const NormalizedInstruction
& i
, int input
);
186 void emitCopy(PhysReg srcCell
, int disp
, PhysReg destCell
);
187 void emitCopyToStack(Asm
& a
,
188 const NormalizedInstruction
& ni
,
191 void emitCopyToStackRegSafe(Asm
& a
,
192 const NormalizedInstruction
& ni
,
196 void emitTvSetRegSafe(const NormalizedInstruction
&, PhysReg from
,
197 DataType fromType
, PhysReg toPtr
, int toOffset
, PhysReg tmp1
, PhysReg tmp2
,
199 void emitTvSet(const NormalizedInstruction
&, PhysReg from
,
200 DataType fromType
, PhysReg toPtr
, int toOffset
= 0, bool incRefFrom
= true);
202 void emitThisCheck(const NormalizedInstruction
& i
, PhysReg reg
);
203 void emitPushAR(const NormalizedInstruction
& i
, const Func
* func
,
204 const int bytesPopped
= 0, bool isCtor
= false,
205 bool clearThis
= true, uintptr_t varEnvInvName
= 0);
207 void emitCallSaveRegs();
208 void prepareCallSaveRegs();
209 void emitCallStaticLocHelper(X64Assembler
& as
,
210 const NormalizedInstruction
& i
,
213 void emitCall(Asm
& a
, TCA dest
, bool killRegs
=false);
215 /* Continuation-related helpers */
216 static bool mapContParams(ContParamMap
& map
, const Func
* origFunc
,
217 const Func
* genFunc
);
218 void emitCallFillCont(Asm
& a
, const Func
* orig
, const Func
* gen
);
219 void emitCallUnpack(Asm
& a
, const NormalizedInstruction
& i
, int nCopy
);
220 void emitCallPack(Asm
& a
, const NormalizedInstruction
& i
, int nCopy
);
221 void emitContRaiseCheck(Asm
& a
, const NormalizedInstruction
& i
);
222 void emitContPreNext(const NormalizedInstruction
& i
, ScratchReg
& rCont
);
223 void emitContStartedCheck(const NormalizedInstruction
& i
, ScratchReg
& rCont
);
225 void translateContSendImpl(const NormalizedInstruction
& i
);
227 void translateClassExistsImpl(const Tracelet
& t
,
228 const NormalizedInstruction
& i
,
230 void recordSyncPoint(Asm
& a
, Offset pcOff
, Offset spOff
);
231 template <bool reentrant
>
232 void recordCallImpl(Asm
& a
, const NormalizedInstruction
& i
,
233 bool advance
= false);
234 void recordReentrantCall(Asm
& a
, const NormalizedInstruction
& i
) {
235 recordCallImpl
<true>(a
, i
);
237 void recordReentrantCall(const NormalizedInstruction
& i
) {
238 recordCallImpl
<true>(a
, i
);
240 void recordReentrantStubCall(const NormalizedInstruction
& i
,
241 bool advance
= false) {
242 recordCallImpl
<true>(astubs
, i
, advance
);
244 void recordCall(Asm
& a
, const NormalizedInstruction
& i
);
245 void recordCall(const NormalizedInstruction
& i
);
246 void recordStubCall(const NormalizedInstruction
& i
) {
247 recordCall(astubs
, i
);
249 void emitSideExit(Asm
& a
, const NormalizedInstruction
& dest
, bool next
);
250 void emitStringToClass(const NormalizedInstruction
& i
);
251 void emitKnownClassCheck(const NormalizedInstruction
& i
,
252 const StringData
* clssName
,
253 register_name_t reg
);
254 void emitStringToKnownClass(const NormalizedInstruction
& i
,
255 const StringData
* clssName
);
256 void emitObjToClass(const NormalizedInstruction
& i
);
257 void emitClsAndPals(const NormalizedInstruction
& i
);
258 void emitStaticPropInlineLookup(const NormalizedInstruction
& i
,
259 const DynLocation
& clsInput
,
260 const DynLocation
& propInput
,
263 inline bool isValidCodeAddress(TCA tca
) const {
264 return a
.code
.isValidAddress(tca
) || astubs
.code
.isValidAddress(tca
) ||
265 atrampolines
.code
.isValidAddress(tca
);
267 template<int Arity
> TCA
emitNAryStub(Asm
& a
, void* fptr
);
268 TCA
emitUnaryStub(Asm
& a
, void* fptr
);
269 TCA
emitBinaryStub(Asm
& a
, void* fptr
);
270 TCA
genericRefCountStub(Asm
& a
);
271 TCA
genericRefCountStubRegs(Asm
& a
);
272 TCA
getCallArrayProlog(Func
* func
);
273 TCA
emitPrologueRedispatch(Asm
&a
);
274 TCA
emitFuncGuard(Asm
& a
, const Func
*f
);
275 template <bool reentrant
>
276 void callUnaryStubImpl(Asm
& a
, const NormalizedInstruction
& i
, TCA stub
,
277 PhysReg arg
, int disp
= 0);
278 void callUnaryReentrantStub(Asm
& a
, const NormalizedInstruction
& i
, TCA stub
,
279 PhysReg arg
, int disp
= 0) {
280 callUnaryStubImpl
<true>(a
, i
, stub
, arg
, disp
);
282 void callUnaryStub(Asm
& a
, const NormalizedInstruction
& i
, TCA stub
,
283 PhysReg arg
, int disp
= 0) {
284 callUnaryStubImpl
<false>(a
, i
, stub
, arg
, disp
);
286 void callBinaryStub(Asm
& a
, const NormalizedInstruction
& i
, TCA stub
,
287 PhysReg arg1
, PhysReg arg2
);
288 void emitDerefStoreToLoc(PhysReg srcReg
, const Location
& destLoc
);
290 void binaryIntegerArith(const NormalizedInstruction
&i
,
291 Opcode op
, PhysReg srcReg
, PhysReg srcDestReg
);
292 void binaryArithCell(const NormalizedInstruction
&i
,
293 Opcode op
, const DynLocation
& in1
,
294 const DynLocation
& inout
);
295 void binaryArithLocal(const NormalizedInstruction
&i
,
297 const DynLocation
& in1
,
298 const DynLocation
& in2
,
299 const DynLocation
& out
);
300 void emitRB(Asm
& a
, Trace::RingBufferType t
, SrcKey sk
,
301 RegSet toSave
= RegSet());
302 void emitRB(Asm
& a
, Trace::RingBufferType t
, const char* msgm
,
303 RegSet toSave
= RegSet());
306 ArgDontAllocate
= -1,
309 void allocInputsForCall(const NormalizedInstruction
& i
,
314 TypedValue tvScratch
;
315 TypedValue tvLiteral
;
322 } __attribute__((aligned(16)));
325 MVecTransState
* m_vecState
;
326 int mResultStackOffset(const NormalizedInstruction
& ni
) const;
327 bool generateMVal(const Tracelet
& t
, const NormalizedInstruction
& ni
,
328 const MInstrInfo
& mii
) const;
329 bool logicalTeleportMVal(const Tracelet
& t
, const NormalizedInstruction
& ni
,
330 const MInstrInfo
& mii
) const;
331 bool teleportMVal(const Tracelet
& t
, const NormalizedInstruction
& ni
,
332 const MInstrInfo
& mii
) const;
333 bool useTvResult(const Tracelet
& t
, const NormalizedInstruction
& ni
,
334 const MInstrInfo
& mii
) const;
335 bool forceMValIncDec(const NormalizedInstruction
& ni
, const DynLocation
& base
,
336 const DynLocation
& val
) const;
337 bool forceMValIncDec(const Tracelet
& t
, const NormalizedInstruction
& ni
,
338 const MInstrInfo
& mii
) const;
339 void emitBaseLCR(const Tracelet
& t
, const NormalizedInstruction
& ni
,
340 const MInstrInfo
& mii
, unsigned iInd
, LazyScratchReg
& rBase
);
341 void emitBaseH(unsigned iInd
, LazyScratchReg
& rBase
);
342 void emitBaseN(const Tracelet
& t
, const NormalizedInstruction
& ni
,
343 const MInstrInfo
& mii
, unsigned iInd
, LazyScratchReg
& rBase
);
344 void emitBaseG(const Tracelet
& t
, const NormalizedInstruction
& ni
,
345 const MInstrInfo
& mii
, unsigned iInd
, LazyScratchReg
& rBase
);
346 void emitBaseS(const Tracelet
& t
, const NormalizedInstruction
& ni
,
347 unsigned iInd
, bool ctxFixed
, LazyScratchReg
& rBase
);
348 void emitBaseOp(const Tracelet
& t
, const NormalizedInstruction
& ni
,
349 const MInstrInfo
& mii
, unsigned iInd
, bool ctxFixed
,
350 LazyScratchReg
& rBase
);
351 void emitHphpArrayGetIntKey(const NormalizedInstruction
& i
,
353 const DynLocation
& keyLoc
,
356 template<DataType keyType
>
357 void emitElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
358 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
359 LazyScratchReg
& rBase
);
360 void emitProp(const MInstrInfo
& mii
, bool ctxFixed
, unsigned mInd
,
361 unsigned iInd
, LazyScratchReg
& rBase
);
362 void emitPropGeneric(const Tracelet
& t
, const NormalizedInstruction
& ni
,
363 const MInstrInfo
& mii
, bool ctxFixed
, unsigned mInd
,
364 unsigned iInd
, LazyScratchReg
& rBase
);
365 void emitPropSpecialized(MInstrAttr
, const Class
*,
366 int propOffset
, unsigned mInd
, unsigned iInd
,
367 LazyScratchReg
& rBase
);
368 void emitNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
369 unsigned mInd
, LazyScratchReg
& rBase
);
370 void emitIntermediateOp(const Tracelet
& t
, const NormalizedInstruction
& ni
,
371 const MInstrInfo
& mii
, bool ctxFixed
, unsigned mInd
,
372 unsigned& iInd
, LazyScratchReg
& rBase
);
373 bool needFirstRatchet(const Tracelet
& t
, const NormalizedInstruction
& ni
,
374 const MInstrInfo
& mii
) const;
375 bool needFinalRatchet(const Tracelet
& t
, const NormalizedInstruction
& ni
,
376 const MInstrInfo
& mii
) const;
377 unsigned nLogicalRatchets(const Tracelet
& t
, const NormalizedInstruction
& ni
,
378 const MInstrInfo
& mii
) const;
379 int ratchetInd(const Tracelet
& t
, const NormalizedInstruction
& ni
,
380 const MInstrInfo
& mii
, unsigned mInd
) const;
381 void emitRatchetRefs(const Tracelet
& t
, const NormalizedInstruction
& ni
,
382 const MInstrInfo
& mii
, unsigned mInd
,
384 template <bool useEmpty
>
385 void emitIssetEmptyElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
386 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
388 template <bool useEmpty
>
389 void emitIssetEmptyProp(const Tracelet
& t
, const NormalizedInstruction
& ni
,
390 const MInstrInfo
& mii
, bool ctxFixed
, unsigned mInd
,
391 unsigned iInd
, PhysReg rBase
);
392 void emitVGetNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
393 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
395 void emitSetNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
396 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
398 void emitSetOpNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
399 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
401 void emitIncDecNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
402 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
404 void emitBindNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
405 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
407 void emitNotSuppNewElem(const Tracelet
& t
, const NormalizedInstruction
& ni
,
408 const MInstrInfo
& mii
, unsigned mInd
, unsigned iInd
,
410 bool needMInstrCtx(const Tracelet
& t
, const NormalizedInstruction
& ni
) const;
411 void emitMPre(const Tracelet
& t
, const NormalizedInstruction
& ni
,
412 const MInstrInfo
& mii
, bool& ctxFixed
, unsigned& mInd
,
413 unsigned& iInd
, LazyScratchReg
& rBase
);
414 void emitMPost(const Tracelet
& t
, const NormalizedInstruction
& ni
,
415 const MInstrInfo
& mii
);
416 #define MII(instr, attrs, bS, iS, vC, fN) \
417 void emit##instr##Elem(const Tracelet& t, const NormalizedInstruction& ni, \
418 const MInstrInfo& mii, unsigned mInd, unsigned iInd, \
420 void emit##instr##Prop(const Tracelet& t, const NormalizedInstruction& ni, \
421 const MInstrInfo& mii, bool ctxFixed, unsigned mInd, \
422 unsigned iInd, LazyScratchReg& rBase); \
423 void emitFinal##instr##MOp(const Tracelet& t, \
424 const NormalizedInstruction& ni, \
425 const MInstrInfo& mii, bool ctxFixed, \
426 unsigned mInd, unsigned iInd, \
427 LazyScratchReg& rBase);
487 CASE(FPushClsMethodD) \
488 CASE(FPushClsMethodF) \
489 CASE(FPushObjMethodD) \
492 CASE(FPushContFunc) \
503 CASE(VerifyParamType) \
505 CASE(StaticLocInit) \
518 CASE(InterfaceExists) \
535 // These are instruction-like functions which cover more than one
537 #define PSEUDOINSTRS \
538 CASE(BinaryArithOp) \
542 CASE(UnaryBooleanOp) \
544 CASE(AssignToLocalOp) \
550 void analyze ## nm(Tracelet& t, NormalizedInstruction& i); \
551 void translate ## nm(const Tracelet& t, const NormalizedInstruction& i);
561 void branchWithFlagsSet(const Tracelet
& t
, const NormalizedInstruction
& i
,
563 void fuseBranchSync(const Tracelet
& t
, const NormalizedInstruction
& i
);
564 void fuseBranchAfterBool(const Tracelet
& t
, const NormalizedInstruction
& i
,
566 void fuseBranchAfterStaticBool(const Tracelet
& t
,
567 const NormalizedInstruction
& i
,
569 void translateSetMArray(const Tracelet
&t
, const NormalizedInstruction
& i
);
570 void emitPropGet(const NormalizedInstruction
& i
,
571 const DynLocation
& base
,
573 const Location
& outLoc
);
574 void translateCGetMProp(const Tracelet
&t
, const NormalizedInstruction
& i
);
575 void translateCGetM_LEE(const Tracelet
&t
, const NormalizedInstruction
& i
);
576 void translateCGetM_GE(const Tracelet
&t
, const NormalizedInstruction
& i
);
577 void emitGetGlobal(const NormalizedInstruction
& i
, int nameIdx
,
579 void emitArrayElem(const NormalizedInstruction
& i
,
580 const DynLocation
* baseInput
,
582 const DynLocation
* keyIn
,
583 const Location
& outLoc
);
584 void translateIssetMSimple(const Tracelet
& t
,
585 const NormalizedInstruction
& ni
);
586 void setupActRecClsForStaticCall(const NormalizedInstruction
& i
,
587 const Func
* func
, const Class
* cls
,
588 size_t clsOff
, bool forward
);
590 const Func
* findCuf(const NormalizedInstruction
& ni
,
591 Class
* &cls
, StringData
*& invName
, bool& forward
);
592 static void toStringHelper(ObjectData
*obj
);
593 void invalidateSrcKey(const SrcKey
& sk
);
594 bool dontGuardAnyInputs(Opcode op
);
597 void invalidateSrcKeys(const T
& keys
) {
598 BlockingLeaseHolder
writer(s_writeLease
);
600 for (typename
T::const_iterator i
= keys
.begin(); i
!= keys
.end(); ++i
) {
601 invalidateSrcKey(*i
);
605 const UnwindRegInfo
* getUnwindInfo(CTCA ip
) const {
606 return m_unwindRegMap
.find(ip
);
609 void enableIntercepts() {m_interceptsEnabled
= true;}
610 bool interceptsEnabled() {return m_interceptsEnabled
;}
612 static void SEGVHandler(int signum
, siginfo_t
*info
, void *ctx
);
614 // public for syncing gdb state
615 Debug::DebugInfo m_debugInfo
;
617 void fixupWork(VMExecutionContext
* ec
, ActRec
* startRbp
) const;
618 void fixup(VMExecutionContext
* ec
) const;
620 // helpers for srcDB.
621 SrcRec
* getSrcRec(const SrcKey
& sk
) {
622 // TODO: add a insert-or-find primitive to THM
623 if (SrcRec
* r
= m_srcDB
.find(sk
)) return r
;
624 ASSERT(s_writeLease
.amOwner());
625 return m_srcDB
.insert(sk
);
628 TCA
getTopTranslation(const SrcKey
& sk
) {
629 return getSrcRec(sk
)->getTopTranslation();
632 TCA
getCallToExit() {
636 TCA
getRetFromInterpretedFrame() {
640 // If we were to shove every little helper function into this class
641 // header, we'd spend the rest of our lives compiling. So, these public
642 // functions are for static helpers private to translator-x64.cpp. Be
645 Asm
& getAsm() { return a
; }
646 void emitChainTo(const SrcKey
*dest
, bool isCall
= false);
647 void syncOutputs(const Tracelet
& t
);
648 void syncOutputs(const NormalizedInstruction
& i
);
649 void syncOutputs(int stackOff
);
651 static bool isPseudoEvent(const char* event
);
652 void getPerfCounters(Array
& ret
);
655 virtual void syncWork();
657 void spillTo(DataType t
, PhysReg reg
, bool writeType
,
658 PhysReg base
, int disp
);
660 // SpillFill interface
661 void spill(const Location
& loc
, DataType t
, PhysReg reg
,
663 void fill(const Location
& loc
, PhysReg reg
);
664 void fillByMov(PhysReg src
, PhysReg dst
);
665 void loadImm(int64 immVal
, PhysReg reg
);
666 void poison(PhysReg dest
);
669 void analyzeInstr(Tracelet
& t
, NormalizedInstruction
& i
);
670 bool acquireWriteLease(bool blocking
) {
671 return s_writeLease
.acquire(blocking
);
673 void dropWriteLease() {
676 void interceptPrologues(Func
* func
);
678 void emitGuardChecks(Asm
& a
, const SrcKey
&, const ChangeMap
&,
679 const RefDeps
&, SrcRec
&);
680 void emitOneGuard(const Tracelet
& t
,
681 const NormalizedInstruction
& i
,
682 PhysReg reg
, int disp
, DataType type
,
684 void irEmitResolvedDeps(const ChangeMap
& resolvedDeps
);
686 void emitVariantGuards(const Tracelet
& t
, const NormalizedInstruction
& i
);
687 void emitPredictionGuards(const NormalizedInstruction
& i
);
689 Debug::DebugInfo
* getDebugInfo() { return &m_debugInfo
; }
692 TCA
getInterceptHelper();
693 void translateInstr(const Tracelet
& t
, const NormalizedInstruction
& i
);
694 void translateInstrWork(const Tracelet
& t
, const NormalizedInstruction
& i
);
695 void irTranslateInstr(const Tracelet
& t
, const NormalizedInstruction
& i
);
696 void irTranslateInstrWork(const Tracelet
& t
, const NormalizedInstruction
& i
);
697 void irTranslateInstrDefault(const Tracelet
& t
,
698 const NormalizedInstruction
& i
);
699 bool checkTranslationLimit(const SrcKey
&, const SrcRec
&) const;
700 void translateTracelet(const Tracelet
& t
);
701 bool irTranslateTracelet(const Tracelet
& t
,
703 const TCA stubStart
);
704 void emitStringCheck(Asm
& _a
, PhysReg base
, int offset
, PhysReg tmp
);
705 void emitTypeCheck(Asm
& _a
, DataType dt
,
706 PhysReg base
, int offset
,
707 PhysReg tmp
= InvalidReg
);
708 void irAssertType(const Location
& l
, const RuntimeType
& rtt
);
709 void checkType(Asm
&, const Location
& l
, const RuntimeType
& rtt
,
711 void irCheckType(Asm
&, const Location
& l
, const RuntimeType
& rtt
,
713 void checkRefs(Asm
&, const SrcKey
&, const RefDeps
&, SrcRec
&);
715 void emitFrameRelease(Asm
& a
, const NormalizedInstruction
& i
,
716 bool noThis
= false);
717 void dumpStack(const char* msg
, int offset
) const;
719 static const size_t kJmpTargetAlign
= 16;
720 static const int kJmpLen
= 5;
721 static const int kJmpccLen
= 6;
722 static const int kJcc8Len
= 3;
723 static const int kLeaRipLen
= 7;
724 // Cache alignment is required for mutable instructions to make sure
725 // mutations don't "tear" on remote cpus.
726 static const size_t kX64CacheLineSize
= 64;
727 void moveToAlign(Asm
&aa
, const size_t alignment
= kJmpTargetAlign
,
728 const bool unreachable
= true);
729 void prepareForSmash(Asm
&a
, int nBytes
);
730 void prepareForSmash(int nBytes
);
731 static bool isSmashable(Asm
&a
, int nBytes
);
732 static void smash(Asm
&a
, TCA src
, TCA dest
);
734 TCA
getTranslation(const SrcKey
*sk
, bool align
, bool forceNoHHIR
= false);
735 TCA
retranslate(SrcKey sk
, bool align
, bool useHHIR
);
736 TCA
retranslateOpt(TransID transId
, bool align
);
737 TCA
retranslateAndPatchNoIR(SrcKey sk
,
740 TCA
bindJmp(TCA toSmash
, SrcKey dest
, ServiceRequest req
);
741 TCA
bindJmpccFirst(TCA toSmash
,
742 Offset offTrue
, Offset offFalse
,
745 TCA
bindJmpccSecond(TCA toSmash
, const Offset off
,
747 void emitFallbackJmp(SrcRec
& dest
);
748 void emitFallbackJmp(Asm
& as
, SrcRec
& dest
);
749 void emitFallbackUncondJmp(Asm
& as
, SrcRec
& dest
);
750 void emitDebugPrint(Asm
&, const char*,
755 TCA
emitServiceReq(bool align
, ServiceRequest
, int numArgs
, ...);
756 TCA
emitServiceReq(ServiceRequest
, int numArgs
, ...);
757 TCA
emitServiceReqVA(bool align
, ServiceRequest
, int numArgs
, va_list args
);
758 TCA
emitRetFromInterpretedFrame();
759 TCA
emitGearTrigger(Asm
& a
, const SrcKey
& sk
, TransID transId
);
760 void emitBox(DataType t
, PhysReg rToBox
);
761 void emitUnboxTopOfStack(const NormalizedInstruction
& ni
);
762 void emitBindCall(const Tracelet
& t
, const NormalizedInstruction
&ni
,
763 Offset atCall
, Offset after
);
764 void emitCondJmp(const SrcKey
&skTrue
, const SrcKey
&skFalse
,
766 void emitInterpOne(const Tracelet
& t
, const NormalizedInstruction
& i
);
767 void emitMovRegReg(Asm
& a
, PhysReg src
, PhysReg dest
);
768 void emitMovRegReg(PhysReg src
, PhysReg dest
);
769 void enterTC(SrcKey sk
);
771 void recordGdbTranslation(const SrcKey
& sk
, const Unit
* u
,
774 bool exit
, bool inPrologue
);
775 void recordGdbStub(const Asm
& a
, TCA start
, const char* name
);
776 void recordBCInstr(uint32_t op
, const Asm
& a
, const TCA addr
);
778 void emitStackCheck(int funcDepth
, Offset pc
);
779 void emitStackCheckDynamic(int numArgs
, Offset pc
);
780 void emitTestSurpriseFlags();
781 void emitCheckSurpriseFlagsEnter(bool inTracelet
, Offset pcOff
,
783 TCA
emitTransCounterInc(Asm
& a
);
785 static void trimExtraArgs(ActRec
* ar
);
786 static int shuffleArgsForMagicCall(ActRec
* ar
);
787 static void setArgInActRec(ActRec
* ar
, int argNum
, uint64_t datum
,
789 TCA
funcPrologue(Func
* func
, int nArgs
);
790 bool checkCachedPrologue(const Func
* func
, int param
, TCA
& plgOut
) const;
791 SrcKey
emitPrologue(Func
* func
, int nArgs
);
792 void emitNativeImpl(const Func
*, bool emitSavedRIPReturn
);
793 TCA
emitInterceptPrologue(Func
* func
, TCA next
=NULL
);
794 void emitBindJ(Asm
& a
, int cc
, const SrcKey
& dest
,
796 void emitBindJmp(Asm
& a
, const SrcKey
& dest
,
797 ServiceRequest req
= REQ_BIND_JMP
);
798 void emitBindJcc(Asm
& a
, ConditionCode cc
, const SrcKey
& dest
,
799 ServiceRequest req
= REQ_BIND_JCC
);
800 void emitBindJmp(const SrcKey
& dest
);
801 void emitBindCallHelper(register_name_t stashedAR
,
806 void emitIncCounter(TCA start
, int cntOfs
);
808 void analyzeReqLit(Tracelet
& t
, NormalizedInstruction
& i
,
810 void translateReqLit(const Tracelet
& t
, const NormalizedInstruction
& i
,
812 struct ReqLitStaticArgs
{
813 HPHP::Eval::PhpFile
* m_efile
;
818 static void reqLitHelper(const ReqLitStaticArgs
* args
);
819 struct FCallArrayArgs
{
823 static void fCallArrayHelper(const FCallArrayArgs
* args
);
825 TCA
getNativeTrampoline(TCA helperAddress
);
826 TCA
emitNativeTrampoline(TCA helperAddress
);
828 // Utility function shared with IR code
829 static uint64_t packBitVec(const vector
<bool>& bits
, unsigned i
);
832 void resume(SrcKey sk
);
834 TCA
translate(const SrcKey
*sk
, bool align
, bool useHHIR
);
837 virtual ~TranslatorX64();
840 static TranslatorX64
* Get();
842 // Called before entering a new PHP "world."
845 // Called at the end of eval()
848 // Called when name is bound to a value
849 void defineCns(StringData
* name
);
851 // Returns a string with cache usage information
852 std::string
getUsage();
854 // true iff calling thread is sole writer.
855 static bool canWrite() {
856 // We can get called early in boot, so allow null tx64.
857 return !tx64
|| s_writeLease
.amOwner();
860 // Returns true on success
861 bool dumpTC(bool ignoreLease
= false);
863 // Returns true on success
864 bool dumpTCCode(const char* filename
);
866 // Returns true on success
869 // Async hook for file modifications.
870 bool invalidateFile(Eval::PhpFile
* f
);
871 void invalidateFileWork(Eval::PhpFile
* f
);
873 // Start a new translation space. Returns true IFF this thread created
877 // Debugging interfaces to prevent tampering with code.
879 void unprotectCode();
882 virtual bool addDbgGuards(const Unit
* unit
);
883 virtual bool addDbgGuard(const Func
* func
, Offset offset
);
884 void addDbgGuardImpl(const SrcKey
& sk
, SrcRec
& sr
);
886 private: // Only for HackIR
887 void emitReqRetransNoIR(Asm
& as
, SrcKey
& sk
);
889 public: // Only for HackIR
890 #define DECLARE_FUNC(nm) \
891 void irTranslate ## nm(const Tracelet& t, \
892 const NormalizedInstruction& i);
893 #define CASE DECLARE_FUNC
901 // Helper functions not covered by macros above
902 void irTranslateSetMProp(const Tracelet
& t
, const NormalizedInstruction
& i
);
903 void irTranslateCGetMProp(const Tracelet
&t
, const NormalizedInstruction
& i
);
904 void irTranslateCGetM_LEE(const Tracelet
&t
, const NormalizedInstruction
& i
);
905 void irTranslateCGetM_GE(const Tracelet
&t
, const NormalizedInstruction
& i
);
906 void irTranslateReqLit(const Tracelet
& t
,
907 const NormalizedInstruction
& i
,
913 * RAII bookmark for temporarily rewinding a.code.frontier.
916 typedef X64Assembler Asm
;
920 CodeCursor(Asm
& a
, TCA newFrontier
) :
921 m_a(a
), m_oldFrontier(a
.code
.frontier
) {
922 ASSERT(TranslatorX64::canWrite());
923 m_a
.code
.frontier
= newFrontier
;
924 TRACE_MOD(Trace::trans
, 1, "RewindTo: %p (from %p)\n",
925 m_a
.code
.frontier
, m_oldFrontier
);
928 ASSERT(TranslatorX64::canWrite());
929 m_a
.code
.frontier
= m_oldFrontier
;
930 TRACE_MOD(Trace::trans
, 1, "Restore: %p\n",
935 const size_t kTrampolinesBlockSize
= 8 << 12;
937 // minimum length in bytes of each trampoline code sequence
938 // Note that if stats is on, then this size is ~24 bytes due to the
939 // instrumentation code that counts the number of calls through each
941 const size_t kMinPerTrampolineSize
= 11;
943 const size_t kMaxNumTrampolines
= kTrampolinesBlockSize
/
944 kMinPerTrampolineSize
;
946 void fcallHelperThunk() asm ("__fcallHelperThunk");
947 void funcBodyHelperThunk() asm ("__funcBodyHelperThunk");
949 // These could be static but are used in hopt/codegen.cpp
950 void raiseUndefVariable(StringData
* nm
);
951 void defFuncHelper(Func
*f
);
952 Instance
* newInstanceHelper(Class
* cls
, int numArgs
, ActRec
* ar
,
954 Instance
* newInstanceHelperCached(Class
** classCache
,
955 const StringData
* clsName
, int numArgs
,
956 ActRec
* ar
, ActRec
* prevAr
);
958 SrcKey
nextSrcKey(const Tracelet
& t
, const NormalizedInstruction
& i
);
959 bool isNormalPropertyAccess(const NormalizedInstruction
& i
,
962 bool isContextFixed();
963 int getNormalPropertyOffset(const NormalizedInstruction
& i
,
965 int propInput
, int objInput
);
966 bool isSupportedCGetMProp(const NormalizedInstruction
& i
);
967 bool isSupportedCGetM_LE(const NormalizedInstruction
& i
);
968 bool isSupportedCGetM_LEE(const NormalizedInstruction
& i
);
969 bool isSupportedCGetM_RE(const NormalizedInstruction
& i
);
970 bool isSupportedCGetM_GE(const NormalizedInstruction
& i
);
971 bool isSupportedCGetM(const NormalizedInstruction
& i
);
972 TXFlags
planInstrAdd_Int(const NormalizedInstruction
& i
);
973 TXFlags
planInstrAdd_Array(const NormalizedInstruction
& i
);
974 void dumpTranslationInfo(const Tracelet
& t
, TCA postGuards
);
976 // SpaceRecorder is used in translator-x64.cpp and in hopt/irtranslator.cpp
977 // RAII logger for TC space consumption.
978 struct SpaceRecorder
{
980 const X64Assembler m_a
;
981 // const X64Assembler& m_a;
982 const uint8_t *m_start
;
983 SpaceRecorder(const char* name
, const X64Assembler
& a
) :
984 m_name(name
), m_a(a
), m_start(a
.code
.frontier
)
987 if (Trace::moduleEnabledRelease(Trace::tcspace
, 1)) {
988 ptrdiff_t diff
= m_a
.code
.frontier
- m_start
;
989 if (diff
) Trace::traceRelease("TCSpace %10s %3d\n", m_name
, diff
);
991 if (Trace::moduleEnabledRelease(Trace::tcdump
, 1)) {
992 Trace::traceRelease("TCDump %s", m_name
);
993 for (const uint8_t* p
= m_start
; p
< m_a
.code
.frontier
; p
++) {
994 Trace::traceRelease(" %x", *p
);
996 Trace::traceRelease("\n");
1001 typedef const int COff
; // Const offsets