Clean up register allocation for Location::This
[hiphop-php.git] / src / runtime / vm / translator / translator-x64.h
blob5b15b58b40575f47938d144338e0da1d131e6f5a
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 +----------------------------------------------------------------------+
16 #ifndef incl_RUNTIME_VM_TRANSLATOR_X64_H_
17 #define incl_RUNTIME_VM_TRANSLATOR_X64_H_
19 #include <signal.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"
34 namespace HPHP {
36 class ExecutionContext;
38 namespace VM {
39 namespace Transl {
41 class IRTranslator;
42 class MVecTransState;
44 struct TraceletCounters {
45 uint64_t m_numEntered, m_numExecuted;
48 struct TraceletCountersVec {
49 int64_t m_size;
50 TraceletCounters *m_elms;
51 Mutex m_lock;
53 TraceletCountersVec() : m_size(0), m_elms(NULL), m_lock() { }
56 class TranslatorX64;
57 extern __thread TranslatorX64* tx64;
59 extern void* interpOneEntryPoints[];
61 extern "C" TCA funcBodyHelper(ActRec* fp);
63 class TranslatorX64 : public Translator
64 , SpillFill
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;
90 Asm a;
91 Asm astubs;
92 Asm atrampolines;
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.
99 Asm* m_spillFillCode;
101 SrcDB m_srcDB;
102 SignalStubMap m_segvStubs;
103 sigaction_t m_segvChain;
104 TCA m_callToExit;
105 TCA m_retHelper;
106 TCA m_stackOverflowHelper;
107 TCA m_dtorGenericStub;
108 TCA m_dtorGenericStubRegs;
109 TCA m_dtorStubs[MaxNumDataTypes];
110 TCA m_interceptHelper;
111 TCA m_defClsHelper;
112 TCA m_funcPrologueRedispatch;
113 DataBlock m_globalData;
114 size_t m_irAUsage;
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)
133 : saver(saver)
134 , savedState(state)
137 void* saver; // For debugging: ensure these are popped in the right order
138 RegAlloc savedState;
141 RegAlloc m_regMap;
142 std::stack<SavedRegState> m_savedRegMaps;
143 volatile bool m_interceptsEnabled;
144 FixupMap m_fixupMap;
145 UnwindRegMap m_unwindRegMap;
146 UnwindInfoHandle m_unwindRegistrar;
148 // Currently translating trace or instruction---only valid during
149 // translate phase.
150 const Tracelet* m_curTrace;
151 const NormalizedInstruction* m_curNI;
153 struct PendingFixup {
154 TCA m_tca;
155 Fixup m_fixup;
156 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,
179 DataType type);
180 void emitDecRef(const NormalizedInstruction& i, PhysReg rDatum,
181 DataType type);
182 void emitDecRefGeneric(const NormalizedInstruction& i, PhysReg srcReg,
183 int disp = 0);
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,
189 PhysReg src,
190 int off);
191 void emitCopyToStackRegSafe(Asm& a,
192 const NormalizedInstruction& ni,
193 PhysReg src,
194 int off,
195 PhysReg tmpReg);
196 void emitTvSetRegSafe(const NormalizedInstruction&, PhysReg from,
197 DataType fromType, PhysReg toPtr, int toOffset, PhysReg tmp1, PhysReg tmp2,
198 bool incRefFrom);
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,
211 ScratchReg& output,
212 ptrdiff_t ch);
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);
224 template<bool raise>
225 void translateContSendImpl(const NormalizedInstruction& i);
227 void translateClassExistsImpl(const Tracelet& t,
228 const NormalizedInstruction& i,
229 Attr typeAttr);
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,
261 PhysReg scr);
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,
296 Opcode op,
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());
305 enum {
306 ArgDontAllocate = -1,
307 ArgAnyReg = -2
309 void allocInputsForCall(const NormalizedInstruction& i,
310 const int* args);
312 public:
313 struct MInstrState {
314 TypedValue tvScratch;
315 TypedValue tvLiteral;
316 TypedValue tvRef;
317 TypedValue tvRef2;
318 TypedValue tvResult;
319 TypedValue tvVal;
320 bool baseStrOff;
321 Class* ctx;
322 } __attribute__((aligned(16)));
323 private:
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,
352 PhysReg rBase,
353 const DynLocation& keyLoc,
354 Location outLoc,
355 void* fallbackFunc);
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,
383 PhysReg rBase);
384 template <bool useEmpty>
385 void emitIssetEmptyElem(const Tracelet& t, const NormalizedInstruction& ni,
386 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
387 PhysReg rBase);
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,
394 PhysReg rBase);
395 void emitSetNewElem(const Tracelet& t, const NormalizedInstruction& ni,
396 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
397 PhysReg rBase);
398 void emitSetOpNewElem(const Tracelet& t, const NormalizedInstruction& ni,
399 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
400 PhysReg rBase);
401 void emitIncDecNewElem(const Tracelet& t, const NormalizedInstruction& ni,
402 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
403 PhysReg rBase);
404 void emitBindNewElem(const Tracelet& t, const NormalizedInstruction& ni,
405 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
406 PhysReg rBase);
407 void emitNotSuppNewElem(const Tracelet& t, const NormalizedInstruction& ni,
408 const MInstrInfo& mii, unsigned mInd, unsigned iInd,
409 PhysReg rBase);
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, \
419 PhysReg rBase); \
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);
428 MINSTRS
429 #undef MII
431 #define INSTRS \
432 CASE(PopC) \
433 CASE(PopV) \
434 CASE(PopR) \
435 CASE(UnboxR) \
436 CASE(Null) \
437 CASE(True) \
438 CASE(False) \
439 CASE(Int) \
440 CASE(String) \
441 CASE(Array) \
442 CASE(NewArray) \
443 CASE(Nop) \
444 CASE(AddElemC) \
445 CASE(AddNewElemC) \
446 CASE(Cns) \
447 CASE(DefCns) \
448 CASE(ClsCnsD) \
449 CASE(Concat) \
450 CASE(Add) \
451 CASE(Xor) \
452 CASE(Not) \
453 CASE(BitNot) \
454 CASE(CastInt) \
455 CASE(CastString) \
456 CASE(Print) \
457 CASE(Jmp) \
458 CASE(Switch) \
459 CASE(RetC) \
460 CASE(RetV) \
461 CASE(NativeImpl) \
462 CASE(AGetC) \
463 CASE(AGetL) \
464 CASE(CGetL) \
465 CASE(CGetL2) \
466 CASE(CGetS) \
467 CASE(CGetM) \
468 CASE(CGetG) \
469 CASE(VGetL) \
470 CASE(VGetG) \
471 CASE(VGetM) \
472 CASE(IssetM) \
473 CASE(EmptyM) \
474 CASE(AKExists) \
475 CASE(SetS) \
476 CASE(SetG) \
477 CASE(SetM) \
478 CASE(SetOpL) \
479 CASE(SetOpM) \
480 CASE(IncDecL) \
481 CASE(IncDecM) \
482 CASE(UnsetL) \
483 CASE(UnsetM) \
484 CASE(BindM) \
485 CASE(FPushFuncD) \
486 CASE(FPushFunc) \
487 CASE(FPushClsMethodD) \
488 CASE(FPushClsMethodF) \
489 CASE(FPushObjMethodD) \
490 CASE(FPushCtor) \
491 CASE(FPushCtorD) \
492 CASE(FPushContFunc) \
493 CASE(FPassR) \
494 CASE(FPassL) \
495 CASE(FPassM) \
496 CASE(FPassS) \
497 CASE(FPassG) \
498 CASE(This) \
499 CASE(CheckThis) \
500 CASE(InitThisLoc) \
501 CASE(FCall) \
502 CASE(FCallArray) \
503 CASE(VerifyParamType) \
504 CASE(InstanceOfD) \
505 CASE(StaticLocInit) \
506 CASE(IterInit) \
507 CASE(IterValueC) \
508 CASE(IterKey) \
509 CASE(IterNext) \
510 CASE(ReqDoc) \
511 CASE(ReqMod) \
512 CASE(ReqSrc) \
513 CASE(DefCls) \
514 CASE(DefFunc) \
515 CASE(Self) \
516 CASE(Parent) \
517 CASE(ClassExists) \
518 CASE(InterfaceExists) \
519 CASE(TraitExists) \
520 CASE(Dup) \
521 CASE(CreateCont) \
522 CASE(UnpackCont) \
523 CASE(PackCont) \
524 CASE(ContReceive) \
525 CASE(ContRaised) \
526 CASE(ContDone) \
527 CASE(ContNext) \
528 CASE(ContSend) \
529 CASE(ContRaise) \
530 CASE(ContValid) \
531 CASE(ContCurrent) \
532 CASE(ContStopped) \
533 CASE(ContHandle)
535 // These are instruction-like functions which cover more than one
536 // opcode.
537 #define PSEUDOINSTRS \
538 CASE(BinaryArithOp) \
539 CASE(SameOp) \
540 CASE(EqOp) \
541 CASE(LtGtOp) \
542 CASE(UnaryBooleanOp) \
543 CASE(BranchOp) \
544 CASE(AssignToLocalOp) \
545 CASE(FPushCufOp) \
546 CASE(FPassCOp) \
547 CASE(CheckTypeOp)
549 #define PAIR(nm) \
550 void analyze ## nm(Tracelet& t, NormalizedInstruction& i); \
551 void translate ## nm(const Tracelet& t, const NormalizedInstruction& i);
552 #define CASE PAIR
554 INSTRS
555 PSEUDOINSTRS
557 #undef CASE
558 #undef PAIR
561 void branchWithFlagsSet(const Tracelet& t, const NormalizedInstruction& i,
562 ConditionCode cc);
563 void fuseBranchSync(const Tracelet& t, const NormalizedInstruction& i);
564 void fuseBranchAfterBool(const Tracelet& t, const NormalizedInstruction& i,
565 ConditionCode cc);
566 void fuseBranchAfterStaticBool(const Tracelet& t,
567 const NormalizedInstruction& i,
568 bool resultIsTrue);
569 void translateSetMArray(const Tracelet &t, const NormalizedInstruction& i);
570 void emitPropGet(const NormalizedInstruction& i,
571 const DynLocation& base,
572 PhysReg fieldAddr,
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,
578 bool allowCreate);
579 void emitArrayElem(const NormalizedInstruction& i,
580 const DynLocation* baseInput,
581 PhysReg baseReg,
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);
595 public:
596 template<typename T>
597 void invalidateSrcKeys(const T& keys) {
598 BlockingLeaseHolder writer(s_writeLease);
599 ASSERT(writer);
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() {
633 return m_callToExit;
636 TCA getRetFromInterpretedFrame() {
637 return m_retHelper;
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
643 // professional.
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);
654 private:
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,
662 bool writeType);
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);
668 public:
669 void analyzeInstr(Tracelet& t, NormalizedInstruction& i);
670 bool acquireWriteLease(bool blocking) {
671 return s_writeLease.acquire(blocking);
673 void dropWriteLease() {
674 s_writeLease.drop();
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,
683 TCA &sideExit);
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; }
691 private:
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,
702 const TCA start,
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,
710 SrcRec& fail);
711 void irCheckType(Asm&, const Location& l, const RuntimeType& rtt,
712 SrcRec& fail);
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,
738 bool align,
739 TCA toSmash);
740 TCA bindJmp(TCA toSmash, SrcKey dest, ServiceRequest req);
741 TCA bindJmpccFirst(TCA toSmash,
742 Offset offTrue, Offset offFalse,
743 bool toTake,
744 ConditionCode cc);
745 TCA bindJmpccSecond(TCA toSmash, const Offset off,
746 ConditionCode cc);
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*,
751 PhysReg = reg::r13,
752 PhysReg = reg::r14,
753 PhysReg = reg::rax);
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,
765 ConditionCode cc);
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,
772 const Asm& a,
773 const TCA start,
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,
782 Offset stackOff);
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,
788 DataType t);
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,
795 ServiceRequest req);
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,
802 SrcKey srcKey,
803 const Func* funcd,
804 int numArgs,
805 bool isImmutable);
806 void emitIncCounter(TCA start, int cntOfs);
808 void analyzeReqLit(Tracelet& t, NormalizedInstruction& i,
809 InclOpFlags flags);
810 void translateReqLit(const Tracelet& t, const NormalizedInstruction& i,
811 InclOpFlags flags);
812 struct ReqLitStaticArgs {
813 HPHP::Eval::PhpFile* m_efile;
814 TCA m_pseudoMain;
815 Offset m_pcOff;
816 bool m_local;
818 static void reqLitHelper(const ReqLitStaticArgs* args);
819 struct FCallArrayArgs {
820 Offset m_pcOff;
821 Offset m_pcNext;
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);
831 public:
832 void resume(SrcKey sk);
834 TCA translate(const SrcKey *sk, bool align, bool useHHIR);
836 TranslatorX64();
837 virtual ~TranslatorX64();
839 void initGdb();
840 static TranslatorX64* Get();
842 // Called before entering a new PHP "world."
843 void requestInit();
845 // Called at the end of eval()
846 void requestExit();
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
867 bool dumpTCData();
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
874 // a new space.
875 bool replace();
877 // Debugging interfaces to prevent tampering with code.
878 void protectCode();
879 void unprotectCode();
881 private:
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
895 INSTRS
896 PSEUDOINSTRS
898 #undef CASE
899 #undef 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,
908 InclOpFlags flags);
913 * RAII bookmark for temporarily rewinding a.code.frontier.
915 class CodeCursor {
916 typedef X64Assembler Asm;
917 Asm& m_a;
918 TCA m_oldFrontier;
919 public:
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);
927 ~CodeCursor() {
928 ASSERT(TranslatorX64::canWrite());
929 m_a.code.frontier = m_oldFrontier;
930 TRACE_MOD(Trace::trans, 1, "Restore: %p\n",
931 m_a.code.frontier);
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
940 // trampoline
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,
953 ActRec* prevAr);
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,
960 int propInput,
961 int objInput);
962 bool isContextFixed();
963 int getNormalPropertyOffset(const NormalizedInstruction& i,
964 const MInstrInfo&,
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 {
979 const char *m_name;
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)
986 ~SpaceRecorder() {
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
1003 } } }
1005 #endif