1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #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/common_stubs.h"
21 #include "ecmascript/compiler/rt_call_signature.h"
22 #include "ecmascript/ecma_runtime_call_info.h"
23 #include "ecmascript/frames.h"
24 #include "ecmascript/js_function.h"
25 #include "ecmascript/js_thread.h"
26 #include "ecmascript/js_generator_object.h"
27 #include "ecmascript/message_string.h"
28 #include "ecmascript/method.h"
29 #include "ecmascript/runtime_call_id.h"
30
31 namespace panda::ecmascript::aarch64 {
32 using Label = panda::ecmascript::Label;
33 #define __ assembler->
34
PushAsmInterpBridgeFrame(ExtendedAssembler * assembler)35 void CommonCall::PushAsmInterpBridgeFrame(ExtendedAssembler *assembler)
36 {
37 Register fp(X29);
38 Register sp(SP);
39
40 [[maybe_unused]] TempRegister1Scope scope1(assembler);
41 Register frameTypeRegister = __ TempRegister1();
42
43 __ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
44 // 2 : return addr & frame type
45 __ Stp(frameTypeRegister, Register(X30), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
46 // 2 : prevSp & pc
47 __ Stp(Register(Zero), Register(FP), MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
48 __ Add(fp, sp, Immediate(24)); // 24: skip frame type, prevSp, pc
49
50 if (!assembler->FromInterpreterHandler()) {
51 __ CalleeSave();
52 }
53 }
54
PopAsmInterpBridgeFrame(ExtendedAssembler * assembler)55 void CommonCall::PopAsmInterpBridgeFrame(ExtendedAssembler *assembler)
56 {
57 Register sp(SP);
58
59 if (!assembler->FromInterpreterHandler()) {
60 __ CalleeRestore();
61 }
62 // 2: prevSp & pc
63 __ Ldp(Register(Zero), Register(FP), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
64 // 2: return addr & frame type
65 __ Ldp(Register(Zero), Register(X30), MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
66 }
67
68
PushLeaveFrame(ExtendedAssembler * assembler,Register glue)69 void CommonCall::PushLeaveFrame(ExtendedAssembler *assembler, Register glue)
70 {
71 TempRegister2Scope temp2Scope(assembler);
72 Register frameType = __ TempRegister2();
73 Register currentSp(X6);
74 Register sp(SP);
75
76 // construct leave frame
77 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
78 __ PushFpAndLr();
79 // 2 : 2 means pairs
80 __ Stp(Register(X19), frameType, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
81 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE));
82 // save to thread currentLeaveFrame_;
83 __ Str(Register(FP), MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
84 }
85
86
PopLeaveFrame(ExtendedAssembler * assembler)87 void CommonCall::PopLeaveFrame(ExtendedAssembler *assembler)
88 {
89 Register sp(SP);
90 Register currentSp(X6);
91 TempRegister2Scope temp2Scope(assembler);
92 Register frameType = __ TempRegister2();
93 // 2 : 2 means pairs
94 __ Ldp(Register(X19), frameType, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
95 __ RestoreFpAndLr();
96 }
97
PushArgsWithArgv(ExtendedAssembler * assembler,Register glue,Register argc,Register argv,Register op,Register currentSlot,Label * next,Label * stackOverflow)98 void CommonCall::PushArgsWithArgv(ExtendedAssembler *assembler, Register glue, Register argc,
99 Register argv, Register op, Register currentSlot, Label *next, Label *stackOverflow)
100 {
101 Label loopBeginning;
102 if (next != nullptr) {
103 __ Cmp(argc.W(), Immediate(0));
104 __ B(Condition::LS, next);
105 }
106 if (stackOverflow != nullptr) {
107 StackOverflowCheck(assembler, glue, currentSlot, argc, op, stackOverflow);
108 }
109 __ Add(argv, argv, Operand(argc.W(), UXTW, 3)); // 3: argc * 8
110 __ Bind(&loopBeginning);
111 __ Ldr(op, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX)); // -8: 8 bytes
112 __ Str(op, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, PREINDEX)); // -8: 8 bytes
113 __ Sub(argc.W(), argc.W(), Immediate(1));
114 __ Cbnz(argc.W(), &loopBeginning);
115 }
116
PushUndefinedWithArgc(ExtendedAssembler * assembler,Register glue,Register argc,Register temp,Register currentSlot,Label * next,Label * stackOverflow)117 void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register glue, Register argc, Register temp,
118 Register currentSlot, Label *next, Label *stackOverflow)
119 {
120 if (next != nullptr) {
121 __ Cmp(argc.W(), Immediate(0));
122 __ B(Condition::LE, next);
123 }
124 if (stackOverflow != nullptr) {
125 StackOverflowCheck(assembler, glue, currentSlot, argc, temp, stackOverflow);
126 }
127 Label loopBeginning;
128 __ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
129 __ Bind(&loopBeginning);
130 __ Str(temp, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
131 __ Sub(argc.W(), argc.W(), Immediate(1));
132 __ Cbnz(argc.W(), &loopBeginning);
133 }
134
StackOverflowCheck(ExtendedAssembler * assembler,Register glue,Register currentSlot,Register numArgs,Register op,Label * stackOverflow)135 void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register currentSlot,
136 Register numArgs, Register op, Label *stackOverflow)
137 {
138 __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
139 Label skipThrow;
140 __ Sub(op, currentSlot, Operand(op, UXTX, 0));
141 __ Cmp(op, Operand(numArgs, LSL, 3)); // 3: each args occupies 8 bytes
142 __ B(Condition::GT, &skipThrow);
143 __ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetAllowCrossThreadExecutionOffset(false)));
144 __ Cbz(op, stackOverflow);
145 __ Bind(&skipThrow);
146 }
147 #undef __
148 } // panda::ecmascript::aarch64