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
23namespace panda::ecmascript::x64 {
24
25enum class FrameTransitionType : uint8_t {
26    BASELINE_TO_OTHER,
27    BASELINE_TO_BASELINE_CHECK,
28    OTHER_TO_BASELINE_CHECK,
29    OTHER_TO_OTHER
30};
31
32class CommonCall {
33public:
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    static void PushAsmBridgeFrame(ExtendedAssembler *assembler);
50    static void PopAsmBridgeFrame(ExtendedAssembler *assembler);
51};
52
53class OptimizedCall : public CommonCall {
54public:
55    static void CallRuntime(ExtendedAssembler *assembler);
56
57    static void JSFunctionEntry(ExtendedAssembler *assembler);
58
59    static void OptimizedCallAndPushArgv(ExtendedAssembler *assembler);
60
61    static void JSProxyCallInternalWithArgV(ExtendedAssembler *assembler);
62
63    static void JSCall(ExtendedAssembler *assembler);
64
65    static void CallOptimized(ExtendedAssembler *assembler);
66
67    static void CallRuntimeWithArgv(ExtendedAssembler *assembler);
68
69    static void JSCallWithArgV(ExtendedAssembler *assembler);
70
71    static void JSCallWithArgVAndPushArgv(ExtendedAssembler *assembler);
72
73    static void SuperCallWithArgV(ExtendedAssembler *assembler);
74
75    static void AOTCallToAsmInterBridge(ExtendedAssembler *assembler);
76
77    static void FastCallToAsmInterBridge(ExtendedAssembler *assembler);
78
79    static void DeoptHandlerAsm(ExtendedAssembler *assembler);
80
81    static void JSCallNew(ExtendedAssembler *assembler);
82
83    static void GenJSCall(ExtendedAssembler *assembler, bool isNew);
84
85    static void GenJSCallWithArgV(ExtendedAssembler *assembler, int id);
86private:
87    static void DeoptEnterAsmInterp(ExtendedAssembler *assembler);
88    static void JSCallCheck(ExtendedAssembler *assembler, Register jsFuncReg,
89                            Label *lNonCallable, Label *lNotJSFunction, Label *lJSFunctionCall);
90    static void ThrowNonCallableInternal(ExtendedAssembler *assembler, Register glueReg);
91    static void JSBoundFunctionCallInternal(ExtendedAssembler *assembler, Register jsFuncReg, Label *jsCall);
92    static void OptimizedCallAsmInterpreter(ExtendedAssembler *assembler);
93    static void PushArgsWithArgV(ExtendedAssembler *assembler, Register jsfunc,
94                                 Register actualNumArgs, Register argV, Label *pushCallThis);
95    static void PushMandatoryJSArgs(ExtendedAssembler *assembler, Register jsfunc,
96                                    Register thisObj, Register newTarget);
97    static void PopJSFunctionArgs(ExtendedAssembler *assembler, Register expectedNumArgs);
98    static void PushJSFunctionEntryFrame(ExtendedAssembler *assembler, Register prevFp);
99    static void PopJSFunctionEntryFrame(ExtendedAssembler *assembler, Register glue);
100    static void PushOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler, Register callSiteSp);
101    static void PopOptimizedUnfoldArgVFrame(ExtendedAssembler *assembler);
102    static void CallBuiltinTrampoline(ExtendedAssembler *assembler, Register temp);
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
110class OptimizedFastCall : public CommonCall {
111public:
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
121class AsmInterpreterCall : public CommonCall {
122public:
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);
188private:
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 ThrowStackOverflowExceptionAndReturnToAotFrame(ExtendedAssembler *assembler, Register glue,
206        Register fp, Register op);
207    static void HasPendingException(ExtendedAssembler *assembler, Register threadRegister);
208    static void PushCallThis(ExtendedAssembler *assembler, JSCallMode mode,
209                             Label *stackOverflow, FrameTransitionType type);
210    static Register GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
211    static Register GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister);
212    static void PushVregs(ExtendedAssembler *assembler, Label *stackOverflow, FrameTransitionType type);
213    static void DispatchCall(ExtendedAssembler *assembler, Register pcRegister, Register newSpRegister,
214                             Register callTargetRegister, Register methodRegister, Register accRegister = rInvalid);
215    static void CallNativeEntry(ExtendedAssembler *assembler);
216    static void CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin);
217    static void CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget = false);
218    static void CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode);
219    static bool PushBuiltinFrame(ExtendedAssembler *assembler, Register glue, FrameType type);
220    static void JSCallCommonEntry(ExtendedAssembler *assembler, JSCallMode mode, FrameTransitionType type);
221    static void JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *stackOverflow);
222    static void JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
223        Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow);
224    static void PreserveMostCall(ExtendedAssembler* assembler);
225    static void ASMFastSharedWriteBarrier(ExtendedAssembler *assembler, Label &needcall);
226    friend class OptimizedCall;
227    friend class BaselineCall;
228};
229
230class BaselineCall : public CommonCall {
231public:
232    /* other call baseline: need to check whether baseline code exists */
233    static void CallArg0AndCheckToBaseline(ExtendedAssembler *assembler);
234    static void CallArg1AndCheckToBaseline(ExtendedAssembler *assembler);
235    static void CallArgs2AndCheckToBaseline(ExtendedAssembler *assembler);
236    static void CallArgs3AndCheckToBaseline(ExtendedAssembler *assembler);
237    static void CallThisArg0AndCheckToBaseline(ExtendedAssembler *assembler);
238    static void CallThisArg1AndCheckToBaseline(ExtendedAssembler *assembler);
239    static void CallThisArgs2AndCheckToBaseline(ExtendedAssembler *assembler);
240    static void CallThisArgs3AndCheckToBaseline(ExtendedAssembler *assembler);
241    static void CallRangeAndCheckToBaseline(ExtendedAssembler *assembler);
242    static void CallNewAndCheckToBaseline(ExtendedAssembler *assembler);
243    static void SuperCallAndCheckToBaseline(ExtendedAssembler *assembler);
244    static void CallThisRangeAndCheckToBaseline(ExtendedAssembler *assembler);
245    /* baseline call other: need to save fp and lr */
246    static void CallArg0AndDispatchFromBaseline(ExtendedAssembler *assembler);
247    static void CallArg1AndDispatchFromBaseline(ExtendedAssembler *assembler);
248    static void CallArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler);
249    static void CallArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler);
250    static void CallThisArg0AndDispatchFromBaseline(ExtendedAssembler *assembler);
251    static void CallThisArg1AndDispatchFromBaseline(ExtendedAssembler *assembler);
252    static void CallThisArgs2AndDispatchFromBaseline(ExtendedAssembler *assembler);
253    static void CallThisArgs3AndDispatchFromBaseline(ExtendedAssembler *assembler);
254    static void CallRangeAndDispatchFromBaseline(ExtendedAssembler *assembler);
255    static void CallNewAndDispatchFromBaseline(ExtendedAssembler *assembler);
256    static void SuperCallAndDispatchFromBaseline(ExtendedAssembler *assembler);
257    static void CallThisRangeAndDispatchFromBaseline(ExtendedAssembler *assembler);
258    /* baseline call baseline: need to check whether baseline code exists and save fp and lr */
259    static void CallArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
260    static void CallArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
261    static void CallArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
262    static void CallArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
263    static void CallThisArg0AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
264    static void CallThisArg1AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
265    static void CallThisArgs2AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
266    static void CallThisArgs3AndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
267    static void CallRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
268    static void CallNewAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
269    static void SuperCallAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
270    static void CallThisRangeAndCheckToBaselineFromBaseline(ExtendedAssembler *assembler);
271    /* get baselineBuiltinFp when baselineBuiltin call the others */
272    static void GetBaselineBuiltinFp(ExtendedAssembler *assembler);
273};
274
275class JsFunctionArgsConfigFrameScope {
276public:
277    static constexpr int FRAME_SLOT_SIZE = 8;
278    explicit JsFunctionArgsConfigFrameScope(ExtendedAssembler *assembler) : assembler_(assembler)
279    {
280        assembler_->Pushq(rbp);
281        assembler_->Pushq(static_cast<int32_t>(FrameType::OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME));
282        // 2: skip jsFunc and frameType
283        assembler_->Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
284        // callee save
285        assembler_->Pushq(r12);
286        assembler_->Pushq(r13);
287        assembler_->Pushq(r14);
288        assembler_->Pushq(rbx);
289        assembler_->Pushq(rax);
290    }
291    ~JsFunctionArgsConfigFrameScope()
292    {
293        assembler_->Movq(rbp, rsp);
294        assembler_->Addq(-5 * FRAME_SLOT_SIZE, rsp); // -5: get r12 r13 r14 rbx
295        assembler_->Popq(rbx);
296        assembler_->Popq(r14);
297        assembler_->Popq(r13);
298        assembler_->Popq(r12);
299        assembler_->Addq(FRAME_SLOT_SIZE, rsp); // skip frame type
300        assembler_->Pop(rbp);
301        assembler_->Ret();
302    }
303    NO_COPY_SEMANTIC(JsFunctionArgsConfigFrameScope);
304    NO_MOVE_SEMANTIC(JsFunctionArgsConfigFrameScope);
305private:
306    ExtendedAssembler *assembler_;
307};
308
309class OptimizedUnfoldArgVFrameFrameScope {
310public:
311    static constexpr int FRAME_SLOT_SIZE = 8;
312    explicit OptimizedUnfoldArgVFrameFrameScope(ExtendedAssembler *assembler) : assembler_(assembler)
313    {
314        assembler_->Pushq(rbp);
315        // construct frame
316        assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
317        assembler_->Pushq(assembler_->AvailableRegister2());
318        // 2: skip callSiteSp and frameType
319        assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
320        assembler_->Pushq(rbx);
321        assembler_->Pushq(r12); // callee save
322    }
323    ~OptimizedUnfoldArgVFrameFrameScope()
324    {
325        assembler_->Movq(rbp, rsp);
326        assembler_->Addq(-4 * FRAME_SLOT_SIZE, rsp); // -4: get r12 rbx
327        assembler_->Popq(r12);
328        assembler_->Popq(rbx);
329        assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp
330        assembler_->Popq(rbp);
331        assembler_->Ret();
332    }
333    NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope);
334    NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrameScope);
335private:
336    ExtendedAssembler *assembler_;
337};
338
339class OptimizedUnfoldArgVFrameFrame1Scope {
340public:
341    static constexpr int FRAME_SLOT_SIZE = 8;
342    explicit OptimizedUnfoldArgVFrameFrame1Scope(ExtendedAssembler *assembler) : assembler_(assembler)
343    {
344        assembler_->Pushq(rbp);
345        // construct frame
346        assembler_->Pushq(static_cast<int64_t>(FrameType::OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME));
347        assembler_->Pushq(assembler_->AvailableRegister2());
348        // 2: skip callSiteSp and frameType
349        assembler_->Leaq(Operand(rsp, 2 * FRAME_SLOT_SIZE), rbp);
350        assembler_->Pushq(rbx);
351        assembler_->Pushq(r12); // callee save
352        assembler_->Pushq(r13);
353        assembler_->Pushq(r14); // callee save
354    }
355    ~OptimizedUnfoldArgVFrameFrame1Scope()
356    {
357        assembler_->Movq(rbp, rsp);
358        assembler_->Addq(-6 * FRAME_SLOT_SIZE, rsp); // -6: get r12 r13 r14 rbx
359        assembler_->Popq(r14);
360        assembler_->Popq(r13);
361        assembler_->Popq(r12);
362        assembler_->Popq(rbx);
363        assembler_->Addq(2 * FRAME_SLOT_SIZE, rsp); // 2: skip frame type and sp
364        assembler_->Popq(rbp);
365        assembler_->Ret();
366    }
367    NO_COPY_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope);
368    NO_MOVE_SEMANTIC(OptimizedUnfoldArgVFrameFrame1Scope);
369private:
370    ExtendedAssembler *assembler_;
371};
372}  // namespace panda::ecmascript::x64
373#endif  // ECMASCRIPT_COMPILER_ASSEMBLER_MODULE_X64_H
374