* Copyright (c) 2022-2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/compiler/trampoline/aarch64/common_call.h"
#include "ecmascript/runtime_call_id.h"
namespace panda::ecmascript::aarch64 {
using Label = panda::ecmascript::Label;
#define __ assembler->
void CommonCall::PushAsmInterpBridgeFrame(ExtendedAssembler *assembler)
{
[[maybe_unused]] TempRegister1Scope scope1(assembler);
Register frameTypeRegister = __ TempRegister1();
__ Mov(frameTypeRegister, Immediate(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME)));
__ Stp(frameTypeRegister, x30, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
__ Stp(xzr, fp, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
__ Add(fp, sp, Immediate(24));
if (!assembler->FromInterpreterHandler()) {
__ CalleeSave();
}
}
void CommonCall::PopAsmInterpBridgeFrame(ExtendedAssembler *assembler)
{
if (!assembler->FromInterpreterHandler()) {
#ifdef ENABLE_CMC_IR_FIX_REGISTER
__ CalleeRestoreNoReservedRegister();
#else
__ CalleeRestore();
#endif
}
__ Ldp(xzr, fp, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
__ Ldp(xzr, x30, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
}
void CommonCall::PushLeaveFrame(ExtendedAssembler *assembler, Register glue)
{
TempRegister2Scope temp2Scope(assembler);
Register frameType = __ TempRegister2();
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::LEAVE_FRAME)));
__ PushFpAndLr();
__ Stp(x19, frameType, MemoryOperand(sp, -2 * FRAME_SLOT_SIZE, AddrMode::PREINDEX));
__ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
__ Str(fp, MemoryOperand(glue, JSThread::GlueData::GetLeaveFrameOffset(false)));
}
void CommonCall::PopLeaveFrame(ExtendedAssembler *assembler)
{
TempRegister2Scope temp2Scope(assembler);
Register frameType = __ TempRegister2();
__ Ldp(x19, frameType, MemoryOperand(sp, 2 * FRAME_SLOT_SIZE, AddrMode::POSTINDEX));
__ RestoreFpAndLr();
}
void CommonCall::PushArgsWithArgv(ExtendedAssembler *assembler, Register glue, Register argc,
Register argv, Register op, Register currentSlot, Label *next, Label *stackOverflow)
{
Label loopBeginning;
if (next != nullptr) {
__ Cmp(argc.W(), Immediate(0));
__ B(Condition::LS, next);
}
if (stackOverflow != nullptr) {
StackOverflowCheck(assembler, glue, currentSlot, argc, op, stackOverflow);
}
__ Add(argv, argv, Operand(argc.W(), UXTW, 3));
__ Bind(&loopBeginning);
__ Ldr(op, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
__ Str(op, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, PREINDEX));
__ Sub(argc.W(), argc.W(), Immediate(1));
__ Cbnz(argc.W(), &loopBeginning);
}
void CommonCall::PushArgsWithArgvInPair(ExtendedAssembler *assembler, Register argc,
Register argv, Register padding, Register op1, Register op2, Label *next)
{
if (next != nullptr) {
__ Cmp(argc.W(), Immediate(0));
__ B(Condition::LS, next);
}
Label copyArgs;
__ Tbnz(argc, 0, ©Args);
{
__ Add(argv, argv, Operand(argc.W(), UXTW, 3));
__ Ldr(op1, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
__ Stp(op1, xzr, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ Sub(argc.W(), argc.W(), Immediate(1));
__ Sub(argv, argv, Operand(argc.W(), UXTW, 3));
__ B(©Args);
}
__ Bind(©Args);
{
Label loopBeginning;
Label pushPadding;
__ Add(argv, argv, Operand(argc.W(), UXTW, 3));
__ Cmp(argc.W(), Immediate(1));
__ B(Condition::LS, &pushPadding);
__ Bind(&loopBeginning);
__ Ldp(op1, op2, MemoryOperand(argv, -DOUBLE_SLOT_SIZE, PREINDEX));
__ Stp(op1, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
__ Sub(argc.W(), argc.W(), Immediate(2));
__ Cmp(argc.W(), Immediate(1));
__ B(Condition::HI, &loopBeginning);
__ Bind(&pushPadding);
__ Ldr(op2, MemoryOperand(argv, -FRAME_SLOT_SIZE, PREINDEX));
__ Stp(padding, op2, MemoryOperand(sp, -DOUBLE_SLOT_SIZE, AddrMode::PREINDEX));
if (next != nullptr) {
__ B(next);
}
}
}
void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register glue, Register argc, Register temp,
Register currentSlot, Label *next, Label *stackOverflow)
{
if (next != nullptr) {
__ Cmp(argc.W(), Immediate(0));
__ B(Condition::LE, next);
}
if (stackOverflow != nullptr) {
StackOverflowCheck(assembler, glue, currentSlot, argc, temp, stackOverflow);
}
Label loopBeginning;
__ Mov(temp, Immediate(JSTaggedValue::VALUE_UNDEFINED));
__ Bind(&loopBeginning);
__ Str(temp, MemoryOperand(currentSlot, -FRAME_SLOT_SIZE, AddrMode::PREINDEX));
__ Sub(argc.W(), argc.W(), Immediate(1));
__ Cbnz(argc.W(), &loopBeginning);
}
void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register currentSlot,
Register numArgs, Register op, Label *stackOverflow)
{
__ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetStackLimitOffset(false)));
Label skipThrow;
__ Sub(op, currentSlot, Operand(op, UXTX, 0));
__ Cmp(op, Operand(numArgs, LSL, 3));
__ B(Condition::GT, &skipThrow);
__ Ldr(op, MemoryOperand(glue, JSThread::GlueData::GetAllowCrossThreadExecutionOffset(false)));
__ Cbz(op, stackOverflow);
__ Bind(&skipThrow);
}
void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
{
TempRegister2Scope temp2Scope(assembler);
Register frameType = __ TempRegister2();
__ PushFpAndLr();
__ Mov(frameType, Immediate(static_cast<int64_t>(FrameType::ASM_BRIDGE_FRAME)));
__ Stp(x19, frameType, MemoryOperand(sp, -FRAME_SLOT_SIZE * 2, AddrMode::PREINDEX));
__ Add(fp, sp, Immediate(DOUBLE_SLOT_SIZE));
}
void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
{
TempRegister2Scope temp2Scope(assembler);
Register frameType = __ TempRegister2();
__ Ldp(x19, frameType, MemoryOperand(sp, FRAME_SLOT_SIZE * 2, AddrMode::POSTINDEX));
__ RestoreFpAndLr();
}
#undef __
}