• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 #include "ecmascript/compiler/trampoline/aarch64/common_call.h"
17 
18 #include "ecmascript/js_generator_object.h"
19 #include "ecmascript/message_string.h"
20 
21 namespace panda::ecmascript::aarch64 {
22 using Label = panda::ecmascript::Label;
23 #define __ assembler->
24 
25 // Generate code for entering asm interpreter
26 // c++ calling convention
27 // Input: glue           - %X0
28 //        callTarget     - %X1
29 //        method         - %X2
30 //        callField      - %X3
31 //        argc           - %X4
32 //        argv           - %X5(<callTarget, newTarget, this> are at the beginning of argv)
AsmInterpreterEntry(ExtendedAssembler * assembler)33 void AsmInterpreterCall::AsmInterpreterEntry(ExtendedAssembler *assembler)
34 {
35     __ BindAssemblerStub(RTSTUB_ID(AsmInterpreterEntry));
36     Label target;
37     size_t begin = __ GetCurrentPosition();
38     PushAsmInterpEntryFrame(assembler);
39     __ Bl(&target);
40     PopAsmInterpEntryFrame(assembler);
41     size_t end = __ GetCurrentPosition();
42     if ((end - begin) != FrameCompletionPos::ARM64EntryFrameDuration) {
43         LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64EntryFrameDuration
44                             << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
45     }
46     __ Ret();
47 
48     __ Bind(&target);
49     {
50         AsmInterpEntryDispatch(assembler);
51     }
52 }
53 
54 // Input: glue           - %X0
55 //        callTarget     - %X1
56 //        method         - %X2
57 //        callField      - %X3
58 //        argc           - %X4
59 //        argv           - %X5(<callTarget, newTarget, this> are at the beginning of argv)
AsmInterpEntryDispatch(ExtendedAssembler * assembler)60 void AsmInterpreterCall::AsmInterpEntryDispatch(ExtendedAssembler *assembler)
61 {
62     Label notJSFunction;
63     Label callNativeEntry;
64     Label callJSFunctionEntry;
65     Label notCallable;
66     Register glueRegister(X0);
67     Register argcRegister(X4, W);
68     Register argvRegister(X5);
69     Register callTargetRegister(X1);
70     Register callFieldRegister(X3);
71     Register bitFieldRegister(X16);
72     Register tempRegister(X17); // can not be used to store any variable
73     Register functionTypeRegister(X18, W);
74     __ Ldr(tempRegister, MemoryOperand(callTargetRegister, TaggedObject::HCLASS_OFFSET));
75     __ Ldr(bitFieldRegister, MemoryOperand(tempRegister, JSHClass::BIT_FIELD_OFFSET));
76     __ And(functionTypeRegister, bitFieldRegister.W(), LogicalImmediate::Create(0xFF, RegWSize));
77     __ Mov(tempRegister.W(), Immediate(static_cast<int64_t>(JSType::JS_FUNCTION_FIRST)));
78     __ Cmp(functionTypeRegister, tempRegister.W());
79     __ B(Condition::LO, &notJSFunction);
80     __ Mov(tempRegister.W(), Immediate(static_cast<int64_t>(JSType::JS_FUNCTION_LAST)));
81     __ Cmp(functionTypeRegister, tempRegister.W());
82     __ B(Condition::LS, &callJSFunctionEntry);
83     __ Bind(&notJSFunction);
84     {
85         __ Tst(bitFieldRegister,
86             LogicalImmediate::Create(static_cast<int64_t>(1ULL << JSHClass::CallableBit::START_BIT), RegXSize));
87         __ B(Condition::EQ, &notCallable);
88         CallNativeEntry(assembler, true);
89     }
90     __ Bind(&callNativeEntry);
91     CallNativeEntry(assembler, false);
92     __ Bind(&callJSFunctionEntry);
93     {
94         __ Tbnz(callFieldRegister, MethodLiteral::IsNativeBit::START_BIT, &callNativeEntry);
95         // fast path
96         __ Add(argvRegister, argvRegister, Immediate(NUM_MANDATORY_JSFUNC_ARGS * JSTaggedValue::TaggedTypeSize()));
97         JSCallCommonEntry(assembler, JSCallMode::CALL_ENTRY, FrameTransitionType::OTHER_TO_BASELINE_CHECK);
98     }
99     __ Bind(&notCallable);
100     {
101         Register runtimeId(X11);
102         Register trampoline(X12);
103         __ Mov(runtimeId, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowNotCallableException));
104         // 3 : 3 means *8
105         __ Add(trampoline, glueRegister, Operand(runtimeId, LSL, 3));
106         __ Ldr(trampoline, MemoryOperand(trampoline, JSThread::GlueData::GetRTStubEntriesOffset(false)));
107         __ Blr(trampoline);
108         __ Ret();
109     }
110 }
111 
JSCallCommonEntry(ExtendedAssembler * assembler,JSCallMode mode,FrameTransitionType type)112 void AsmInterpreterCall::JSCallCommonEntry(ExtendedAssembler *assembler,
113     JSCallMode mode, FrameTransitionType type)
114 {
115     Label stackOverflow;
116     Register glueRegister = __ GlueRegister();
117     Register fpRegister = __ AvailableRegister1();
118     Register currentSlotRegister = __ AvailableRegister3();
119     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
120     Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
121     if (!kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode) || type == FrameTransitionType::BASELINE_TO_OTHER ||
122         type == FrameTransitionType::BASELINE_TO_BASELINE_CHECK) {
123         __ PushFpAndLr();
124     }
125     // save fp
126     __ Mov(fpRegister, Register(SP));
127     __ Mov(currentSlotRegister, Register(SP));
128 
129     {
130         // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
131         [[maybe_unused]] TempRegister1Scope scope(assembler);
132         Register tempRegister = __ TempRegister1();
133         __ Ldr(tempRegister, MemoryOperand(glueRegister, JSThread::GlueData::GetStackLimitOffset(false)));
134         __ Mov(Register(SP), tempRegister);
135     }
136 
137     Register declaredNumArgsRegister = __ AvailableRegister2();
138     GetDeclaredNumArgsFromCallField(assembler, callFieldRegister, declaredNumArgsRegister);
139 
140     Label slowPathEntry;
141     Label fastPathEntry;
142     Label pushCallThis;
143     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
144     if (argc >= 0) {
145         __ Cmp(declaredNumArgsRegister, Immediate(argc));
146     } else {
147         __ Cmp(declaredNumArgsRegister, argcRegister);
148     }
149     __ B(Condition::NE, &slowPathEntry);
150     __ Bind(&fastPathEntry);
151     JSCallCommonFastPath(assembler, mode, &pushCallThis, &stackOverflow);
152     __ Bind(&pushCallThis);
153     PushCallThis(assembler, mode, &stackOverflow, type);
154     __ Bind(&slowPathEntry);
155     JSCallCommonSlowPath(assembler, mode, &fastPathEntry, &pushCallThis, &stackOverflow);
156 
157     __ Bind(&stackOverflow);
158     if (kungfu::AssemblerModule::IsJumpToCallCommonEntry(mode)) {
159         __ Mov(Register(SP), fpRegister);
160         [[maybe_unused]] TempRegister1Scope scope(assembler);
161         Register temp = __ TempRegister1();
162         // only glue and acc are useful in exception handler
163         if (glueRegister.GetId() != X19) {
164             __ Mov(Register(X19), glueRegister);
165         }
166         Register acc(X23);
167         __ Mov(acc, Immediate(JSTaggedValue::VALUE_EXCEPTION));
168         Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
169         Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
170         // Reload pc to make sure stack trace is right
171         __ Mov(temp, callTargetRegister);
172         __ Ldr(Register(X20), MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
173         // Reload constpool and profileInfo to make sure gc map work normally
174         __ Ldr(Register(X22), MemoryOperand(temp, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
175         __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));
176         __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
177 
178         __ Mov(temp, kungfu::BytecodeStubCSigns::ID_ThrowStackOverflowException);
179         __ Add(temp, glueRegister, Operand(temp, UXTW, 3));  // 3: bc * 8
180         __ Ldr(temp, MemoryOperand(temp, JSThread::GlueData::GetBCStubEntriesOffset(false)));
181         __ Br(temp);
182     } else {
183         [[maybe_unused]] TempRegister1Scope scope(assembler);
184         Register temp = __ TempRegister1();
185         ThrowStackOverflowExceptionAndReturn(assembler, glueRegister, fpRegister, temp);
186     }
187 }
188 
JSCallCommonFastPath(ExtendedAssembler * assembler,JSCallMode mode,Label * pushCallThis,Label * stackOverflow)189 void AsmInterpreterCall::JSCallCommonFastPath(ExtendedAssembler *assembler, JSCallMode mode, Label *pushCallThis,
190     Label *stackOverflow)
191 {
192     Register glueRegister = __ GlueRegister();
193     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
194     Register currentSlotRegister = __ AvailableRegister3();
195     // call range
196     if (argc < 0) {
197         Register numRegister = __ AvailableRegister2();
198         Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
199         Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGV);
200         __ Mov(numRegister, argcRegister);
201         [[maybe_unused]] TempRegister1Scope scope(assembler);
202         Register opRegister = __ TempRegister1();
203         PushArgsWithArgv(assembler, glueRegister, numRegister, argvRegister, opRegister,
204                          currentSlotRegister, pushCallThis, stackOverflow);
205     } else if (argc > 0) {
206         if (argc > 2) { // 2: call arg2
207             Register arg2 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
208             __ Str(arg2, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
209         }
210         if (argc > 1) {
211             Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
212             __ Str(arg1, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
213         }
214         if (argc > 0) {
215             Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
216             __ Str(arg0, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
217         }
218     }
219 }
220 
JSCallCommonSlowPath(ExtendedAssembler * assembler,JSCallMode mode,Label * fastPathEntry,Label * pushCallThis,Label * stackOverflow)221 void AsmInterpreterCall::JSCallCommonSlowPath(ExtendedAssembler *assembler, JSCallMode mode,
222                                               Label *fastPathEntry, Label *pushCallThis, Label *stackOverflow)
223 {
224     Register glueRegister = __ GlueRegister();
225     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
226     Register argcRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGC);
227     Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARGV);
228     Register currentSlotRegister = __ AvailableRegister3();
229     Register arg0 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
230     Register arg1 = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
231     Label noExtraEntry;
232     Label pushArgsEntry;
233 
234     auto argc = kungfu::AssemblerModule::GetArgcFromJSCallMode(mode);
235     Register declaredNumArgsRegister = __ AvailableRegister2();
236     __ Tbz(callFieldRegister, MethodLiteral::HaveExtraBit::START_BIT, &noExtraEntry);
237     // extra entry
238     {
239         [[maybe_unused]] TempRegister1Scope scope1(assembler);
240         Register tempArgcRegister = __ TempRegister1();
241         if (argc >= 0) {
242             __ PushArgc(argc, tempArgcRegister, currentSlotRegister);
243         } else {
244             __ PushArgc(argcRegister, tempArgcRegister, currentSlotRegister);
245         }
246         // fall through
247     }
248     __ Bind(&noExtraEntry);
249     {
250         if (argc == 0) {
251             {
252                 [[maybe_unused]] TempRegister1Scope scope(assembler);
253                 Register tempRegister = __ TempRegister1();
254                 PushUndefinedWithArgc(assembler, glueRegister, declaredNumArgsRegister, tempRegister,
255                                       currentSlotRegister, nullptr, stackOverflow);
256             }
257             __ B(fastPathEntry);
258             return;
259         }
260         [[maybe_unused]] TempRegister1Scope scope1(assembler);
261         Register diffRegister = __ TempRegister1();
262         if (argc >= 0) {
263             __ Sub(diffRegister.W(), declaredNumArgsRegister.W(), Immediate(argc));
264         } else {
265             __ Sub(diffRegister.W(), declaredNumArgsRegister.W(), argcRegister.W());
266         }
267         [[maybe_unused]] TempRegister2Scope scope2(assembler);
268         Register tempRegister = __ TempRegister2();
269         PushUndefinedWithArgc(assembler, glueRegister, diffRegister, tempRegister,
270                               currentSlotRegister, &pushArgsEntry, stackOverflow);
271         __ B(fastPathEntry);
272     }
273     // declare < actual
274     __ Bind(&pushArgsEntry);
275     {
276         __ Tbnz(callFieldRegister, MethodLiteral::HaveExtraBit::START_BIT, fastPathEntry);
277         // no extra branch
278         // arg1, declare must be 0
279         if (argc == 1) {
280             __ B(pushCallThis);
281             return;
282         }
283         __ Cmp(declaredNumArgsRegister, Immediate(0));
284         __ B(Condition::EQ, pushCallThis);
285         // call range
286         if (argc < 0) {
287             [[maybe_unused]] TempRegister1Scope scope(assembler);
288             Register opRegister = __ TempRegister1();
289             PushArgsWithArgv(assembler, glueRegister, declaredNumArgsRegister,
290                              argvRegister, opRegister,
291                              currentSlotRegister, nullptr, stackOverflow);
292         } else if (argc > 0) {
293             Label pushArgs0;
294             if (argc > 2) {  // 2: call arg2
295                 // decalare is 2 or 1 now
296                 __ Cmp(declaredNumArgsRegister, Immediate(1));
297                 __ B(Condition::EQ, &pushArgs0);
298                 __ Str(arg1, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
299             }
300             if (argc > 1) {
301                 __ Bind(&pushArgs0);
302                 // decalare is is 1 now
303                 __ Str(arg0, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
304             }
305         }
306         __ B(pushCallThis);
307     }
308 }
309 
GetThisRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)310 Register AsmInterpreterCall::GetThisRegsiter(ExtendedAssembler *assembler, JSCallMode mode, Register defaultRegister)
311 {
312     switch (mode) {
313         case JSCallMode::CALL_GETTER:
314         case JSCallMode::CALL_THIS_ARG0:
315             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG0);
316         case JSCallMode::CALL_SETTER:
317         case JSCallMode::CALL_THIS_ARG1:
318             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
319         case JSCallMode::CALL_THIS_ARG2:
320         case JSCallMode::CALL_THIS_ARG2_WITH_RETURN:
321         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
322         case JSCallMode::SUPER_CALL_WITH_ARGV:
323         case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
324         case JSCallMode::CALL_THIS_WITH_ARGV:
325         case JSCallMode::CALL_THIS_ARGV_WITH_RETURN:
326             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG2);
327         case JSCallMode::CALL_THIS_ARG3:
328         case JSCallMode::CALL_THIS_ARG3_WITH_RETURN:
329             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
330         case JSCallMode::CALL_FROM_AOT:
331         case JSCallMode::CALL_ENTRY: {
332             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
333             __ Ldur(defaultRegister, MemoryOperand(argvRegister, -FRAME_SLOT_SIZE));
334             return defaultRegister;
335         }
336         default:
337             LOG_ECMA(FATAL) << "this branch is unreachable";
338             UNREACHABLE();
339     }
340     return INVALID_REG;
341 }
342 
GetNewTargetRegsiter(ExtendedAssembler * assembler,JSCallMode mode,Register defaultRegister)343 Register AsmInterpreterCall::GetNewTargetRegsiter(ExtendedAssembler *assembler, JSCallMode mode,
344     Register defaultRegister)
345 {
346     switch (mode) {
347         case JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV:
348         case JSCallMode::CALL_THIS_WITH_ARGV:
349             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
350         case JSCallMode::SUPER_CALL_WITH_ARGV:
351         case JSCallMode::SUPER_CALL_SPREAD_WITH_ARGV:
352             return __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG3);
353         case JSCallMode::CALL_FROM_AOT:
354         case JSCallMode::CALL_ENTRY: {
355             Register argvRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
356             // 2: new Target index
357             __ Ldur(defaultRegister, MemoryOperand(argvRegister, -2 * FRAME_SLOT_SIZE));
358             return defaultRegister;
359         }
360         default:
361             LOG_ECMA(FATAL) << "this branch is unreachable";
362             UNREACHABLE();
363     }
364     return INVALID_REG;
365 }
366 
367 // void PushCallArgsxAndDispatch(uintptr_t glue, uintptr_t sp, uint64_t callTarget, uintptr_t method,
368 //     uint64_t callField, ...)
369 // GHC calling convention
370 // Input1: for callarg0/1/2/3        Input2: for callrange
371 // X19 - glue                        // X19 - glue
372 // FP  - sp                          // FP  - sp
373 // X20 - callTarget                  // X20 - callTarget
374 // X21 - method                      // X21 - method
375 // X22 - callField                   // X22 - callField
376 // X23 - arg0                        // X23 - actualArgc
377 // X24 - arg1                        // X24 - argv
378 // X25 - arg2
PushCallThisRangeAndDispatch(ExtendedAssembler * assembler)379 void AsmInterpreterCall::PushCallThisRangeAndDispatch(ExtendedAssembler *assembler)
380 {
381     __ BindAssemblerStub(RTSTUB_ID(PushCallThisRangeAndDispatch));
382     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
383 }
384 
PushCallRangeAndDispatch(ExtendedAssembler * assembler)385 void AsmInterpreterCall::PushCallRangeAndDispatch(ExtendedAssembler *assembler)
386 {
387     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatch));
388     JSCallCommonEntry(assembler, JSCallMode::CALL_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
389 }
390 
PushCallNewAndDispatch(ExtendedAssembler * assembler)391 void AsmInterpreterCall::PushCallNewAndDispatch(ExtendedAssembler *assembler)
392 {
393     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatch));
394     JSCallCommonEntry(assembler, JSCallMode::CALL_CONSTRUCTOR_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
395 }
396 
PushSuperCallAndDispatch(ExtendedAssembler * assembler)397 void AsmInterpreterCall::PushSuperCallAndDispatch(ExtendedAssembler *assembler)
398 {
399     __ BindAssemblerStub(RTSTUB_ID(PushSuperCallAndDispatch));
400     JSCallCommonEntry(assembler, JSCallMode::SUPER_CALL_WITH_ARGV, FrameTransitionType::OTHER_TO_OTHER);
401 }
402 
PushCallArgs3AndDispatch(ExtendedAssembler * assembler)403 void AsmInterpreterCall::PushCallArgs3AndDispatch(ExtendedAssembler *assembler)
404 {
405     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs3AndDispatch));
406     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG3, FrameTransitionType::OTHER_TO_OTHER);
407 }
408 
PushCallArgs2AndDispatch(ExtendedAssembler * assembler)409 void AsmInterpreterCall::PushCallArgs2AndDispatch(ExtendedAssembler *assembler)
410 {
411     __ BindAssemblerStub(RTSTUB_ID(PushCallArgs2AndDispatch));
412     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG2, FrameTransitionType::OTHER_TO_OTHER);
413 }
414 
PushCallArg1AndDispatch(ExtendedAssembler * assembler)415 void AsmInterpreterCall::PushCallArg1AndDispatch(ExtendedAssembler *assembler)
416 {
417     __ BindAssemblerStub(RTSTUB_ID(PushCallArg1AndDispatch));
418     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG1, FrameTransitionType::OTHER_TO_OTHER);
419 }
420 
PushCallArg0AndDispatch(ExtendedAssembler * assembler)421 void AsmInterpreterCall::PushCallArg0AndDispatch(ExtendedAssembler *assembler)
422 {
423     __ BindAssemblerStub(RTSTUB_ID(PushCallArg0AndDispatch));
424     JSCallCommonEntry(assembler, JSCallMode::CALL_ARG0, FrameTransitionType::OTHER_TO_OTHER);
425 }
426 
PushCallThisArg0AndDispatch(ExtendedAssembler * assembler)427 void AsmInterpreterCall::PushCallThisArg0AndDispatch(ExtendedAssembler *assembler)
428 {
429     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg0AndDispatch));
430     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG0, FrameTransitionType::OTHER_TO_OTHER);
431 }
432 
PushCallThisArg1AndDispatch(ExtendedAssembler * assembler)433 void AsmInterpreterCall::PushCallThisArg1AndDispatch(ExtendedAssembler *assembler)
434 {
435     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArg1AndDispatch));
436     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG1, FrameTransitionType::OTHER_TO_OTHER);
437 }
438 
PushCallThisArgs2AndDispatch(ExtendedAssembler * assembler)439 void AsmInterpreterCall::PushCallThisArgs2AndDispatch(ExtendedAssembler *assembler)
440 {
441     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs2AndDispatch));
442     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2, FrameTransitionType::OTHER_TO_OTHER);
443 }
444 
PushCallThisArgs3AndDispatch(ExtendedAssembler * assembler)445 void AsmInterpreterCall::PushCallThisArgs3AndDispatch(ExtendedAssembler *assembler)
446 {
447     __ BindAssemblerStub(RTSTUB_ID(PushCallThisArgs3AndDispatch));
448     JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3, FrameTransitionType::OTHER_TO_OTHER);
449 }
450 
451 // uint64_t PushCallRangeAndDispatchNative(uintptr_t glue, uint32_t argc, JSTaggedType calltarget, uintptr_t argv[])
452 // c++ calling convention call js function
453 // Input: X0 - glue
454 //        X1 - nativeCode
455 //        X2 - callTarget
456 //        X3 - thisValue
457 //        X4  - argc
458 //        X5  - argV (...)
PushCallRangeAndDispatchNative(ExtendedAssembler * assembler)459 void AsmInterpreterCall::PushCallRangeAndDispatchNative(ExtendedAssembler *assembler)
460 {
461     __ BindAssemblerStub(RTSTUB_ID(PushCallRangeAndDispatchNative));
462     CallNativeWithArgv(assembler, false);
463 }
464 
PushCallNewAndDispatchNative(ExtendedAssembler * assembler)465 void AsmInterpreterCall::PushCallNewAndDispatchNative(ExtendedAssembler *assembler)
466 {
467     __ BindAssemblerStub(RTSTUB_ID(PushCallNewAndDispatchNative));
468     CallNativeWithArgv(assembler, true);
469 }
470 
PushNewTargetAndDispatchNative(ExtendedAssembler * assembler)471 void AsmInterpreterCall::PushNewTargetAndDispatchNative(ExtendedAssembler *assembler)
472 {
473     __ BindAssemblerStub(RTSTUB_ID(PushNewTargetAndDispatchNative));
474     CallNativeWithArgv(assembler, true, true);
475 }
476 
CallNativeWithArgv(ExtendedAssembler * assembler,bool callNew,bool hasNewTarget)477 void AsmInterpreterCall::CallNativeWithArgv(ExtendedAssembler *assembler, bool callNew, bool hasNewTarget)
478 {
479     Register glue(X0);
480     Register nativeCode(X1);
481     Register callTarget(X2);
482     Register thisObj(X3);
483     Register argc(X4);
484     Register argv(X5);
485     Register newTarget(X6);
486     Register opArgc(X8);
487     Register opArgv(X9);
488     Register temp(X10);
489     Register currentSlotRegister(X11);
490     Register spRegister(SP);
491 
492     Label pushThis;
493     Label stackOverflow;
494     bool isFrameComplete = PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME_WITH_ARGV, temp, argc);
495 
496     __ Mov(currentSlotRegister, spRegister);
497     // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
498     __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
499     __ Mov(Register(SP), temp);
500 
501     __ Mov(opArgc, argc);
502     __ Mov(opArgv, argv);
503     PushArgsWithArgv(assembler, glue, opArgc, opArgv, temp, currentSlotRegister, &pushThis, &stackOverflow);
504 
505     __ Bind(&pushThis);
506     // newTarget
507     if (callNew) {
508         if (hasNewTarget) {
509             // 16: this & newTarget
510             __ Stp(newTarget, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
511         } else {
512             // 16: this & newTarget
513             __ Stp(callTarget, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
514         }
515     } else {
516         __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
517         // 16: this & newTarget
518         __ Stp(temp, thisObj, MemoryOperand(currentSlotRegister, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
519     }
520     // callTarget
521     __ Str(callTarget, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
522     __ Add(temp, currentSlotRegister, Immediate(QUINTUPLE_SLOT_SIZE));
523     if (!isFrameComplete) {
524         __ Add(Register(FP), temp, Operand(argc, LSL, 3));  // 3: argc * 8
525     }
526 
527     __ Add(temp, argc, Immediate(NUM_MANDATORY_JSFUNC_ARGS));
528     // 2: thread & argc
529     __ Stp(glue, temp, MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
530     __ Add(Register(X0), currentSlotRegister, Immediate(0));
531 
532     __ Align16(currentSlotRegister);
533     __ Mov(spRegister, currentSlotRegister);
534 
535     CallNativeInternal(assembler, nativeCode);
536     __ Ret();
537 
538     __ Bind(&stackOverflow);
539     {
540         // use builtin_with_argv_frame to mark gc map
541         Register frameType(X11);
542         __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
543         __ Mov(spRegister, temp);
544         __ Mov(frameType, Immediate(static_cast<int32_t>(FrameType::BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME)));
545         // 2: frame type and argc
546         __ Stp(Register(Zero), frameType, MemoryOperand(Register(SP), -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
547         __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
548         // 2: fill this&newtgt slots
549         __ Stp(temp, temp, MemoryOperand(spRegister, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
550         // 2: fill func&align slots
551         __ Stp(Register(Zero), temp, MemoryOperand(spRegister, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
552         __ Mov(temp, spRegister);
553         // 6:frame type, argc, this, newTarget, func and align
554         // +----------------------------------------------------------------+ <---- fp = sp + 6 * frame_slot_size
555         // |     FrameType =  BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME |
556         // +----------------------------------------------------------------+
557         // |                           argc = 0                             |
558         // |----------------------------------------------------------------|
559         // |                       this = undefined                         |
560         // |----------------------------------------------------------------|
561         // |                      newTarget = undefine                      |
562         // |----------------------------------------------------------------|
563         // |                       function = undefined                     |
564         // |----------------------------------------------------------------|
565         // |                               align                            |
566         // +----------------------------------------------------------------+  <---- sp
567         __ Add(Register(FP), temp, Immediate(FRAME_SLOT_SIZE * 6));
568 
569         Register runtimeId(X11);
570         Register trampoline(X12);
571         __ Mov(runtimeId, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException));
572         // 3 : 3 means *8
573         __ Add(trampoline, glue, Operand(runtimeId, LSL, 3));
574         __ Ldr(trampoline, MemoryOperand(trampoline, JSThread::GlueData::GetRTStubEntriesOffset(false)));
575         __ Blr(trampoline);
576 
577         // resume rsp
578         __ Mov(Register(SP), Register(FP));
579         __ RestoreFpAndLr();
580         __ Ret();
581     }
582 }
583 
584 // uint64_t PushCallArgsAndDispatchNative(uintptr_t codeAddress, uintptr_t glue, uint32_t argc, ...)
585 // webkit_jscc calling convention call runtime_id's runtion function(c-abi)
586 // Input: X0 - codeAddress
587 // stack layout: sp + N*8 argvN
588 //               ........
589 //               sp + 24: argv1
590 //               sp + 16: argv0
591 //               sp + 8:  actualArgc
592 //               sp:      thread
593 // construct Native Leave Frame
594 //               +--------------------------+
595 //               |     argV[N - 1]          |
596 //               |--------------------------|
597 //               |       . . . .            |
598 //               |--------------------------+
599 //               |     argV[2]=this         |
600 //               +--------------------------+
601 //               |     argV[1]=new-target   |
602 //               +--------------------------+
603 //               |     argV[0]=call-target  |
604 //               +--------------------------+ ---------
605 //               |       argc               |         ^
606 //               |--------------------------|         |
607 //               |       thread             |         |
608 //               |--------------------------|         |
609 //               |       returnAddr         |     BuiltinFrame
610 //               |--------------------------|         |
611 //               |       callsiteFp         |         |
612 //               |--------------------------|         |
613 //               |       frameType          |         v
614 //               +--------------------------+ ---------
615 
PushCallArgsAndDispatchNative(ExtendedAssembler * assembler)616 void AsmInterpreterCall::PushCallArgsAndDispatchNative(ExtendedAssembler *assembler)
617 {
618     __ BindAssemblerStub(RTSTUB_ID(PushCallArgsAndDispatchNative));
619 
620     Register nativeCode(X0);
621     Register glue(X1);
622     Register argv(X5);
623     Register temp(X6);
624     Register sp(SP);
625     Register nativeCodeTemp(X2);
626 
627     __ Mov(nativeCodeTemp, nativeCode);
628 
629     __ Ldr(glue, MemoryOperand(sp, 0));
630     __ Add(Register(X0), sp, Immediate(0));
631     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_FRAME, temp, argv);
632 
633     CallNativeInternal(assembler, nativeCodeTemp);
634     __ Ret();
635 }
636 
PushBuiltinFrame(ExtendedAssembler * assembler,Register glue,FrameType type,Register op,Register next)637 bool AsmInterpreterCall::PushBuiltinFrame(ExtendedAssembler *assembler, Register glue,
638     FrameType type, Register op, Register next)
639 {
640     Register sp(SP);
641     __ PushFpAndLr();
642     __ Mov(op, sp);
643     __ Str(op, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
644     __ Mov(op, Immediate(static_cast<int32_t>(type)));
645     if (type == FrameType::BUILTIN_FRAME) {
646         // push stack args
647         __ Add(next, sp, Immediate(BuiltinFrame::GetStackArgsToFpDelta(false)));
648         // 2: -2 * FRAME_SLOT_SIZE means type & next
649         __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
650         // 2: 2 * FRAME_SLOT_SIZE means skip next and frame type
651         __ Add(Register(FP), sp, Immediate(2 * FRAME_SLOT_SIZE));
652         return true;
653     } else if (type == FrameType::BUILTIN_ENTRY_FRAME) {
654         // 2: -2 * FRAME_SLOT_SIZE means type & next
655         __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
656         // 2: 2 * FRAME_SLOT_SIZE means skip next and frame type
657         __ Add(Register(FP), sp, Immediate(2 * FRAME_SLOT_SIZE));
658         return true;
659     } else if (type == FrameType::BUILTIN_FRAME_WITH_ARGV) {
660         // this frame push stack args must before update FP, otherwise cpu profiler maybe visit incomplete stack
661         // BuiltinWithArgvFrame layout please see frames.h
662         // 2: -2 * FRAME_SLOT_SIZE means type & next
663         __ Stp(next, op, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
664         return false;
665     } else {
666         LOG_ECMA(FATAL) << "this branch is unreachable";
667         UNREACHABLE();
668     }
669 }
670 
CallNativeInternal(ExtendedAssembler * assembler,Register nativeCode)671 void AsmInterpreterCall::CallNativeInternal(ExtendedAssembler *assembler, Register nativeCode)
672 {
673     __ Blr(nativeCode);
674     // resume rsp
675     __ Mov(Register(SP), Register(FP));
676     __ RestoreFpAndLr();
677 }
678 
679 // ResumeRspAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
680 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
681 // GHC calling convention
682 // X19 - glue
683 // FP  - sp
684 // X20 - pc
685 // X21 - constantPool
686 // X22 - profileTypeInfo
687 // X23 - acc
688 // X24 - hotnessCounter
689 // X25 - jumpSizeAfterCall
ResumeRspAndDispatch(ExtendedAssembler * assembler)690 void AsmInterpreterCall::ResumeRspAndDispatch(ExtendedAssembler *assembler)
691 {
692     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndDispatch));
693 
694     Register glueRegister = __ GlueRegister();
695     Register sp(FP);
696     Register rsp(SP);
697     Register pc(X20);
698     Register jumpSizeRegister(X25);
699 
700     Register ret(X23);
701     Register opcode(X6, W);
702     Register temp(X7);
703     Register bcStub(X7);
704     Register fp(X8);
705 
706     int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
707         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
708     int64_t spOffset = static_cast<int64_t>(AsmInterpretedFrame::GetBaseOffset(false))
709         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
710     int64_t thisOffset = static_cast<int64_t>(AsmInterpretedFrame::GetThisOffset(false))
711         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
712     ASSERT(fpOffset < 0);
713     ASSERT(spOffset < 0);
714 
715     Label newObjectRangeReturn;
716     Label dispatch;
717     __ Ldur(fp, MemoryOperand(sp, fpOffset));  // store fp for temporary
718     __ Cmp(jumpSizeRegister, Immediate(0));
719     __ B(Condition::LE, &newObjectRangeReturn);
720     __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
721 
722     __ Add(pc, pc, Operand(jumpSizeRegister, LSL, 0));
723     __ Ldrb(opcode, MemoryOperand(pc, 0));
724     __ Bind(&dispatch);
725     {
726         __ Mov(rsp, fp);  // resume rsp
727         __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
728         __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
729         __ Br(bcStub);
730     }
731 
732     Label getThis;
733     Label notUndefined;
734     __ Bind(&newObjectRangeReturn);
735     {
736         __ Cmp(ret, Immediate(JSTaggedValue::VALUE_UNDEFINED));
737         __ B(Condition::NE, &notUndefined);
738         ASSERT(thisOffset < 0);
739         __ Bind(&getThis);
740         __ Ldur(ret, MemoryOperand(sp, thisOffset));  // update acc
741         __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
742         __ Mov(rsp, fp);  // resume rsp
743         __ Sub(pc, pc, jumpSizeRegister); // sub negative jmupSize
744         __ Ldrb(opcode, MemoryOperand(pc, 0));
745         __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
746         __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
747         __ Br(bcStub);
748     }
749     __ Bind(&notUndefined);
750     {
751         Label notEcmaObject;
752         __ Mov(temp, Immediate(JSTaggedValue::TAG_HEAPOBJECT_MASK));
753         __ And(temp, temp, ret);
754         __ Cmp(temp, Immediate(0));
755         __ B(Condition::NE, &notEcmaObject);
756         // acc is heap object
757         __ Ldr(temp, MemoryOperand(ret, TaggedObject::HCLASS_OFFSET));
758         __ Ldr(temp, MemoryOperand(temp, JSHClass::BIT_FIELD_OFFSET));
759         __ And(temp.W(), temp.W(), LogicalImmediate::Create(0xFF, RegWSize));
760         __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_LAST)));
761         __ B(Condition::HI, &notEcmaObject);
762         __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
763         __ B(Condition::LO, &notEcmaObject);
764         // acc is ecma object
765         __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
766         __ Sub(pc, pc, jumpSizeRegister); // sub negative jmupSize
767         __ Ldrb(opcode, MemoryOperand(pc, 0));
768         __ B(&dispatch);
769 
770         __ Bind(&notEcmaObject);
771         {
772             int64_t constructorOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false))
773                 - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
774             ASSERT(constructorOffset < 0);
775             __ Ldur(temp, MemoryOperand(sp, constructorOffset));  // load constructor
776             __ Ldr(temp, MemoryOperand(temp, JSFunctionBase::METHOD_OFFSET));
777             __ Ldr(temp, MemoryOperand(temp, Method::EXTRA_LITERAL_INFO_OFFSET));
778             __ Lsr(temp.W(), temp.W(), MethodLiteral::FunctionKindBits::START_BIT);
779             __ And(temp.W(), temp.W(),
780                 LogicalImmediate::Create((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, RegWSize));
781             __ Cmp(temp.W(), Immediate(static_cast<int64_t>(FunctionKind::CLASS_CONSTRUCTOR)));
782             __ B(Condition::LS, &getThis);  // constructor is base
783             // exception branch
784             {
785                 __ Mov(opcode, kungfu::BytecodeStubCSigns::ID_NewObjectRangeThrowException);
786                 __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
787                 __ B(&dispatch);
788             }
789         }
790     }
791 }
792 
793 // ResumeRspAndReturn(uintptr_t acc)
794 // GHC calling convention
795 // X19 - acc
796 // FP - prevSp
797 // X20 - sp
ResumeRspAndReturn(ExtendedAssembler * assembler)798 void AsmInterpreterCall::ResumeRspAndReturn(ExtendedAssembler *assembler)
799 {
800     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturn));
801     Register rsp(SP);
802     Register currentSp(X20);
803 
804     [[maybe_unused]] TempRegister1Scope scope1(assembler);
805     Register fpRegister = __ TempRegister1();
806     int64_t offset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
807         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
808     ASSERT(offset < 0);
809     __ Ldur(fpRegister, MemoryOperand(currentSp, offset));
810     __ Mov(rsp, fpRegister);
811 
812     // return
813     {
814         __ RestoreFpAndLr();
815         __ Mov(Register(X0), Register(X19));
816         __ Ret();
817     }
818 }
819 
820 // ResumeRspAndReturnBaseline(uintptr_t acc)
821 // GHC calling convention
822 // X19 - acc
823 // FP - prevSp
824 // X20 - sp
825 // X21 - jumpSizeAfterCall
ResumeRspAndReturnBaseline(ExtendedAssembler * assembler)826 void AsmInterpreterCall::ResumeRspAndReturnBaseline(ExtendedAssembler *assembler)
827 {
828     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndReturnBaseline));
829     Register rsp(SP);
830     Register currentSp(X20);
831 
832     [[maybe_unused]] TempRegister1Scope scope1(assembler);
833     Register fpRegister = __ TempRegister1();
834     int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false)) -
835         static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
836     ASSERT(fpOffset < 0);
837     __ Ldur(fpRegister, MemoryOperand(currentSp, fpOffset));
838     __ Mov(rsp, fpRegister);
839     __ RestoreFpAndLr();
840     __ Mov(Register(X0), Register(X19));
841 
842     // Check and set result
843     Register ret = X0;
844     Register jumpSizeRegister = X21;
845     Label getThis;
846     Label notUndefined;
847     Label normalReturn;
848     Label newObjectRangeReturn;
849     __ Cmp(jumpSizeRegister, Immediate(0));
850     __ B(Condition::GT, &normalReturn);
851 
852     __ Bind(&newObjectRangeReturn);
853     {
854         __ Cmp(ret, Immediate(JSTaggedValue::VALUE_UNDEFINED));
855         __ B(Condition::NE, &notUndefined);
856 
857         __ Bind(&getThis);
858         int64_t thisOffset = static_cast<int64_t>(AsmInterpretedFrame::GetThisOffset(false)) -
859             static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
860         ASSERT(thisOffset < 0);
861         __ Ldur(ret, MemoryOperand(currentSp, thisOffset));  // update result
862         __ B(&normalReturn);
863 
864         __ Bind(&notUndefined);
865         {
866             Register temp = X19;
867             Label notEcmaObject;
868             __ Mov(temp, Immediate(JSTaggedValue::TAG_HEAPOBJECT_MASK));
869             __ And(temp, temp, ret);
870             __ Cmp(temp, Immediate(0));
871             __ B(Condition::NE, &notEcmaObject);
872             // acc is heap object
873             __ Ldr(temp, MemoryOperand(ret, TaggedObject::HCLASS_OFFSET));
874             __ Ldr(temp, MemoryOperand(temp, JSHClass::BIT_FIELD_OFFSET));
875             __ And(temp.W(), temp.W(), LogicalImmediate::Create(0xFF, RegWSize));
876             __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_LAST)));
877             __ B(Condition::HI, &notEcmaObject);
878             __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
879             __ B(Condition::LO, &notEcmaObject);
880             // acc is ecma object
881             __ B(&normalReturn);
882 
883             __ Bind(&notEcmaObject);
884             {
885                 int64_t funcOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false)) -
886                     static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
887                 ASSERT(funcOffset < 0);
888                 __ Ldur(temp, MemoryOperand(currentSp, funcOffset));  // load constructor
889                 __ Ldr(temp, MemoryOperand(temp, JSFunctionBase::METHOD_OFFSET));
890                 __ Ldr(temp, MemoryOperand(temp, Method::EXTRA_LITERAL_INFO_OFFSET));
891                 __ Lsr(temp.W(), temp.W(), MethodLiteral::FunctionKindBits::START_BIT);
892                 __ And(temp.W(), temp.W(),
893                        LogicalImmediate::Create((1LU << MethodLiteral::FunctionKindBits::SIZE) - 1, RegWSize));
894                 __ Cmp(temp.W(), Immediate(static_cast<int64_t>(FunctionKind::CLASS_CONSTRUCTOR)));
895                 __ B(Condition::LS, &getThis);  // constructor is base
896                 // fall through
897             }
898         }
899     }
900     __ Bind(&normalReturn);
901     __ Ret();
902 }
903 
904 // ResumeCaughtFrameAndDispatch(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
905 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter)
906 // GHC calling convention
907 // X19 - glue
908 // FP  - sp
909 // X20 - pc
910 // X21 - constantPool
911 // X22 - profileTypeInfo
912 // X23 - acc
913 // X24 - hotnessCounter
ResumeCaughtFrameAndDispatch(ExtendedAssembler * assembler)914 void AsmInterpreterCall::ResumeCaughtFrameAndDispatch(ExtendedAssembler *assembler)
915 {
916     __ BindAssemblerStub(RTSTUB_ID(ResumeCaughtFrameAndDispatch));
917 
918     Register glue(X19);
919     Register pc(X20);
920     Register fp(X5);
921     Register opcode(X6, W);
922     Register bcStub(X7);
923 
924     Label dispatch;
925     __ Ldr(fp, MemoryOperand(glue, JSThread::GlueData::GetLastFpOffset(false)));
926     __ Cmp(fp, Immediate(0));
927     __ B(Condition::EQ, &dispatch);
928     // up frame
929     __ Mov(Register(SP), fp);
930     // fall through
931     __ Bind(&dispatch);
932     {
933         __ Ldrb(opcode, MemoryOperand(pc, 0));
934         __ Add(bcStub, glue, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
935         __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
936         __ Br(bcStub);
937     }
938 }
939 
940 // ResumeUncaughtFrameAndReturn(uintptr_t glue)
941 // GHC calling convention
942 // X19 - glue
943 // FP - sp
944 // X20 - acc
ResumeUncaughtFrameAndReturn(ExtendedAssembler * assembler)945 void AsmInterpreterCall::ResumeUncaughtFrameAndReturn(ExtendedAssembler *assembler)
946 {
947     __ BindAssemblerStub(RTSTUB_ID(ResumeUncaughtFrameAndReturn));
948 
949     Register glue(X19);
950     Register fp(X5);
951     Register acc(X20);
952     Register cppRet(X0);
953 
954     __ Ldr(fp, MemoryOperand(glue, JSThread::GlueData::GetLastFpOffset(false)));
955     __ Mov(Register(SP), fp);
956     // this method will return to Execute(cpp calling convention), and the return value should be put into X0.
957     __ Mov(cppRet, acc);
958     __ RestoreFpAndLr();
959     __ Ret();
960 }
961 
962 // ResumeRspAndRollback(uintptr_t glue, uintptr_t sp, uintptr_t pc, uintptr_t constantPool,
963 //     uint64_t profileTypeInfo, uint64_t acc, uint32_t hotnessCounter, size_t jumpSize)
964 // GHC calling convention
965 // X19 - glue
966 // FP  - sp
967 // X20 - pc
968 // X21 - constantPool
969 // X22 - profileTypeInfo
970 // X23 - acc
971 // X24 - hotnessCounter
972 // X25 - jumpSizeAfterCall
ResumeRspAndRollback(ExtendedAssembler * assembler)973 void AsmInterpreterCall::ResumeRspAndRollback(ExtendedAssembler *assembler)
974 {
975     __ BindAssemblerStub(RTSTUB_ID(ResumeRspAndRollback));
976 
977     Register glueRegister = __ GlueRegister();
978     Register sp(FP);
979     Register rsp(SP);
980     Register pc(X20);
981     Register jumpSizeRegister(X25);
982 
983     Register ret(X23);
984     Register opcode(X6, W);
985     Register bcStub(X7);
986     Register fp(X8);
987 
988     int64_t fpOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFpOffset(false))
989         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
990     int64_t spOffset = static_cast<int64_t>(AsmInterpretedFrame::GetBaseOffset(false))
991         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
992     int64_t funcOffset = static_cast<int64_t>(AsmInterpretedFrame::GetFunctionOffset(false))
993         - static_cast<int64_t>(AsmInterpretedFrame::GetSize(false));
994     ASSERT(fpOffset < 0);
995     ASSERT(spOffset < 0);
996     ASSERT(funcOffset < 0);
997 
998     __ Ldur(fp, MemoryOperand(sp, fpOffset));  // store fp for temporary
999     __ Ldur(ret, MemoryOperand(sp, funcOffset)); // restore acc
1000     __ Ldur(sp, MemoryOperand(sp, spOffset));  // update sp
1001 
1002     __ Add(pc, pc, Operand(jumpSizeRegister, LSL, 0));
1003     __ Ldrb(opcode, MemoryOperand(pc, 0));
1004 
1005     __ Mov(rsp, fp);  // resume rsp
1006     __ Add(bcStub, glueRegister, Operand(opcode, UXTW, FRAME_SLOT_SIZE_LOG2));
1007     __ Ldr(bcStub, MemoryOperand(bcStub, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1008     __ Br(bcStub);
1009 }
1010 
1011 // c++ calling convention
1012 // X0 - glue
1013 // X1 - callTarget
1014 // X2 - method
1015 // X3 - callField
1016 // X4 - receiver
1017 // X5 - value
CallGetter(ExtendedAssembler * assembler)1018 void AsmInterpreterCall::CallGetter(ExtendedAssembler *assembler)
1019 {
1020     __ BindAssemblerStub(RTSTUB_ID(CallGetter));
1021     Label target;
1022 
1023     PushAsmInterpBridgeFrame(assembler);
1024     __ Bl(&target);
1025     PopAsmInterpBridgeFrame(assembler);
1026     __ Ret();
1027     __ Bind(&target);
1028     {
1029         JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER, FrameTransitionType::OTHER_TO_OTHER);
1030     }
1031 }
1032 
CallSetter(ExtendedAssembler * assembler)1033 void AsmInterpreterCall::CallSetter(ExtendedAssembler *assembler)
1034 {
1035     __ BindAssemblerStub(RTSTUB_ID(CallSetter));
1036     Label target;
1037     PushAsmInterpBridgeFrame(assembler);
1038     __ Bl(&target);
1039     PopAsmInterpBridgeFrame(assembler);
1040     __ Ret();
1041     __ Bind(&target);
1042     {
1043         JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER, FrameTransitionType::OTHER_TO_OTHER);
1044     }
1045 }
1046 
CallContainersArgs2(ExtendedAssembler * assembler)1047 void AsmInterpreterCall::CallContainersArgs2(ExtendedAssembler *assembler)
1048 {
1049     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs2));
1050     Label target;
1051     PushAsmInterpBridgeFrame(assembler);
1052     __ Bl(&target);
1053     PopAsmInterpBridgeFrame(assembler);
1054     __ Ret();
1055     __ Bind(&target);
1056     {
1057         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2_WITH_RETURN,
1058                           FrameTransitionType::OTHER_TO_OTHER);
1059     }
1060 }
1061 
CallContainersArgs3(ExtendedAssembler * assembler)1062 void AsmInterpreterCall::CallContainersArgs3(ExtendedAssembler *assembler)
1063 {
1064     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3));
1065     Label target;
1066     PushAsmInterpBridgeFrame(assembler);
1067     __ Bl(&target);
1068     PopAsmInterpBridgeFrame(assembler);
1069     __ Ret();
1070     __ Bind(&target);
1071     {
1072         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
1073                           FrameTransitionType::OTHER_TO_OTHER);
1074     }
1075 }
1076 
1077 // c++ calling convention
1078 // X0 - glue
1079 // X1 - callTarget
1080 // X2 - method
1081 // X3 - callField
1082 // X4 - arg0(argc)
1083 // X5 - arg1(arglist)
1084 // X6 - arg3(argthis)
CallReturnWithArgv(ExtendedAssembler * assembler)1085 void AsmInterpreterCall::CallReturnWithArgv(ExtendedAssembler *assembler)
1086 {
1087     __ BindAssemblerStub(RTSTUB_ID(CallReturnWithArgv));
1088     Label target;
1089     PushAsmInterpBridgeFrame(assembler);
1090     __ Bl(&target);
1091     PopAsmInterpBridgeFrame(assembler);
1092     __ Ret();
1093     __ Bind(&target);
1094     {
1095         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
1096                           FrameTransitionType::OTHER_TO_OTHER);
1097     }
1098 }
1099 
1100 // c++ calling convention
1101 // X0 - glue
1102 // X1 - callTarget
1103 // X2 - method
1104 // X3 - callField
1105 // X4 - receiver
1106 // X5 - value
CallGetterToBaseline(ExtendedAssembler * assembler)1107 void AsmInterpreterCall::CallGetterToBaseline(ExtendedAssembler *assembler)
1108 {
1109     __ BindAssemblerStub(RTSTUB_ID(CallGetterToBaseline));
1110     Label target;
1111 
1112     PushAsmInterpBridgeFrame(assembler);
1113     __ Bl(&target);
1114     PopAsmInterpBridgeFrame(assembler);
1115     __ Ret();
1116     __ Bind(&target);
1117     {
1118         JSCallCommonEntry(assembler, JSCallMode::CALL_GETTER, FrameTransitionType::OTHER_TO_BASELINE_CHECK);
1119     }
1120 }
1121 
CallSetterToBaseline(ExtendedAssembler * assembler)1122 void AsmInterpreterCall::CallSetterToBaseline(ExtendedAssembler *assembler)
1123 {
1124     __ BindAssemblerStub(RTSTUB_ID(CallSetterToBaseline));
1125     Label target;
1126     PushAsmInterpBridgeFrame(assembler);
1127     __ Bl(&target);
1128     PopAsmInterpBridgeFrame(assembler);
1129     __ Ret();
1130     __ Bind(&target);
1131     {
1132         JSCallCommonEntry(assembler, JSCallMode::CALL_SETTER, FrameTransitionType::OTHER_TO_BASELINE_CHECK);
1133     }
1134 }
1135 
CallContainersArgs2ToBaseline(ExtendedAssembler * assembler)1136 void AsmInterpreterCall::CallContainersArgs2ToBaseline(ExtendedAssembler *assembler)
1137 {
1138     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs2ToBaseline));
1139     Label target;
1140     PushAsmInterpBridgeFrame(assembler);
1141     __ Bl(&target);
1142     PopAsmInterpBridgeFrame(assembler);
1143     __ Ret();
1144     __ Bind(&target);
1145     {
1146         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG2_WITH_RETURN,
1147                           FrameTransitionType::OTHER_TO_BASELINE_CHECK);
1148     }
1149 }
1150 
CallContainersArgs3ToBaseline(ExtendedAssembler * assembler)1151 void AsmInterpreterCall::CallContainersArgs3ToBaseline(ExtendedAssembler *assembler)
1152 {
1153     __ BindAssemblerStub(RTSTUB_ID(CallContainersArgs3ToBaseline));
1154     Label target;
1155     PushAsmInterpBridgeFrame(assembler);
1156     __ Bl(&target);
1157     PopAsmInterpBridgeFrame(assembler);
1158     __ Ret();
1159     __ Bind(&target);
1160     {
1161         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARG3_WITH_RETURN,
1162                           FrameTransitionType::OTHER_TO_BASELINE_CHECK);
1163     }
1164 }
1165 
1166 // c++ calling convention
1167 // X0 - glue
1168 // X1 - callTarget
1169 // X2 - method
1170 // X3 - callField
1171 // X4 - arg0(argc)
1172 // X5 - arg1(arglist)
1173 // X6 - arg3(argthis)
CallReturnWithArgvToBaseline(ExtendedAssembler * assembler)1174 void AsmInterpreterCall::CallReturnWithArgvToBaseline(ExtendedAssembler *assembler)
1175 {
1176     __ BindAssemblerStub(RTSTUB_ID(CallReturnWithArgvToBaseline));
1177     Label target;
1178     PushAsmInterpBridgeFrame(assembler);
1179     __ Bl(&target);
1180     PopAsmInterpBridgeFrame(assembler);
1181     __ Ret();
1182     __ Bind(&target);
1183     {
1184         JSCallCommonEntry(assembler, JSCallMode::CALL_THIS_ARGV_WITH_RETURN,
1185                           FrameTransitionType::OTHER_TO_OTHER);
1186     }
1187 }
1188 
1189 // preserve all the general registers, except x15 and callee saved registers/
1190 // and call x15
PreserveMostCall(ExtendedAssembler * assembler)1191 void AsmInterpreterCall::PreserveMostCall(ExtendedAssembler* assembler)
1192 {
1193     // * layout as the following:
1194     //               +--------------------------+ ---------
1195     //               |       . . . . .          |         ^
1196     // callerSP ---> |--------------------------|         |
1197     //               |       returnAddr         |         |
1198     //               |--------------------------|   OptimizedFrame
1199     //               |       callsiteFp         |         |
1200     //       fp ---> |--------------------------|         |
1201     //               |     OPTIMIZED_FRAME      |         v
1202     //               +--------------------------+ ---------
1203     //               |           x0             |
1204     //               +--------------------------+
1205     //               |           x1             |
1206     //               +--------------------------+
1207     //               |           r2             |
1208     //               +--------------------------+
1209     //               |           x3             |
1210     //               +--------------------------+
1211     //               |           x4             |
1212     //               +--------------------------+
1213     //               |           x5             |
1214     //               +--------------------------+
1215     //               |           x6             |
1216     //               +--------------------------+
1217     //               |           x7             |
1218     //               +--------------------------+
1219     //               |           x8             |
1220     //               +--------------------------+
1221     //               |           x9             |
1222     //               +--------------------------+
1223     //               |           x10            |
1224     //               +--------------------------+
1225     //               |           x11            |
1226     //               +--------------------------+
1227     //               |           x12            |
1228     //               +--------------------------+
1229     //               |           x13            |
1230     //               +--------------------------+
1231     //               |           x14            |
1232     //               +--------------------------+
1233     //               |           x16            |
1234     //               +--------------------------+
1235     //               |           x17            |
1236     //               +--------------------------+
1237     //               |           x18            |
1238     //               +--------------------------+
1239     //               |         align            |
1240     // calleeSP ---> +--------------------------+
1241     {
1242         // prologue to save fp, frametype, and update fp.
1243         __ Stp(X29, X30, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1244         // Zero register means OPTIMIZED_FRAME
1245         __ Stp(X0, Zero, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1246         __ Add(FP, SP, Immediate(DOUBLE_SLOT_SIZE));
1247     }
1248     int32_t PreserveRegPairIndex = 9;
1249     // x0~x14,x16,x17,x18 should be preserved,
1250     // other general registers are callee saved register, callee will save them.
1251     __ Sub(SP, SP, Immediate(DOUBLE_SLOT_SIZE * PreserveRegPairIndex));
1252     __ Stp(X1, X2, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1253     __ Stp(X3, X4, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1254     __ Stp(X5, X6, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1255     __ Stp(X7, X8, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1256     __ Stp(X9, X10, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1257     __ Stp(X11, X12, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1258     __ Stp(X13, X14, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1259     __ Stp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (--PreserveRegPairIndex)));
1260     __ Str(X18, MemoryOperand(SP, FRAME_SLOT_SIZE));
1261     __ Blr(X15);
1262     __ Ldr(X18, MemoryOperand(SP, FRAME_SLOT_SIZE));
1263     __ Ldp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1264     __ Ldp(X13, X14, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1265     __ Ldp(X11, X12, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1266     __ Ldp(X9, X10, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1267     __ Ldp(X7, X8, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1268     __ Ldp(X5, X6, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1269     __ Ldp(X3, X4, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1270     __ Ldp(X1, X2, MemoryOperand(SP, DOUBLE_SLOT_SIZE * (PreserveRegPairIndex++)));
1271     __ Ldr(X0, MemoryOperand(SP, DOUBLE_SLOT_SIZE * PreserveRegPairIndex));
1272     {
1273         // epilogue to restore sp, fp, lr.
1274         // Skip x0 slot and frametype slot
1275         __ Add(SP, SP, Immediate(DOUBLE_SLOT_SIZE * PreserveRegPairIndex +
1276             FRAME_SLOT_SIZE + FRAME_SLOT_SIZE));
1277         __ Ldp(FP, X30, MemoryOperand(SP, DOUBLE_SLOT_SIZE, AddrMode::POSTINDEX));
1278         __ Ret();
1279     }
1280 }
1281 
1282 // ASMFastWriteBarrier(GateRef glue, GateRef obj, GateRef offset, GateRef value)
1283 // c calling convention, but preserve all general registers except %x15
1284 // %x0 - glue
1285 // %x1 - obj
1286 // %x2 - offset
1287 // %x3 - value
ASMFastWriteBarrier(ExtendedAssembler * assembler)1288 void AsmInterpreterCall::ASMFastWriteBarrier(ExtendedAssembler* assembler)
1289 {
1290     // valid region flag are as follows, assume it will be ALWAYS VALID.
1291     // Judge the region of value with:
1292     //                          "young"            "sweepable share"  "readonly share"
1293     // region flag:         0x08, 0x09, [0x0A, 0x11], [0x12, 0x15],     0x16
1294     // value is share:                                [0x12,            0x16] =>  valueMaybeSweepableShare
1295     // readonly share:                                                  0x16  =>  return
1296     // sweepable share:                               [0x12, 0x15]            =>  needShareBarrier
1297     // value is not share:  0x08, 0x09, [0x0A, 0x11],                         =>  valueNotShare
1298     // value is young :           0x09                                        =>  needCallNotShare
1299     // value is not young : 0x08,       [0x0A, 0x11],                         =>  checkMark
1300     ASSERT(IN_YOUNG_SPACE < SHARED_SPACE_BEGIN && SHARED_SPACE_BEGIN <= SHARED_SWEEPABLE_SPACE_BEGIN &&
1301            SHARED_SWEEPABLE_SPACE_END < IN_SHARED_READ_ONLY_SPACE && IN_SHARED_READ_ONLY_SPACE == HEAP_SPACE_END);
1302     __ BindAssemblerStub(RTSTUB_ID(ASMFastWriteBarrier));
1303     Label needCall;
1304     Label checkMark;
1305     Label needCallNotShare;
1306     Label needShareBarrier;
1307     Label valueNotShare;
1308     Label valueMaybeSweepableShare;
1309     {
1310         // int8_t *valueRegion = value & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1311         // int8_t valueFlag = *valueRegion
1312         // if (valueFlag >= SHARED_SWEEPABLE_SPACE_BEGIN){
1313         //    goto valueMaybeSweepableShare
1314         // }
1315 
1316         __ And(X15, X3, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1317         // X15 is the region address of value.
1318         __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1319         // X15 is the flag load from region of value.
1320         __ Cmp(Register(X15, W), Immediate(SHARED_SWEEPABLE_SPACE_BEGIN));
1321         __ B(GE, &valueMaybeSweepableShare);
1322         // if value may be SweepableShare, goto valueMaybeSweepableShare
1323     }
1324     __ Bind(&valueNotShare);
1325     {
1326         // valueNotShare:
1327         // if (valueFlag != IN_YOUNG_SPACE){
1328         //      goto checkMark
1329         // }
1330         // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1331         // int8_t objFlag = *objRegion
1332         // if (objFlag != IN_YOUNG_SPACE){
1333         //    goto needCallNotShare
1334         // }
1335 
1336         __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_YOUNG_SPACE));
1337         __ B(NE, &checkMark);
1338         // if value is not in young, goto checkMark
1339 
1340         __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1341         // X15 is the region address of obj.
1342         __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1343         // X15 is the flag load from region of obj.
1344         __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_YOUNG_SPACE));
1345         __ B(NE, &needCallNotShare);
1346         // if obj is not in young, goto needCallNotShare
1347     }
1348 
1349     __ Bind(&checkMark);
1350     {
1351         // checkMark:
1352         // int8_t GCStateBitField = *(glue+GCStateBitFieldOffset)
1353         // if (GCStateBitField & JSThread::CONCURRENT_MARKING_BITFIELD_MASK != 0) {
1354         //    goto needCallNotShare
1355         // }
1356         // return
1357 
1358         __ Mov(X15, JSThread::GlueData::GetGCStateBitFieldOffset(false));
1359         __ Ldrb(Register(X15, W), MemoryOperand(X0, Register(X15), UXTX));
1360         __ Tst(Register(X15, W), LogicalImmediate::Create(JSThread::CONCURRENT_MARKING_BITFIELD_MASK, RegWSize));
1361         __ B(NE, &needCallNotShare);
1362         // if GCState is not READY_TO_MARK, go to needCallNotShare.
1363         __ Ret();
1364     }
1365 
1366     __ Bind(&valueMaybeSweepableShare);
1367     {
1368         // valueMaybeSweepableShare:
1369         // if (valueFlag != IN_SHARED_READ_ONLY_SPACE){
1370         //    goto needShareBarrier
1371         // }
1372         // return
1373         __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE));
1374         __ B(NE, &needShareBarrier);
1375         __ Ret();
1376     }
1377 
1378     __ Bind(&needCallNotShare);
1379     {
1380         int32_t NonSValueBarrier = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
1381             kungfu::CommonStubCSigns::SetNonSValueWithBarrier * FRAME_SLOT_SIZE;
1382         __ Mov(X15, NonSValueBarrier);
1383     }
1384     __ Bind(&needCall);
1385     {
1386         __ Ldr(X15, MemoryOperand(X0, Register(X15), UXTX));
1387         PreserveMostCall(assembler);
1388     }
1389     __ Bind(&needShareBarrier);
1390     {
1391         ASMFastSharedWriteBarrier(assembler, needCall);
1392     }
1393 }
1394 
1395 // %x0 - glue
1396 // %x1 - obj
1397 // %x2 - offset
1398 // %x3 - value
ASMFastSharedWriteBarrier(ExtendedAssembler * assembler,Label & needCall)1399 void AsmInterpreterCall::ASMFastSharedWriteBarrier(ExtendedAssembler* assembler, Label& needCall)
1400 {
1401     Label checkBarrierForSharedValue;
1402     Label restoreScratchRegister;
1403     Label callSharedBarrier;
1404     {
1405         // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1406         // int8_t objFlag = *objRegion
1407         // if (objFlag >= SHARED_SPACE_BEGIN){
1408         //    // share to share, just check the barrier
1409         //    goto checkBarrierForSharedValue
1410         // }
1411         __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1412         __ Ldrb(Register(X15, W), MemoryOperand(X15, 0));
1413         // X15 is the flag load from region of obj.
1414         __ Cmp(Register(X15, W), Immediate(RegionSpaceFlag::SHARED_SPACE_BEGIN));
1415         __ B(GE, &checkBarrierForSharedValue);  // if objflag >= SHARED_SPACE_BEGIN  => checkBarrierForSharedValue
1416     }
1417     {
1418         // int8_t *objRegion = obj & (~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK))
1419         // int8_t *localToShareSet = *(objRegion + LocalToShareSetOffset)
1420         // if (localToShareSet == 0){
1421         //    goto callSharedBarrier
1422         // }
1423         __ And(X15, X1, LogicalImmediate::Create(~(JSTaggedValue::TAG_MARK | DEFAULT_REGION_MASK), RegXSize));
1424         __ Ldr(X15, MemoryOperand(X15, Region::PackedData::GetLocalToShareSetOffset(false)));
1425         // X15 is localToShareSet for obj region.
1426         __ Cbz({X15, X}, &callSharedBarrier);   // if localToShareSet == 0  => callSharedBarrier
1427     }
1428     {
1429         // X16, X17 will be used as scratch register, spill them.
1430         // the caller will call this function with inline asm, it will not save any registers except x15.
1431         // So we need spill and restore x16, x17 when we need them as scratch register.
1432         {
1433             __ Stp(X16, X17, MemoryOperand(SP, -DOUBLE_SLOT_SIZE, PREINDEX));
1434         }
1435         // int64_t objOffset = obj & DEFAULT_REGION_MASK
1436         // int64_t slotOffset = objOffset + offset
1437         __ And(X16, X1, LogicalImmediate::Create(DEFAULT_REGION_MASK, RegXSize));
1438         __ Add(X16, X16, Operand(Register(X2)));
1439 
1440         // the logic to get mask in stub_builder.cpp
1441         //               [63-------------------------35][34------------------------8][7---3][2-0]
1442         // bitOffset:                                       bbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1443         // bitPerWordMask:                                                               11  111
1444         // indexInWord = And bitoffset bitPerWordMask
1445         // indexInWord:                                                                  cc  ccc
1446         // mask = 1 << indexInWord
1447 
1448         // the logic to test bit set value here:
1449         //               [63-------------------------35][34------------------------8][7---3][2-0]
1450         // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1451         // Ubfm X16 slotOffset 3 7
1452         // indexInWord:                                                                  cc  ccc
1453         __ Ubfm(X17, X16, TAGGED_TYPE_SIZE_LOG, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2 - 1);
1454 
1455         // the logic to get byteIndex in stub_builder.cpp
1456         //               [63-------------------------35][34------------------------8][7---3][2-0]
1457         // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1458         // 1. bitOffsetPtr = LSR TAGGED_TYPE_SIZE_LOG(3) slotOffset
1459         // bitOffsetPtr:     aaaaaaaaaaaaaaaaaaaaaaaaaa  aaabbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1460         // 2. bitOffset = TruncPtrToInt32 bitOffsetPtr
1461         // bitOffset:                                       bbbbbbbbbbbbbbbbbbbbbbbb  bbbcc  ccc
1462         // 3. index = LSR BIT_PER_WORD_LOG2(5) bitOffset
1463         // index:                                                bbbbbbbbbbbbbbbbbbb  bbbbb  bbb
1464         // 4. byteIndex = Mul index BYTE_PER_WORD(4)
1465         // byteIndex:                                          bbbbbbbbbbbbbbbbbbbbb  bbbbb  b00
1466 
1467         // the logic to get byteIndex here:
1468         //               [63-------------------------35][34------------------------8][7---3][2-0]
1469         // slotOffset:    aaaaaaaaaaaaaaaaaaaaaaaaaaaaa  bbbbbbbbbbbbbbbbbbbbbbbbbbb  ccccc  ddd
1470         // Ubfm X16 slotOffset 8 34
1471         // index:                                                bbbbbbbbbbbbbbbbbbb  bbbbb  bbb
1472         __ Ubfm(X16, X16, TAGGED_TYPE_SIZE_LOG + GCBitset::BIT_PER_WORD_LOG2,
1473                 sizeof(uint32_t) * GCBitset::BIT_PER_BYTE + TAGGED_TYPE_SIZE_LOG - 1);
1474         __ Add(X15, X15, Operand(Register(X16), LSL, GCBitset::BYTE_PER_WORD_LOG2));
1475         __ Add(X15, X15, Immediate(RememberedSet::GCBITSET_DATA_OFFSET));
1476         // X15 is the address of bitset value. X15 = X15 + X16 << BYTE_PER_WORD_LOG2 + GCBITSET_DATA_OFFSET
1477 
1478         // mask = 1 << indexInWord
1479         __ Mov(Register(X16, W), 1);
1480         __ Lsl(Register(X17, W), Register(X16, W), Register(X17, W)); // X17 is the mask
1481 
1482         __ Ldr(Register(X16, W), MemoryOperand(X15, 0)); // x16: oldsetValue
1483         __ Tst(Register(X16, W), Register(X17, W));
1484         __ B(NE, &restoreScratchRegister);
1485         __ Orr(Register(X16, W), Register(X16, W), Register(X17, W));
1486         __ Str(Register(X16, W), MemoryOperand(X15, 0));
1487     }
1488     __ Bind(&restoreScratchRegister);
1489     {
1490         __ Ldp(X16, X17, MemoryOperand(SP, DOUBLE_SLOT_SIZE, POSTINDEX));
1491     }
1492     __ Bind(&checkBarrierForSharedValue);
1493     {
1494         // checkBarrierForSharedValue:
1495         // int8_t GCStateBitField = *(glue+SharedGCStateBitFieldOffset)
1496         // if (GCStateBitField & JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK != 0) {
1497         //    goto callSharedBarrier
1498         // }
1499         // return
1500         __ Mov(X15, JSThread::GlueData::GetSharedGCStateBitFieldOffset(false));
1501         __ Ldrb(Register(X15, W), MemoryOperand(X0, Register(X15), UXTX));
1502         static_assert(JSThread::SHARED_CONCURRENT_MARKING_BITFIELD_MASK == 1 && "Tbnz can't handle other bit mask");
1503         __ Tbnz(Register(X15, W), 0, &callSharedBarrier);
1504         // if GCState is not READY_TO_MARK, go to needCallNotShare.
1505         __ Ret();
1506     }
1507 
1508     __ Bind(&callSharedBarrier);
1509     {
1510         int32_t SValueBarrierOffset = static_cast<int32_t>(JSThread::GlueData::GetCOStubEntriesOffset(false)) +
1511             kungfu::CommonStubCSigns::SetSValueWithBarrier * FRAME_SLOT_SIZE;
1512         __ Mov(X15, SValueBarrierOffset);
1513         __ B(&needCall);
1514     }
1515 }
1516 
1517 // Generate code for generator re-entering asm interpreter
1518 // c++ calling convention
1519 // Input: %X0 - glue
1520 //        %X1 - context(GeneratorContext)
GeneratorReEnterAsmInterp(ExtendedAssembler * assembler)1521 void AsmInterpreterCall::GeneratorReEnterAsmInterp(ExtendedAssembler *assembler)
1522 {
1523     __ BindAssemblerStub(RTSTUB_ID(GeneratorReEnterAsmInterp));
1524     Label target;
1525     size_t begin = __ GetCurrentPosition();
1526     PushAsmInterpEntryFrame(assembler);
1527     __ Bl(&target);
1528     PopAsmInterpEntryFrame(assembler);
1529     size_t end = __ GetCurrentPosition();
1530     if ((end - begin) != FrameCompletionPos::ARM64EntryFrameDuration) {
1531         LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64EntryFrameDuration
1532                             << "This frame has been modified, and the offset EntryFrameDuration should be updated too.";
1533     }
1534     __ Ret();
1535     __ Bind(&target);
1536     {
1537         GeneratorReEnterAsmInterpDispatch(assembler);
1538     }
1539 }
1540 
GeneratorReEnterAsmInterpDispatch(ExtendedAssembler * assembler)1541 void AsmInterpreterCall::GeneratorReEnterAsmInterpDispatch(ExtendedAssembler *assembler)
1542 {
1543     Label pushFrameState;
1544     Label stackOverflow;
1545     Register glue = __ GlueRegister();
1546     Register contextRegister(X1);
1547     Register spRegister(SP);
1548     Register pc(X8);
1549     Register prevSpRegister(FP);
1550     Register callTarget(X4);
1551     Register method(X5);
1552     Register temp(X6); // can not be used to store any variable
1553     Register currentSlotRegister(X7);
1554     Register fpRegister(X9);
1555     Register thisRegister(X25);
1556     Register nRegsRegister(X26, W);
1557     Register regsArrayRegister(X27);
1558     Register newSp(X28);
1559     __ Ldr(callTarget, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_METHOD_OFFSET));
1560     __ Ldr(method, MemoryOperand(callTarget, JSFunctionBase::METHOD_OFFSET));
1561     __ PushFpAndLr();
1562     // save fp
1563     __ Mov(fpRegister, spRegister);
1564     __ Mov(currentSlotRegister, spRegister);
1565     // Reserve enough sp space to prevent stack parameters from being covered by cpu profiler.
1566     __ Ldr(temp, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
1567     __ Mov(Register(SP), temp);
1568     // push context regs
1569     __ Ldr(nRegsRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_NREGS_OFFSET));
1570     __ Ldr(thisRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_THIS_OFFSET));
1571     __ Ldr(regsArrayRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET));
1572     __ Add(regsArrayRegister, regsArrayRegister, Immediate(TaggedArray::DATA_OFFSET));
1573     PushArgsWithArgv(assembler, glue, nRegsRegister, regsArrayRegister, temp,
1574                      currentSlotRegister, &pushFrameState, &stackOverflow);
1575 
1576     __ Bind(&pushFrameState);
1577     __ Mov(newSp, currentSlotRegister);
1578     // push frame state
1579     PushGeneratorFrameState(assembler, prevSpRegister, fpRegister, currentSlotRegister, callTarget, thisRegister,
1580                             method, contextRegister, pc, temp);
1581     __ Align16(currentSlotRegister);
1582     __ Mov(Register(SP), currentSlotRegister);
1583     // call bc stub
1584     CallBCStub(assembler, newSp, glue, callTarget, method, pc, temp);
1585 
1586     __ Bind(&stackOverflow);
1587     {
1588         ThrowStackOverflowExceptionAndReturn(assembler, glue, fpRegister, temp);
1589     }
1590 }
1591 
PushCallThis(ExtendedAssembler * assembler,JSCallMode mode,Label * stackOverflow,FrameTransitionType type)1592 void AsmInterpreterCall::PushCallThis(ExtendedAssembler *assembler,
1593     JSCallMode mode, Label *stackOverflow, FrameTransitionType type)
1594 {
1595     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
1596     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1597     Register thisRegister = __ AvailableRegister2();
1598     Register currentSlotRegister = __ AvailableRegister3();
1599 
1600     Label pushVregs;
1601     Label pushNewTarget;
1602     Label pushCallTarget;
1603     bool haveThis = kungfu::AssemblerModule::JSModeHaveThisArg(mode);
1604     bool haveNewTarget = kungfu::AssemblerModule::JSModeHaveNewTargetArg(mode);
1605     if (!haveThis) {
1606         __ Mov(thisRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));  // default this: undefined
1607     } else {
1608         Register thisArgRegister = GetThisRegsiter(assembler, mode, thisRegister);
1609         if (thisRegister.GetId() != thisArgRegister.GetId()) {
1610             __ Mov(thisRegister, thisArgRegister);
1611         }
1612     }
1613     __ Tst(callFieldRegister, LogicalImmediate::Create(CALL_TYPE_MASK, RegXSize));
1614     __ B(Condition::EQ, &pushVregs);
1615     __ Tbz(callFieldRegister, MethodLiteral::HaveThisBit::START_BIT, &pushNewTarget);
1616     if (!haveThis) {
1617         [[maybe_unused]] TempRegister1Scope scope1(assembler);
1618         Register tempRegister = __ TempRegister1();
1619         __ Mov(tempRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1620         __ Str(tempRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1621     } else {
1622         __ Str(thisRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1623     }
1624     __ Bind(&pushNewTarget);
1625     {
1626         __ Tbz(callFieldRegister, MethodLiteral::HaveNewTargetBit::START_BIT, &pushCallTarget);
1627         if (!haveNewTarget) {
1628             [[maybe_unused]] TempRegister1Scope scope1(assembler);
1629             Register newTarget = __ TempRegister1();
1630             __ Mov(newTarget, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1631             __ Str(newTarget, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1632         } else {
1633             [[maybe_unused]] TempRegister1Scope scope1(assembler);
1634             Register defaultRegister = __ TempRegister1();
1635             Register newTargetRegister = GetNewTargetRegsiter(assembler, mode, defaultRegister);
1636             __ Str(newTargetRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1637         }
1638     }
1639     __ Bind(&pushCallTarget);
1640     {
1641         __ Tbz(callFieldRegister, MethodLiteral::HaveFuncBit::START_BIT, &pushVregs);
1642         __ Str(callTargetRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1643     }
1644     __ Bind(&pushVregs);
1645     {
1646         PushVregs(assembler, stackOverflow, type);
1647     }
1648 }
1649 
PushVregs(ExtendedAssembler * assembler,Label * stackOverflow,FrameTransitionType type)1650 void AsmInterpreterCall::PushVregs(ExtendedAssembler *assembler,
1651     Label *stackOverflow, FrameTransitionType type)
1652 {
1653     Register glue = __ GlueRegister();
1654     Register prevSpRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::SP);
1655     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1656     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1657     Register callFieldRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_FIELD);
1658     Register fpRegister = __ AvailableRegister1();
1659     Register thisRegister = __ AvailableRegister2();
1660     Register currentSlotRegister = __ AvailableRegister3();
1661 
1662     Label pushFrameStateAndCall;
1663     [[maybe_unused]] TempRegister1Scope scope1(assembler);
1664     Register tempRegister = __ TempRegister1();
1665     // args register can be reused now.
1666     Register newSpRegister = __ AvailableRegister4();
1667     Register numVregsRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::ARG1);
1668     GetNumVregsFromCallField(assembler, callFieldRegister, numVregsRegister);
1669     PushUndefinedWithArgc(assembler, glue, numVregsRegister, tempRegister, currentSlotRegister, &pushFrameStateAndCall,
1670         stackOverflow);
1671     // fall through
1672     __ Bind(&pushFrameStateAndCall);
1673     {
1674         __ Mov(newSpRegister, currentSlotRegister);
1675 
1676         [[maybe_unused]] TempRegister2Scope scope2(assembler);
1677         Register pcRegister = __ TempRegister2();
1678         PushFrameState(assembler, prevSpRegister, fpRegister, currentSlotRegister, callTargetRegister, thisRegister,
1679             methodRegister, pcRegister, tempRegister);
1680 
1681         __ Align16(currentSlotRegister);
1682         __ Mov(Register(SP), currentSlotRegister);
1683         if (type == FrameTransitionType::OTHER_TO_BASELINE_CHECK ||
1684             type == FrameTransitionType::BASELINE_TO_BASELINE_CHECK) {
1685             // check baselinecode, temp modify TOOD: need to check
1686             Label baselineCodeUndefined;
1687             __ Ldr(tempRegister, MemoryOperand(callTargetRegister, JSFunction::BASELINECODE_OFFSET));
1688             __ Cmp(tempRegister, Immediate(JSTaggedValue::VALUE_UNDEFINED));
1689             __ B(Condition::EQ, &baselineCodeUndefined);
1690 
1691             // check is compiling
1692             __ Cmp(tempRegister, Immediate(JSTaggedValue::VALUE_HOLE));
1693             __ B(Condition::EQ, &baselineCodeUndefined);
1694 
1695             if (MachineCode::FUNCADDR_OFFSET % 8 == 0) { // 8: imm in 64-bit ldr insn must be a multiple of 8
1696                 __ Ldr(tempRegister, MemoryOperand(tempRegister, MachineCode::FUNCADDR_OFFSET));
1697             } else {
1698                 ASSERT(MachineCode::FUNCADDR_OFFSET < 256); // 256: imm in ldur insn must be in the range -256 to 255
1699                 __ Ldur(tempRegister, MemoryOperand(tempRegister, MachineCode::FUNCADDR_OFFSET));
1700             }
1701             if (glue != X19) {
1702                 __ Mov(X19, glue);
1703             }
1704             if (methodRegister != X21) {
1705                 __ Mov(X21, methodRegister);
1706             }
1707             __ Mov(currentSlotRegister, Immediate(BASELINEJIT_PC_FLAG));
1708             // -3: frame type, prevSp, pc
1709             __ Stur(currentSlotRegister, MemoryOperand(newSpRegister, -3 * FRAME_SLOT_SIZE));
1710             __ Mov(Register(X29), newSpRegister);
1711             __ Br(tempRegister);
1712             __ Bind(&baselineCodeUndefined);
1713         }
1714         DispatchCall(assembler, pcRegister, newSpRegister);
1715     }
1716 }
1717 
1718 // Input: X19 - glue
1719 //        FP - sp
1720 //        X20 - callTarget
1721 //        X21 - method
DispatchCall(ExtendedAssembler * assembler,Register pcRegister,Register newSpRegister,Register accRegister)1722 void AsmInterpreterCall::DispatchCall(ExtendedAssembler *assembler, Register pcRegister,
1723     Register newSpRegister, Register accRegister)
1724 {
1725     Register glueRegister = __ GlueRegister();
1726     Register callTargetRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::CALL_TARGET);
1727     Register methodRegister = __ CallDispatcherArgument(kungfu::CallDispatchInputs::METHOD);
1728 
1729     if (glueRegister.GetId() != X19) {
1730         __ Mov(Register(X19), glueRegister);
1731     }
1732     __ Ldrh(Register(X24, W), MemoryOperand(methodRegister, Method::LITERAL_INFO_OFFSET));
1733     if (accRegister == INVALID_REG) {
1734         __ Mov(Register(X23), Immediate(JSTaggedValue::VALUE_HOLE));
1735     } else {
1736         ASSERT(accRegister == Register(X23));
1737     }
1738     __ Ldr(Register(X22), MemoryOperand(callTargetRegister, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
1739     __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));
1740     __ Ldr(Register(X21), MemoryOperand(methodRegister, Method::CONSTANT_POOL_OFFSET));
1741     __ Mov(Register(X20), pcRegister);
1742     __ Mov(Register(FP), newSpRegister);
1743 
1744     Register bcIndexRegister = __ AvailableRegister1();
1745     Register tempRegister = __ AvailableRegister2();
1746     __ Ldrb(bcIndexRegister.W(), MemoryOperand(pcRegister, 0));
1747     __ Add(tempRegister, glueRegister, Operand(bcIndexRegister.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1748     __ Ldr(tempRegister, MemoryOperand(tempRegister, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1749     __ Br(tempRegister);
1750 }
1751 
PushFrameState(ExtendedAssembler * assembler,Register prevSp,Register fp,Register currentSlot,Register callTarget,Register thisObj,Register method,Register pc,Register op)1752 void AsmInterpreterCall::PushFrameState(ExtendedAssembler *assembler, Register prevSp, Register fp,
1753     Register currentSlot, Register callTarget, Register thisObj, Register method, Register pc, Register op)
1754 {
1755     __ Mov(op, Immediate(static_cast<int32_t>(FrameType::ASM_INTERPRETER_FRAME)));
1756     __ Stp(prevSp, op, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX)); // -2: frame type & prevSp
1757     __ Ldr(pc, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1758     __ Stp(fp, pc, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX)); // -2: pc & fp
1759     __ Ldr(op, MemoryOperand(callTarget, JSFunction::LEXICAL_ENV_OFFSET));
1760     __ Stp(op, Register(Zero), MemoryOperand(currentSlot,
1761                                              -2 * FRAME_SLOT_SIZE, // -2: jumpSizeAfterCall & env
1762                                              AddrMode::PREINDEX));
1763     __ Mov(op, Immediate(JSTaggedValue::VALUE_HOLE));
1764     __ Stp(thisObj, op, MemoryOperand(currentSlot, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));    // -2: acc & this
1765     __ Str(callTarget, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));         // -1: callTarget
1766 }
1767 
GetNumVregsFromCallField(ExtendedAssembler * assembler,Register callField,Register numVregs)1768 void AsmInterpreterCall::GetNumVregsFromCallField(ExtendedAssembler *assembler, Register callField, Register numVregs)
1769 {
1770     __ Mov(numVregs, callField);
1771     __ Lsr(numVregs, numVregs, MethodLiteral::NumVregsBits::START_BIT);
1772     __ And(numVregs.W(), numVregs.W(), LogicalImmediate::Create(
1773         MethodLiteral::NumVregsBits::Mask() >> MethodLiteral::NumVregsBits::START_BIT, RegWSize));
1774 }
1775 
GetDeclaredNumArgsFromCallField(ExtendedAssembler * assembler,Register callField,Register declaredNumArgs)1776 void AsmInterpreterCall::GetDeclaredNumArgsFromCallField(ExtendedAssembler *assembler, Register callField,
1777     Register declaredNumArgs)
1778 {
1779     __ Mov(declaredNumArgs, callField);
1780     __ Lsr(declaredNumArgs, declaredNumArgs, MethodLiteral::NumArgsBits::START_BIT);
1781     __ And(declaredNumArgs.W(), declaredNumArgs.W(), LogicalImmediate::Create(
1782         MethodLiteral::NumArgsBits::Mask() >> MethodLiteral::NumArgsBits::START_BIT, RegWSize));
1783 }
1784 
PushAsmInterpEntryFrame(ExtendedAssembler * assembler)1785 void AsmInterpreterCall::PushAsmInterpEntryFrame(ExtendedAssembler *assembler)
1786 {
1787     Register glue = __ GlueRegister();
1788     Register fp(X29);
1789     Register sp(SP);
1790 
1791     size_t begin = __ GetCurrentPosition();
1792     if (!assembler->FromInterpreterHandler()) {
1793         __ CalleeSave();
1794     }
1795 
1796     [[maybe_unused]] TempRegister1Scope scope1(assembler);
1797     Register prevFrameRegister = __ TempRegister1();
1798     [[maybe_unused]] TempRegister2Scope scope2(assembler);
1799     Register frameTypeRegister = __ TempRegister2();
1800 
1801     __ PushFpAndLr();
1802 
1803     // prev managed fp is leave frame or nullptr(the first frame)
1804     __ Ldr(prevFrameRegister, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1805     __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_ENTRY_FRAME)));
1806     // 2 : prevSp & frame type
1807     __ Stp(prevFrameRegister, frameTypeRegister, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1808     // 2 : pc & glue
1809     __ Stp(glue, Register(Zero), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // pc
1810     if (!assembler->FromInterpreterHandler()) {
1811         size_t end = __ GetCurrentPosition();
1812         if ((end - begin) != FrameCompletionPos::ARM64CppToAsmInterp) {
1813             LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64CppToAsmInterp
1814                                 << "This frame has been modified, and the offset CppToAsmInterp should be updated too.";
1815         }
1816     }
1817     __ Add(fp, sp, Immediate(4 * FRAME_SLOT_SIZE));  // 4: 32 means skip frame type, prevSp, pc and glue
1818 }
1819 
PopAsmInterpEntryFrame(ExtendedAssembler * assembler)1820 void AsmInterpreterCall::PopAsmInterpEntryFrame(ExtendedAssembler *assembler)
1821 {
1822     Register sp(SP);
1823 
1824     [[maybe_unused]] TempRegister1Scope scope1(assembler);
1825     Register prevFrameRegister = __ TempRegister1();
1826     [[maybe_unused]] TempRegister2Scope scope2(assembler);
1827     Register glue = __ TempRegister2();
1828     // 2: glue & pc
1829     __ Ldp(glue, Register(Zero), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
1830     // 2: skip frame type & prev
1831     __ Ldp(prevFrameRegister, Register(Zero), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
1832     __ Str(prevFrameRegister, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
1833     size_t begin = __ GetCurrentPosition();
1834     __ RestoreFpAndLr();
1835     if (!assembler->FromInterpreterHandler()) {
1836         __ CalleeRestore();
1837         size_t end = __ GetCurrentPosition();
1838         if ((end - begin) != FrameCompletionPos::ARM64AsmInterpToCpp) {
1839             LOG_COMPILER(FATAL) << (end - begin) << " != " << FrameCompletionPos::ARM64AsmInterpToCpp
1840                                 << "This frame has been modified, and the offset AsmInterpToCpp should be updated too.";
1841         }
1842     }
1843 }
1844 
PushGeneratorFrameState(ExtendedAssembler * assembler,Register & prevSpRegister,Register & fpRegister,Register & currentSlotRegister,Register & callTargetRegister,Register & thisRegister,Register & methodRegister,Register & contextRegister,Register & pcRegister,Register & operatorRegister)1845 void AsmInterpreterCall::PushGeneratorFrameState(ExtendedAssembler *assembler, Register &prevSpRegister,
1846     Register &fpRegister, Register &currentSlotRegister, Register &callTargetRegister, Register &thisRegister,
1847     Register &methodRegister, Register &contextRegister, Register &pcRegister, Register &operatorRegister)
1848 {
1849     __ Mov(operatorRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_FRAME)));
1850     __ Stp(prevSpRegister, operatorRegister,
1851         MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // 2 : frameType and prevSp
1852     __ Ldr(pcRegister, MemoryOperand(methodRegister, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1853     // offset need 8 align, GENERATOR_NREGS_OFFSET instead of GENERATOR_BC_OFFSET_OFFSET
1854     __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_NREGS_OFFSET));
1855     // 32: get high 32bit
1856     __ Lsr(operatorRegister, operatorRegister, 32);
1857     __ Add(pcRegister, operatorRegister, pcRegister);
1858     // 2 : pc and fp
1859     __ Stp(fpRegister, pcRegister, MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1860     // jumpSizeAfterCall
1861     __ Str(Register(Zero), MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1862     __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_LEXICALENV_OFFSET));
1863     // env
1864     __ Str(operatorRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1865     __ Ldr(operatorRegister, MemoryOperand(contextRegister, GeneratorContext::GENERATOR_ACC_OFFSET));
1866     // acc
1867     __ Str(operatorRegister, MemoryOperand(currentSlotRegister, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1868     __ Stp(callTargetRegister, thisRegister,
1869         MemoryOperand(currentSlotRegister, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));  // 2 : acc and callTarget
1870 }
1871 
CallBCStub(ExtendedAssembler * assembler,Register & newSp,Register & glue,Register & callTarget,Register & method,Register & pc,Register & temp)1872 void AsmInterpreterCall::CallBCStub(ExtendedAssembler *assembler, Register &newSp, Register &glue,
1873     Register &callTarget, Register &method, Register &pc, Register &temp)
1874 {
1875     // prepare call entry
1876     __ Mov(Register(X19), glue);    // X19 - glue
1877     __ Mov(Register(FP), newSp);    // FP - sp
1878     __ Mov(Register(X20), pc);      // X20 - pc
1879     __ Ldr(Register(X21), MemoryOperand(method, Method::CONSTANT_POOL_OFFSET));   // X21 - constantpool
1880     __ Ldr(Register(X22), MemoryOperand(callTarget, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET));
1881     __ Ldr(Register(X22), MemoryOperand(Register(X22), ProfileTypeInfoCell::VALUE_OFFSET));  // X22 - profileTypeInfo
1882     __ Mov(Register(X23), Immediate(JSTaggedValue::Hole().GetRawData()));                   // X23 - acc
1883     __ Ldr(Register(X24), MemoryOperand(method, Method::LITERAL_INFO_OFFSET)); // X24 - hotnessCounter
1884 
1885     // call the first bytecode handler
1886     __ Ldrb(temp.W(), MemoryOperand(pc, 0));
1887     // 3 : 3 means *8
1888     __ Add(temp, glue, Operand(temp.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1889     __ Ldr(temp, MemoryOperand(temp, JSThread::GlueData::GetBCStubEntriesOffset(false)));
1890     __ Br(temp);
1891 }
1892 
CallNativeEntry(ExtendedAssembler * assembler,bool isJsProxy)1893 void AsmInterpreterCall::CallNativeEntry(ExtendedAssembler *assembler, bool isJsProxy)
1894 {
1895     Label callFastBuiltin;
1896     Label callNativeBuiltin;
1897     Register glue(X0);
1898     Register argv(X5);
1899     Register function(X1);
1900     Register nativeCode(X7);
1901     Register temp(X9);
1902     // get native pointer
1903     if (isJsProxy) {
1904         Register method(X2);
1905         __ Ldr(nativeCode, MemoryOperand(method, Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET));
1906     } else {
1907         Register callFieldRegister(X3);
1908         __ Ldr(nativeCode, MemoryOperand(function, JSFunctionBase::CODE_ENTRY_OFFSET));
1909         __ Tbnz(callFieldRegister, MethodLiteral::IsFastBuiltinBit::START_BIT, &callFastBuiltin);
1910     }
1911 
1912     __ Bind(&callNativeBuiltin);
1913     Register sp(SP);
1914     // 2: function & align
1915     __ Stp(function, Register(Zero), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
1916     // 2: skip argc & thread
1917     __ Sub(sp, sp, Immediate(2 * FRAME_SLOT_SIZE));
1918     PushBuiltinFrame(assembler, glue, FrameType::BUILTIN_ENTRY_FRAME, temp, argv);
1919     __ Mov(temp, argv);
1920     __ Sub(Register(X0), temp, Immediate(2 * FRAME_SLOT_SIZE));  // 2: skip argc & thread
1921     CallNativeInternal(assembler, nativeCode);
1922 
1923     // 4: skip function
1924     __ Add(sp, sp, Immediate(4 * FRAME_SLOT_SIZE));
1925     __ Ret();
1926 
1927     __ Bind(&callFastBuiltin);
1928     CallFastBuiltin(assembler, &callNativeBuiltin);
1929 }
1930 
CallFastBuiltin(ExtendedAssembler * assembler,Label * callNativeBuiltin)1931 void AsmInterpreterCall::CallFastBuiltin(ExtendedAssembler *assembler, Label *callNativeBuiltin)
1932 {
1933     Label lCall1;
1934     Label lCall2;
1935     Label lCall3;
1936     Label callEntry;
1937     Register sp(SP);
1938     Register glue(X0);
1939     Register function(X1);
1940     Register method(X2);
1941     Register argc(X4);
1942     Register argv(X5);
1943     Register nativeCode(X7);
1944 
1945     Register builtinId = __ AvailableRegister1();
1946     Register temp = __ AvailableRegister2();
1947     // get builtinid
1948     __ Ldr(builtinId, MemoryOperand(method, Method::EXTRA_LITERAL_INFO_OFFSET));  // get extra literal
1949     __ And(builtinId.W(), builtinId.W(), LogicalImmediate::Create(0xff, RegWSize));
1950     __ Cmp(builtinId.W(), Immediate(kungfu::BuiltinsStubCSigns::BUILTINS_CONSTRUCTOR_STUB_FIRST));
1951     __ B(Condition::GE, callNativeBuiltin);
1952 
1953     __ Cmp(argc, Immediate(3)); // 3: number of args
1954     __ B(Condition::HI, callNativeBuiltin);
1955 
1956     // get builtin func addr
1957     __ Add(builtinId, glue, Operand(builtinId.W(), UXTW, FRAME_SLOT_SIZE_LOG2));
1958     __ Ldr(builtinId, MemoryOperand(builtinId, JSThread::GlueData::GetBuiltinsStubEntriesOffset(false)));
1959     // create frame
1960     PushAsmBridgeFrame(assembler);
1961     __ Mov(temp, function);
1962     __ Mov(X1, nativeCode);
1963     __ Mov(X2, temp);
1964     __ Mov(temp, argv);
1965     __ Mov(X5, argc);
1966     __ Ldr(X3, MemoryOperand(temp, FRAME_SLOT_SIZE));
1967     __ Ldr(X4, MemoryOperand(temp, DOUBLE_SLOT_SIZE));
1968 
1969     __ Cmp(Register(X5), Immediate(0));
1970     __ B(Condition::NE, &lCall1);
1971     __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1972     __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1973     __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1974     __ B(&callEntry);
1975 
1976     __ Bind(&lCall1);
1977     {
1978         __ Cmp(Register(X5), Immediate(1));
1979         __ B(Condition::NE, &lCall2);
1980         __ Ldr(Register(X6), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
1981         __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));  // reset x7
1982         __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1983         __ B(&callEntry);
1984     }
1985 
1986     __ Bind(&lCall2);
1987     {
1988         __ Cmp(Register(X5), Immediate(2)); // 2: number of args
1989         __ B(Condition::NE, &lCall3);
1990         __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED));
1991         __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
1992         __ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE));
1993         __ B(&callEntry);
1994     }
1995 
1996     __ Bind(&lCall3);
1997     {
1998         __ Ldr(Register(X7), MemoryOperand(temp, QUINTUPLE_SLOT_SIZE));
1999         __ Stp(Register(X7), Register(X7), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX));
2000         __ Ldp(Register(X6), Register(X7), MemoryOperand(temp, TRIPLE_SLOT_SIZE));  // get arg0 arg1
2001         __ B(&callEntry);
2002     }
2003 
2004     __ Bind(&callEntry);
2005     {
2006         __ Blr(builtinId);
2007         __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE));
2008     }
2009     PopAsmBridgeFrame(assembler);
2010     __ Ret();
2011 }
2012 
ThrowStackOverflowExceptionAndReturn(ExtendedAssembler * assembler,Register glue,Register fp,Register op)2013 void AsmInterpreterCall::ThrowStackOverflowExceptionAndReturn(ExtendedAssembler *assembler, Register glue,
2014     Register fp, Register op)
2015 {
2016     if (fp != Register(SP)) {
2017         __ Mov(Register(SP), fp);
2018     }
2019     __ Mov(op, Immediate(kungfu::RuntimeStubCSigns::ID_ThrowStackOverflowException));
2020     // 3 : 3 means *8
2021     __ Add(op, glue, Operand(op, LSL, 3));
2022     __ Ldr(op, MemoryOperand(op, JSThread::GlueData::GetRTStubEntriesOffset(false)));
2023     if (glue.GetId() != X0) {
2024         __ Mov(Register(X0), glue);
2025     }
2026     __ Blr(op);
2027     __ RestoreFpAndLr();
2028     __ Ret();
2029 }
2030 #undef __
2031 }  // panda::ecmascript::aarch64