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, ¬JSFunction);
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(¬JSFunction);
84 {
85 __ Tst(bitFieldRegister,
86 LogicalImmediate::Create(static_cast<int64_t>(1ULL << JSHClass::CallableBit::START_BIT), RegXSize));
87 __ B(Condition::EQ, ¬Callable);
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(¬Callable);
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, ¬Undefined);
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(¬Undefined);
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, ¬EcmaObject);
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, ¬EcmaObject);
762 __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
763 __ B(Condition::LO, ¬EcmaObject);
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(¬EcmaObject);
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, ¬Undefined);
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(¬Undefined);
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, ¬EcmaObject);
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, ¬EcmaObject);
878 __ Cmp(temp.W(), Immediate(static_cast<int64_t>(JSType::ECMA_OBJECT_FIRST)));
879 __ B(Condition::LO, ¬EcmaObject);
880 // acc is ecma object
881 __ B(&normalReturn);
882
883 __ Bind(¬EcmaObject);
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 ¤tSlotRegister, 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