• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/trampoline/aarch64/common_call.h"
17 
18 #include "ecmascript/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, &copyArgs);
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(&copyArgs);
134     }
135     __ Bind(&copyArgs);
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