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 30namespace panda::ecmascript::aarch64 { 31using Label = panda::ecmascript::Label; 32#define __ assembler-> 33 34void 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 54void 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 68void 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 86void 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 97void 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 116void 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 160void 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 178void 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 191void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler) 192{ 193 Register sp(SP); 194 TempRegister2Scope temp2Scope(assembler); 195 Register frameType = __ TempRegister2(); 196 __ PushFpAndLr(); 197 // construct frame 198 __ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME))); 199 // 2 : 2 means pairs. X19 means calleesave and 16bytes align 200 __ Stp(Register(X19), frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX)); 201 __ Add(Register(FP), sp, Immediate(DOUBLE_SLOT_SIZE)); 202} 203 204void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler) 205{ 206 TempRegister2Scope temp2Scope(assembler); 207 Register sp(SP); 208 Register frameType = __ TempRegister2(); 209 // 2 : 2 means pop call site sp and type 210 __ Ldp(Register(X19), frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX)); 211 __ RestoreFpAndLr(); 212} 213#undef __ 214} // panda::ecmascript::aarch64