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/compiler/assembler/assembler.h"
19 #include "ecmascript/compiler/argument_accessor.h"
20 #include "ecmascript/compiler/rt_call_signature.h"
21 #include "ecmascript/ecma_runtime_call_info.h"
22 #include "ecmascript/frames.h"
23 #include "ecmascript/js_function.h"
24 #include "ecmascript/js_thread.h"
25 #include "ecmascript/js_generator_object.h"
26 #include "ecmascript/message_string.h"
27 #include "ecmascript/method.h"
28 #include "ecmascript/runtime_call_id.h"
29
30 namespace panda::ecmascript::aarch64 {
31 using Label = panda::ecmascript::Label;
32 #define __ assembler->
33
PushAsmInterpBridgeFrame(ExtendedAssembler * assembler)34 void CommonCall::PushAsmInterpBridgeFrame(ExtendedAssembler *assembler)
35 {
36 Register fp(X29);
37 Register sp(SP);
38
39 [[maybe_unused]] TempRegister1Scope scope1(assembler);
40 Register frameTypeRegister = __ TempRegister1();
41
42 __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
43 // 2 : return addr & frame type
44 __ Stp(frameTypeRegister, Register(X30), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
45 // 2 : prevSp & pc
46 __ Stp(Register(Zero), Register(FP), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
47 __ Add(fp, sp, Immediate(24)); // 24: skip frame type, prevSp, pc
48
49 if (!assembler->FromInterpreterHandler()) {
50 __ CalleeSave();
51 }
52 }
53
PopAsmInterpBridgeFrame(ExtendedAssembler * assembler)54 void CommonCall::PopAsmInterpBridgeFrame(ExtendedAssembler *assembler)
55 {
56 Register sp(SP);
57
58 if (!assembler->FromInterpreterHandler()) {
59 __ CalleeRestore();
60 }
61 // 2: prevSp & pc
62 __ Ldp(Register(Zero), Register(FP), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
63 // 2: return addr & frame type
64 __ Ldp(Register(Zero), Register(X30), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
65 }
66
67
PushLeaveFrame(ExtendedAssembler * assembler,Register glue)68 void CommonCall::PushLeaveFrame(ExtendedAssembler *assembler, Register glue)
69 {
70 TempRegister2Scope temp2Scope(assembler);
71 Register frameType = __ TempRegister2();
72 Register currentSp(X6);
73 Register sp(SP);
74
75 // construct leave frame
76 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
77 __ PushFpAndLr();
78 // 2 : 2 means pairs
79 __ Stp(Register(X19), frameType, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
80 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
81 // save to thread currentLeaveFrame_;
82 __ Str(Register(FP), MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
83 }
84
85
PopLeaveFrame(ExtendedAssembler * assembler)86 void CommonCall::PopLeaveFrame(ExtendedAssembler *assembler)
87 {
88 Register sp(SP);
89 Register currentSp(X6);
90 TempRegister2Scope temp2Scope(assembler);
91 Register frameType = __ TempRegister2();
92 // 2 : 2 means pairs
93 __ Ldp(Register(X19), frameType, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
94 __ RestoreFpAndLr();
95 }
96
PushArgsWithArgv(ExtendedAssembler * assembler,Register glue,Register argc,Register argv,Register op,Register currentSlot,Label * next,Label * stackOverflow)97 void CommonCall::PushArgsWithArgv(ExtendedAssembler *assembler, Register glue, Register argc,
98 Register argv, Register op, Register currentSlot, Label *next, Label *stackOverflow)
99 {
100 Label loopBeginning;
101 if (next != nullptr) {
102 __ Cmp(argc.W(), Immediate(0));
103 __ B(Condition::LS, next);
104 }
105 if (stackOverflow != nullptr) {
106 StackOverflowCheck(assembler, glue, currentSlot, argc, op, stackOverflow);
107 }
108 __ Add(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
109 __ Bind(&loopBeginning);
110 __ Ldr(op, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX)); // -8: 8 bytes
111 __ Str(op, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, PREINDEX)); // -8: 8 bytes
112 __ Sub(argc.W(), argc.W(), Immediate(1));
113 __ Cbnz(argc.W(), &loopBeginning);
114 }
115
PushArgsWithArgvInPair(ExtendedAssembler * assembler,Register argc,Register argv,Register padding,Register op1,Register op2,Label * next)116 void CommonCall::PushArgsWithArgvInPair(ExtendedAssembler *assembler, Register argc,
117 Register argv, Register padding, Register op1, Register op2, Label *next)
118 {
119 Register sp(SP);
120 if (next != nullptr) {
121 __ Cmp(argc.W(), Immediate(0));
122 __ B(Condition::LS, next);
123 }
124
125 Label copyArgs;
126 __ Tbnz(argc, 0, ©Args);
127 {
128 __ Add(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
129 __ Ldr(op1, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
130 __ Stp(op1, Register(Zero), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
131 __ Sub(argc.W(), argc.W(), Immediate(1)); // 1: push the top arg already
132 __ Sub(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
133 __ B(©Args);
134 }
135 __ Bind(©Args);
136 {
137 Label loopBeginning;
138 Label pushPadding;
139 __ Add(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
140
141 __ Cmp(argc.W(), Immediate(1)); // 1: argc is odd number in copyArgs
142 __ B(Condition::LS, &pushPadding);
143
144 __ Bind(&loopBeginning);
145 __ Ldp(op1, op2, MemoryOperand(argv, -DOUBLE_SLOT_SIZE, PREINDEX));
146 __ Stp(op1, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
147 __ Sub(argc.W(), argc.W(), Immediate(2)); // 2: pair
148 __ Cmp(argc.W(), Immediate(1)); // 1: argc is odd number in copyArgs
149 __ B(Condition::HI, &loopBeginning);
150
151 __ Bind(&pushPadding);
152 __ Ldr(op2, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
153 __ Stp(padding, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
154 if (next != nullptr) {
155 __ B(next);
156 }
157 }
158 }
159
PushUndefinedWithArgc(ExtendedAssembler * assembler,Register glue,Register argc,Register temp,Register currentSlot,Label * next,Label * stackOverflow)160 void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register glue, Register argc, Register temp,
161 Register currentSlot, Label *next, Label *stackOverflow)
162 {
163 if (next != nullptr) {
164 __ Cmp(argc.W(), Immediate(0));
165 __ B(Condition::LE, next);
166 }
167 if (stackOverflow != nullptr) {
168 StackOverflowCheck(assembler, glue, currentSlot, argc, temp, stackOverflow);
169 }
170 Label loopBeginning;
171 __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
172 __ Bind(&loopBeginning);
173 __ Str(temp, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
174 __ Sub(argc.W(), argc.W(), Immediate(1));
175 __ Cbnz(argc.W(), &loopBeginning);
176 }
177
StackOverflowCheck(ExtendedAssembler * assembler,Register glue,Register currentSlot,Register numArgs,Register op,Label * stackOverflow)178 void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register currentSlot,
179 Register numArgs, Register op, Label *stackOverflow)
180 {
181 __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
182 Label skipThrow;
183 __ Sub(op, currentSlot, Operand(op, UXTX, 0));
184 __ Cmp(op, Operand(numArgs, LSL, 3)); // 3: each args occupies 8 bytes
185 __ B(Condition::GT, &skipThrow);
186 __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetAllowCrossThreadExecutionOffset(false)));
187 __ Cbz(op, stackOverflow);
188 __ Bind(&skipThrow);
189 }
190 #undef __
191 } // panda::ecmascript::aarch64