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