2 +----------------------------------------------------------------------+
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
{
32 void emitCallToExit(UniqueStubs
& us
) {
33 MacroAssembler a
{ mcg
->code
.main() };
36 us
.callToExit
= a
.frontier();
38 us
.add("callToExit", us
.callToExit
);
41 void emitReturnHelpers(UniqueStubs
& us
) {
42 MacroAssembler a
{ mcg
->code
.main() };
44 us
.retHelper
= a
.frontier();
47 us
.retInlHelper
= a
.frontier();
50 us
.genRetHelper
= a
.frontier();
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();
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();
78 us
.add("stackOverflowHelper", us
.stackOverflowHelper
);
81 void emitFreeLocalsHelpers(UniqueStubs
& us
) {
82 MacroAssembler a
{ mcg
->code
.main() };
84 us
.freeManyLocalsHelper
= a
.frontier();
87 us
.add("freeManyLocalsHelper", us
.freeManyLocalsHelper
);
90 void emitFuncPrologueRedispatch(UniqueStubs
& us
) {
91 MacroAssembler a
{ mcg
->code
.main() };
96 us
.add("funcPrologueRedispatch", us
.funcPrologueRedispatch
);
99 void emitFCallArrayHelper(UniqueStubs
& us
) {
100 MacroAssembler a
{ mcg
->code
.main() };
102 us
.fcallArrayHelper
= a
.frontier();
105 us
.add("fcallArrayHelper", us
.fcallArrayHelper
);
108 void emitFCallHelperThunk(UniqueStubs
& us
) {
109 MacroAssembler a
{ mcg
->code
.main() };
110 us
.fcallHelperThunk
= a
.frontier();
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
);
125 a
. Pop (rVmFp
, rLinkReg
);
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();
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
));
151 a
. Cbz (rReturnReg
, &skip
);
152 a
. Mov (vixl::sp
, rVmFp
);
153 a
. Pop (rVmFp
, rLinkReg
);
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
]);
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();
176 uniqueStubs
.bindCallStub
= cb
.frontier();
178 uniqueStubs
.immutableBindCallStub
= cb
.frontier();
182 uniqueStubs
.add("bindCallStub", uniqueStubs
.bindCallStub
);
183 uniqueStubs
.add("immutableBindCallStub", uniqueStubs
.immutableBindCallStub
);
186 } // anonymous namespace
188 UniqueStubs
emitUniqueStubs() {
194 emitStackOverflowHelper
,
195 emitFreeLocalsHelpers
,
196 emitFuncPrologueRedispatch
,
197 emitFCallArrayHelper
,
198 emitFCallHelperThunk
,
199 emitFuncBodyHelperThunk
,
200 emitFunctionEnterHelper
,
203 for (auto& f
: functions
) f(us
);