Switch-related cleanup
[hiphop-php.git] / hphp / runtime / vm / jit / unique-stubs-arm.cpp
blob314745c85aa467617076dc16bb28a754b4ec209a
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-2014 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 #include "hphp/util/data-block.h"
18 #include "hphp/runtime/vm/event-hook.h"
19 #include "hphp/runtime/vm/jit/abi-arm.h"
20 #include "hphp/runtime/vm/jit/code-gen-helpers-arm.h"
21 #include "hphp/runtime/vm/jit/unique-stubs.h"
22 #include "hphp/runtime/vm/jit/mc-generator.h"
23 #include "hphp/runtime/vm/jit/service-requests-inline.h"
24 #include "hphp/vixl/a64/macro-assembler-a64.h"
26 namespace HPHP { namespace jit { namespace arm {
28 namespace {
30 using namespace vixl;
32 void emitCallToExit(UniqueStubs& us) {
33 MacroAssembler a { mcg->code.main() };
35 a. Nop ();
36 us.callToExit = a.frontier();
37 a. Br (rLinkReg);
38 us.add("callToExit", us.callToExit);
41 void emitReturnHelpers(UniqueStubs& us) {
42 MacroAssembler a { mcg->code.main() };
44 us.retHelper = a.frontier();
45 a. Brk (0);
47 us.retInlHelper = a.frontier();
48 a. Brk (0);
50 us.genRetHelper = a.frontier();
51 a. Brk (0);
53 us.add("retHelper", us.retHelper);
54 us.add("genRetHelper", us.genRetHelper);
55 us.add("retInlHelper", us.retInlHelper);
58 void emitResumeHelpers(UniqueStubs& us) {
59 MacroAssembler a { mcg->code.main() };
61 us.resumeHelperRet = a.frontier();
62 a. Brk (0);
64 not_implemented();
66 us.add("resumeHelper", us.resumeHelper);
67 us.add("resumeHelperRet", us.resumeHelperRet);
70 void emitStackOverflowHelper(UniqueStubs& us) {
71 MacroAssembler a { mcg->code.cold() };
73 us.stackOverflowHelper = a.frontier();
74 a. Brk (0);
76 not_implemented();
78 us.add("stackOverflowHelper", us.stackOverflowHelper);
81 void emitFreeLocalsHelpers(UniqueStubs& us) {
82 MacroAssembler a { mcg->code.main() };
84 us.freeManyLocalsHelper = a.frontier();
85 a. Brk (0);
87 us.add("freeManyLocalsHelper", us.freeManyLocalsHelper);
90 void emitFuncPrologueRedispatch(UniqueStubs& us) {
91 MacroAssembler a { mcg->code.main() };
93 a. Brk (0);
94 not_implemented();
96 us.add("funcPrologueRedispatch", us.funcPrologueRedispatch);
99 void emitFCallArrayHelper(UniqueStubs& us) {
100 MacroAssembler a { mcg->code.main() };
102 us.fcallArrayHelper = a.frontier();
103 a. Brk (0);
105 us.add("fcallArrayHelper", us.fcallArrayHelper);
108 void emitFCallHelperThunk(UniqueStubs& us) {
109 MacroAssembler a { mcg->code.main() };
110 us.fcallHelperThunk = a.frontier();
111 a. Brk (0);
112 us.add("fcallHelperThunk", us.fcallHelperThunk);
115 void emitFuncBodyHelperThunk(UniqueStubs& us) {
116 TCA (*helper)(ActRec*) = &funcBodyHelper;
117 MacroAssembler a { mcg->code.main() };
119 us.funcBodyHelperThunk = a.frontier();
120 a. Mov (argReg(0), rVmFp);
121 a. Mov (argReg(1), rVmSp);
122 a. Mov (rHostCallReg, reinterpret_cast<intptr_t>(helper));
123 a. Push (rLinkReg, rVmFp);
124 a. HostCall(2);
125 a. Pop (rVmFp, rLinkReg);
126 a. Br (rReturnReg);
128 us.add("funcBodyHelperThunk", us.funcBodyHelperThunk);
131 void emitFunctionEnterHelper(UniqueStubs& us) {
132 bool (*helper)(const ActRec*, int) = &EventHook::onFunctionCall;
133 MacroAssembler a { mcg->code.main() };
135 us.functionEnterHelper = a.frontier();
137 vixl::Label skip;
139 auto ar = argReg(0);
141 a. Push (rLinkReg, rVmFp);
142 a. Mov (rVmFp, vixl::sp);
143 // rAsm2 gets the savedRbp, rAsm gets the savedRip.
144 a. Ldp (rAsm2, rAsm, ar[AROFF(m_sfp)]);
145 static_assert(AROFF(m_sfp) + 8 == AROFF(m_savedRip),
146 "m_sfp must precede m_savedRip");
147 a. Push (rAsm, rAsm2);
148 a. Mov (argReg(1), EventHook::NormalFunc);
149 a. Mov (rHostCallReg, reinterpret_cast<intptr_t>(helper));
150 a. HostCall(2);
151 a. Cbz (rReturnReg, &skip);
152 a. Mov (vixl::sp, rVmFp);
153 a. Pop (rVmFp, rLinkReg);
154 a. Ret (rLinkReg);
156 a. bind (&skip);
158 // Tricky. The last two things we pushed were the saved fp and return TCA from
159 // the function we were supposed to enter. Since we're now "returning" from
160 // that function, restore that fp and jump to that return TCA. Below that on
161 // the stack are that function's *caller's* saved fp and return TCA. We can
162 // ignore the saved fp, but we have to restore the return TCA into x30.
163 auto rIgnored = rAsm2;
164 a. Pop (rVmFp, rAsm);
165 a. Pop (rIgnored, rLinkReg);
166 a. Ldr (rVmSp, rVmTl[rds::kVmspOff]);
167 a. Br (rAsm);
169 us.add("functionEnterHelper", us.functionEnterHelper);
172 void emitBindCallStubs(UniqueStubs& uniqueStubs) {
173 for (int i = 0; i < 2; i++) {
174 auto& cb = mcg->code.cold();
175 if (!i) {
176 uniqueStubs.bindCallStub = cb.frontier();
177 } else {
178 uniqueStubs.immutableBindCallStub = cb.frontier();
180 not_implemented();
182 uniqueStubs.add("bindCallStub", uniqueStubs.bindCallStub);
183 uniqueStubs.add("immutableBindCallStub", uniqueStubs.immutableBindCallStub);
186 } // anonymous namespace
188 UniqueStubs emitUniqueStubs() {
189 UniqueStubs us;
190 auto functions = {
191 emitCallToExit,
192 emitReturnHelpers,
193 emitResumeHelpers,
194 emitStackOverflowHelper,
195 emitFreeLocalsHelpers,
196 emitFuncPrologueRedispatch,
197 emitFCallArrayHelper,
198 emitFCallHelperThunk,
199 emitFuncBodyHelperThunk,
200 emitFunctionEnterHelper,
201 emitBindCallStubs,
203 for (auto& f : functions) f(us);
204 return us;