• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H
17 #define ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H
18 
19 #include "ecmascript/compiler/assembler/x64/assembler_x64.h"
20 #include "ecmascript/compiler/assembler/x64/extended_assembler_x64.h"
21 #include "ecmascript/frames.h"
22 
23 namespace panda::ecmascript::x64 {
24 
25 enum class FrameTransitionType : uint8_t {
26     BASELINE_TO_OTHER,
27     BASELINE_TO_BASELINE_CHECK,
28     OTHER_TO_BASELINE_CHECK,
29     OTHER_TO_OTHER
30 };
31 
32 class CommonCall {
33 public:
34     static constexpr int FRAME_SLOT_SIZE = 8;
35     static constexpr int DOUBLE_SLOT_SIZE = 16;
36     static constexpr int TRIPLE_SLOT_SIZE = 24;
37     static constexpr int QUADRUPLE_SLOT_SIZE = 32;
38     static constexpr int QUINTUPLE_SLOT_SIZE = 40;
39     static constexpr int SEXTUPLE_SLOT_SIZE = 48;
40     static void CopyArgumentWithArgV(ExtendedAssembler *assembler, Register argc, Register argV);
41     static void PushAsmInterpBridgeFrame(ExtendedAssembler *assembler);
42     static void PopAsmInterpBridgeFrame(ExtendedAssembler *assembler);
43     static void PushUndefinedWithArgc(ExtendedAssembler *assembler, Register argc);
44     static void GetArgvAtStack(ExtendedAssembler *assembler);
45     static void PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc, Register argv,
46         Register op1, Register op2, Label *stackOverflow);
47     static void StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
48         Register op2, Label *stackOverflow);
49 };
50 
51 class OptimizedCall : public CommonCall {
52 public:
53     static void CallRuntime(ExtendedAssembler *assembler);
54 
55     static void JSFunctionEntry(ExtendedAssembler *assembler);
56 
57     static void OptimizedCallAndPushArgv(ExtendedAssembler *assembler);
58 
59     static void JSProxyCallInternalWithArgV(ExtendedAssembler *assembler);
60 
61     static void JSCall(ExtendedAssembler *assembler);
62 
63     static void CallOptimized(ExtendedAssembler *assembler);
64 
65     static void CallRuntimeWithArgv(ExtendedAssembler *assembler);
66 
67     static void JSCallWithArgV(ExtendedAssembler *assembler);
68 
69     static void JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler);
70 
71     static void SuperCallWithArgV(ExtendedAssembler *assembler);
72 
73     static void AOTCallToAsmInterBridge(ExtendedAssembler *assembler);
74 
75     static void FastCallToAsmInterBridge(ExtendedAssembler *assembler);
76 
77     static void DeoptHandlerAsm(ExtendedAssembler *assembler);
78 
79     static void JSCallNew(ExtendedAssembler *assembler);
80 
81     static void GenJSCall(ExtendedAssembler *assembler, bool isNew);
82 
83     static void GenJSCallWithArgV(ExtendedAssembler *assembler, int id);
84 private:
85     static void DeoptEnterAsmInterp(ExtendedAssembler *assembler);
86     static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
87                             Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall);
88     static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg);
89     static void JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall);
90     static void OptimizedCallAsmInterpreter(ExtendedAssembler *assembler);
91     static void PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc,
92                                  Register actualNumArgs, Register argV, Label *pushCallThis);
93     static void PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
94                                     Register thisObj, Register newTarget);
95     static void PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs);
96     static void PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp);
97     static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue);
98     static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp);
99     static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler);
100     static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
101     static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp);
102     static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
103     static void CallBuiltinConstructorStub(ExtendedAssembler *assembler, Register builtinStub, Register argv,
104                                            Register glue, Register temp);
105     static void RemoveArgv(ExtendedAssembler *assembler, Register temp);
106 
107     friend class OptimizedFastCall;
108 };
109 
110 class OptimizedFastCall : public CommonCall {
111 public:
112     static void OptimizedFastCallEntry(ExtendedAssembler *assembler);
113 
114     static void OptimizedFastCallAndPushArgv(ExtendedAssembler *assembler);
115 
116     static void JSFastCallWithArgV(ExtendedAssembler *assembler);
117 
118     static void JSFastCallWithArgVAndPushArgv(ExtendedAssembler *assembler);
119 };
120 
121 class AsmInterpreterCall : public CommonCall {
122 public:
123     static void GeneratorReEnterAsmInterp(ExtendedAssembler *assembler);
124 
125     static void GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler);
126 
127     static void AsmInterpEntryDispatch(ExtendedAssembler *assembler);
128 
129     static void AsmInterpreterEntry(ExtendedAssembler *assembler);
130 
131     static void PushCallThisRangeAndDispatch(ExtendedAssembler *assembler);
132 
133     static void PushCallRangeAndDispatch(ExtendedAssembler *assembler);
134 
135     static void PushCallArgs3AndDispatch(ExtendedAssembler *assembler);
136 
137     static void PushCallArgs2AndDispatch(ExtendedAssembler *assembler);
138 
139     static void PushCallArg1AndDispatch(ExtendedAssembler *assembler);
140 
141     static void PushCallArg0AndDispatch(ExtendedAssembler *assembler);
142 
143     static void PushCallThisArg0AndDispatch(ExtendedAssembler *assembler);
144 
145     static void PushCallThisArg1AndDispatch(ExtendedAssembler *assembler);
146 
147     static void PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler);
148 
149     static void PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler);
150 
151     static void PushCallNewAndDispatch(ExtendedAssembler *assembler);
152 
153     static void PushSuperCallAndDispatch(ExtendedAssembler *assembler);
154 
155     static void PushCallNewAndDispatchNative(ExtendedAssembler *assembler);
156 
157     static void PushNewTargetAndDispatchNative(ExtendedAssembler *assembler);
158 
159     static void PushCallRangeAndDispatchNative(ExtendedAssembler *assembler);
160 
161     static void PushCallArgsAndDispatchNative(ExtendedAssembler *assembler);
162 
163     static void ResumeRspAndDispatch(ExtendedAssembler *assembler);
164 
165     static void ResumeRspAndReturn([[maybe_unused]] ExtendedAssembler *assembler);
166 
167     static void ResumeRspAndReturnBaseline([[maybe_unused]] ExtendedAssembler *assembler);
168 
169     static void CallGetter(ExtendedAssembler *assembler);
170 
171     static void CallSetter(ExtendedAssembler *assembler);
172 
173     static void CallContainersArgs2(ExtendedAssembler *assembler);
174 
175     static void CallContainersArgs3(ExtendedAssembler *assembler);
176 
177     static void CallReturnWithArgv(ExtendedAssembler *assembler);
178 
179     static void ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler);
180 
181     static void ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler);
182 
183     static void ResumeRspAndRollback(ExtendedAssembler *assembler);
184 
185     static void ASMFastWriteBarrier(ExtendedAssembler *assembler);
186 
187     static void ASMWriteBarrierWithEden(ExtendedAssembler *assembler);
188 private:
189     static void PushFrameState(ExtendedAssembler *assembler, Register prevSpRegister, Register fpRegister,
190         Register callTargetRegister, Register thisRegister, Register methodRegister, Register pcRegister,
191         Register operatorRegister);
192     static void PushGeneratorFrameState(ExtendedAssembler *assembler, Register prevSpRegister,
193         Register fpRegister, Register callTargetRegister, Register thisRegister, Register methodRegister,
194         Register contextRegister, Register pcRegister, Register operatorRegister);
195     static void PushAsmInterpEntryFrame(ExtendedAssembler *assembler);
196     static void PopAsmInterpEntryFrame(ExtendedAssembler *assembler);
197     static void GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
198         Register declaredNumArgsRegister);
199     static void GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callFieldRegister,
200         Register numVregsRegister);
201     static void PushUndefinedWithArgcAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
202         Register op1, Register op2, Label *stackOverflow);
203     static void ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue, Register fp,
204         Register op);
205     static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister);
206     static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode,
207                              Label *stackOverflow, FrameTransitionType type);
208     static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
209     static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
210     static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type);
211     static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister,
212                              Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid);
213     static void CallNativeEntry(ExtendedAssembler *assemblSer);
214     static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false);
215     static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode);
216     static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type);
217     static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode, FrameTransitionType type);
218     static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow);
219     static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
220         Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow);
221     static void PreserveMostCall(ExtendedAssembler* assembler);
222     friend class OptimizedCall;
223     friend class BaselineCall;
224 };
225 
226 class BaselineCall : public CommonCall {
227 public:
228     /* other call baseline: need to check whether baseline code exists */
229     static void CallArg0AndCheckToBaseline(ExtendedAssembler *assembler);
230     static void CallArg1AndCheckToBaseline(ExtendedAssembler *assembler);
231     static void CallArgs2AndCheckToBaseline(ExtendedAssembler *assembler);
232     static void CallArgs3AndCheckToBaseline(ExtendedAssembler *assembler);
233     static void CallThisArg0AndCheckToBaseline(ExtendedAssembler *assembler);
234     static void CallThisArg1AndCheckToBaseline(ExtendedAssembler *assembler);
235     static void CallThisArgs2AndCheckToBaseline(ExtendedAssembler *assembler);
236     static void CallThisArgs3AndCheckToBaseline(ExtendedAssembler *assembler);
237     static void CallRangeAndCheckToBaseline(ExtendedAssembler *assembler);
238     static void CallNewAndCheckToBaseline(ExtendedAssembler *assembler);
239     static void SuperCallAndCheckToBaseline(ExtendedAssembler *assembler);
240     static void CallThisRangeAndCheckToBaseline(ExtendedAssembler *assembler);
241     /* baseline call other: need to save fp and lr */
242     static void CallArg0AndDispatchFromBaseline(ExtendedAssembler *assembler);
243     static void CallArg1AndDispatchFromBaseline(ExtendedAssembler *assembler);
244     static void CallArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler);
245     static void CallArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler);
246     static void CallThisArg0AndDispatchFromBaseline(ExtendedAssembler *assembler);
247     static void CallThisArg1AndDispatchFromBaseline(ExtendedAssembler *assembler);
248     static void CallThisArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler);
249     static void CallThisArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler);
250     static void CallRangeAndDispatchFromBaseline(ExtendedAssembler *assembler);
251     static void CallNewAndDispatchFromBaseline(ExtendedAssembler *assembler);
252     static void SuperCallAndDispatchFromBaseline(ExtendedAssembler *assembler);
253     static void CallThisRangeAndDispatchFromBaseline(ExtendedAssembler *assembler);
254     /* baseline call baseline: need to check whether baseline code exists and save fp and lr */
255     static void CallArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
256     static void CallArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
257     static void CallArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
258     static void CallArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
259     static void CallThisArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
260     static void CallThisArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
261     static void CallThisArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
262     static void CallThisArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
263     static void CallRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
264     static void CallNewAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
265     static void SuperCallAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
266     static void CallThisRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
267     /* get baselineBuiltinFp when baselineBuiltin call the others */
268     static void GetBaselineBuiltinFp(ExtendedAssembler *assembler);
269 };
270 
271 class JsFunctionArgsConfigFrameScope {
272 public:
273     static constexpr int FRAME_SLOT_SIZE = 8;
JsFunctionArgsConfigFrameScope(ExtendedAssembler * assembler)274     explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler)
275     {
276         assembler_->Pushq(rbp);
277         assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
278         // 2: skip jsFunc and frameType
279         assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
280         // callee save
281         assembler_->Pushq(r12);
282         assembler_->Pushq(r13);
283         assembler_->Pushq(r14);
284         assembler_->Pushq(rbx);
285         assembler_->Pushq(rax);
286     }
~JsFunctionArgsConfigFrameScope()287     ~JsFunctionArgsConfigFrameScope()
288     {
289         assembler_->Movq(rbp, rsp);
290         assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx
291         assembler_->Popq(rbx);
292         assembler_->Popq(r14);
293         assembler_->Popq(r13);
294         assembler_->Popq(r12);
295         assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type
296         assembler_->Pop(rbp);
297         assembler_->Ret();
298     }
299     NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope);
300     NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope);
301 private:
302     ExtendedAssembler *assembler_;
303 };
304 
305 class OptimizedUnfoldArgVFrameFrameScope {
306 public:
307     static constexpr int FRAME_SLOT_SIZE = 8;
OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler * assembler)308     explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler)
309     {
310         assembler_->Pushq(rbp);
311         // construct frame
312         assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
313         assembler_->Pushq(assembler_->AvailableRegister2());
314         // 2: skip callSiteSp and frameType
315         assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
316         assembler_->Pushq(rbx);
317         assembler_->Pushq(r12); // callee save
318     }
~OptimizedUnfoldArgVFrameFrameScope()319     ~OptimizedUnfoldArgVFrameFrameScope()
320     {
321         assembler_->Movq(rbp, rsp);
322         assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx
323         assembler_->Popq(r12);
324         assembler_->Popq(rbx);
325         assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp
326         assembler_->Popq(rbp);
327         assembler_->Ret();
328     }
329     NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope);
330     NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope);
331 private:
332     ExtendedAssembler *assembler_;
333 };
334 
335 class OptimizedUnfoldArgVFrameFrame1Scope {
336 public:
337     static constexpr int FRAME_SLOT_SIZE = 8;
OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler * assembler)338     explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler)
339     {
340         assembler_->Pushq(rbp);
341         // construct frame
342         assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
343         assembler_->Pushq(assembler_->AvailableRegister2());
344         // 2: skip callSiteSp and frameType
345         assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
346         assembler_->Pushq(rbx);
347         assembler_->Pushq(r12); // callee save
348         assembler_->Pushq(r13);
349         assembler_->Pushq(r14); // callee save
350     }
~OptimizedUnfoldArgVFrameFrame1Scope()351     ~OptimizedUnfoldArgVFrameFrame1Scope()
352     {
353         assembler_->Movq(rbp, rsp);
354         assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx
355         assembler_->Popq(r14);
356         assembler_->Popq(r13);
357         assembler_->Popq(r12);
358         assembler_->Popq(rbx);
359         assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp
360         assembler_->Popq(rbp);
361         assembler_->Ret();
362     }
363     NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope);
364     NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope);
365 private:
366     ExtendedAssembler *assembler_;
367 };
368 }  // namespace panda::ecmascript::x64
369 #endif  // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H
370