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/x64/common_call.h"
17
18 #include "ecmascript/runtime_call_id.h"
19
20 namespace panda::ecmascript::x64 {
21 #define __ assembler->
22
CopyArgumentWithArgV(ExtendedAssembler * assembler,Register argc,Register argV)23 void CommonCall::CopyArgumentWithArgV(ExtendedAssembler *assembler, Register argc, Register argV)
24 {
25 Label loopBeginning;
26 Register arg = __ AvailableRegister1();
27 __ Bind(&loopBeginning);
28 __ Movq(Operand(argV, argc, Scale::Times8, -FRAME_SLOT_SIZE), arg); // -8: stack index
29 __ Pushq(arg);
30 __ Subq(1, argc);
31 __ Ja(&loopBeginning);
32 }
33
PushAsmInterpBridgeFrame(ExtendedAssembler * assembler)34 void CommonCall::PushAsmInterpBridgeFrame(ExtendedAssembler *assembler)
35 {
36 // construct asm interpreter bridge frame
37 __ Pushq(static_cast<int64_t>(FrameType::ASM_INTERPRETER_BRIDGE_FRAME));
38 __ Pushq(rbp);
39 __ Pushq(0); // pc
40 __ Leaq(Operand(rsp, 24), rbp); // 24: skip pc, prevSp and frame type
41 __ PushAlignBytes();
42 if (!assembler->FromInterpreterHandler()) {
43 __ PushCppCalleeSaveRegisters();
44 }
45 }
46
GetArgvAtStack(ExtendedAssembler * assembler)47 void CommonCall::GetArgvAtStack(ExtendedAssembler *assembler)
48 {
49 Register r13 = __ CppJSCallAvailableRegister1();
50 Register r14 = __ CppJSCallAvailableRegister2();
51 __ Movq(Operand(rbp, FRAME_SLOT_SIZE), r13);
52 __ Movq(Operand(rbp, 2 * FRAME_SLOT_SIZE), r14); // 2: skip second argv
53 }
54
PopAsmInterpBridgeFrame(ExtendedAssembler * assembler)55 void CommonCall::PopAsmInterpBridgeFrame(ExtendedAssembler *assembler)
56 {
57 if (!assembler->FromInterpreterHandler()) {
58 __ PopCppCalleeSaveRegisters();
59 }
60 __ PopAlignBytes();
61 __ Addq(8, rsp); // 8: skip pc
62 __ Popq(rbp);
63 __ Addq(8, rsp); // 8: skip frame type
64 }
65
PushUndefinedWithArgc(ExtendedAssembler * assembler,Register argc)66 void CommonCall::PushUndefinedWithArgc(ExtendedAssembler *assembler, Register argc)
67 {
68 Label loopBeginning;
69 __ Bind(&loopBeginning);
70 __ Pushq(JSTaggedValue::Undefined().GetRawData());
71 __ Subq(1, argc);
72 __ Ja(&loopBeginning);
73 }
74
PushArgsWithArgvAndCheckStack(ExtendedAssembler * assembler,Register glue,Register argc,Register argv,Register op1,Register op2,Label * stackOverflow)75 void CommonCall::PushArgsWithArgvAndCheckStack(ExtendedAssembler *assembler, Register glue, Register argc,
76 Register argv, Register op1, Register op2, Label *stackOverflow)
77 {
78 ASSERT(stackOverflow != nullptr);
79 StackOverflowCheck(assembler, glue, argc, op1, op2, stackOverflow);
80 Register opArgc = argc;
81 Register op = op1;
82 if (op1 != op2) {
83 // use op2 as opArgc and will not change argc register
84 opArgc = op2;
85 __ Movq(argc, opArgc);
86 }
87 Label loopBeginning;
88 __ Bind(&loopBeginning);
89 __ Movq(Operand(argv, opArgc, Times8, -8), op); // 8: 8 bytes argv crash rdx=0x8
90 __ Pushq(op);
91 __ Subq(1, opArgc);
92 __ Ja(&loopBeginning);
93 }
94
StackOverflowCheck(ExtendedAssembler * assembler,Register glue,Register numArgs,Register op1,Register op2,Label * stackOverflow)95 void CommonCall::StackOverflowCheck(ExtendedAssembler *assembler, Register glue, Register numArgs, Register op1,
96 Register op2, Label *stackOverflow)
97 {
98 Register temp1 = op1;
99 Register temp2 = op2;
100 if (op1 == op2) {
101 // reuse glue as an op register for temporary
102 __ Pushq(glue);
103 temp2 = glue;
104 }
105 __ Movq(Operand(glue, JSThread::GlueData::GetStackLimitOffset(false)), temp1);
106 __ Movq(rsp, temp2);
107 __ Subq(temp1, temp2);
108 __ Movl(numArgs, temp1);
109 __ Shlq(3, temp1); // 3: each arg occupies 8 bytes
110 __ Cmpq(temp1, temp2);
111 if (op1 == op2) {
112 __ Popq(glue);
113 }
114 __ Jle(stackOverflow);
115 }
116
PushAsmBridgeFrame(ExtendedAssembler * assembler)117 void CommonCall::PushAsmBridgeFrame(ExtendedAssembler *assembler)
118 {
119 __ Pushq(rbp);
120 __ Pushq(static_cast<int32_t>(FrameType::ASM_BRIDGE_FRAME));
121 __ Leaq(Operand(rsp, FRAME_SLOT_SIZE), rbp);
122 }
123
PopAsmBridgeFrame(ExtendedAssembler * assembler)124 void CommonCall::PopAsmBridgeFrame(ExtendedAssembler *assembler)
125 {
126 __ Addq(FRAME_SLOT_SIZE, rsp); // skip type
127 __ Popq(rbp);
128 }
129 #undef __
130 } // namespace panda::ecmascript::x64
131