1 /*
2  * Copyright (c) 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/assembler/x64/macro_assembler_x64.h"
17 #include "ecmascript/js_function.h"
18 
19 namespace panda::ecmascript::kungfu {
20 using namespace panda::ecmascript;
21 
Move(const StackSlotOperand &dstStackSlot, Immediate value)22 void MacroAssemblerX64::Move(const StackSlotOperand &dstStackSlot, Immediate value)
23 {
24     x64::Register baseReg = (dstStackSlot.IsFrameBase()) ? x64::rbp : x64::rsp;
25     x64::Operand dstOpnd(baseReg, dstStackSlot.GetOffset());
26     assembler.Movabs(value.GetValue(), LOCAL_SCOPE_REGISTER);
27     assembler.Movq(LOCAL_SCOPE_REGISTER, dstOpnd);
28 }
29 
Move(const StackSlotOperand &dstStackSlot, const StackSlotOperand &srcStackSlot)30 void MacroAssemblerX64::Move(const StackSlotOperand &dstStackSlot,
31                              const StackSlotOperand &srcStackSlot)
32 {
33     x64::Register dstBaseReg = (dstStackSlot.IsFrameBase()) ? x64::rbp : x64::rsp;
34     x64::Register srcBaseReg = (srcStackSlot.IsFrameBase()) ? x64::rbp : x64::rsp;
35     x64::Operand srcOpnd(srcBaseReg, srcStackSlot.GetOffset());
36     x64::Operand dstOpnd(dstBaseReg, dstStackSlot.GetOffset());
37     assembler.Movq(srcOpnd, LOCAL_SCOPE_REGISTER);
38     assembler.Movq(LOCAL_SCOPE_REGISTER, dstOpnd);
39 }
40 
Cmp(const StackSlotOperand &stackSlot, Immediate value)41 void MacroAssemblerX64::Cmp(const StackSlotOperand &stackSlot, Immediate value)
42 {
43     x64::Register baseReg = (stackSlot.IsFrameBase()) ? x64::rbp : x64::rsp;
44     x64::Operand opnd(baseReg, stackSlot.GetOffset());
45     assembler.Movq(opnd, LOCAL_SCOPE_REGISTER);
46     assembler.Cmp(x64::Immediate(value.GetValue()), LOCAL_SCOPE_REGISTER);
47 }
48 
Bind(JumpLabel &label)49 void MacroAssemblerX64::Bind(JumpLabel &label)
50 {
51     assembler.Bind(&label);
52 }
53 
Jz(JumpLabel &label)54 void MacroAssemblerX64::Jz(JumpLabel &label)
55 {
56     assembler.Jz(&label);
57 }
58 
Jnz(JumpLabel &label)59 void MacroAssemblerX64::Jnz(JumpLabel &label)
60 {
61     assembler.Jnz(&label);
62 }
63 
Jump(JumpLabel &label)64 void MacroAssemblerX64::Jump(JumpLabel &label)
65 {
66     assembler.Jmp(&label);
67 }
68 
SaveReturnRegister(const StackSlotOperand &dstStackSlot)69 void MacroAssemblerX64::SaveReturnRegister(const StackSlotOperand &dstStackSlot)
70 {
71     x64::Register dstBaseReg = (dstStackSlot.IsFrameBase()) ? x64::rbp : x64::rsp;
72     x64::Operand dstOpnd(dstBaseReg, dstStackSlot.GetOffset());
73     assembler.Movq(RETURN_REGISTER, dstOpnd);
74 }
75 
MovParameterIntoParamReg(MacroParameter param, x64::Register paramReg)76 void MacroAssemblerX64::MovParameterIntoParamReg(MacroParameter param, x64::Register paramReg)
77 {
78     if (std::holds_alternative<BaselineSpecialParameter>(param)) {
79         auto specialParam = std::get<BaselineSpecialParameter>(param);
80         switch (specialParam) {
81             case BaselineSpecialParameter::GLUE: {
82                 assembler.Movq(GLUE_REGISTER, paramReg);
83                 break;
84             }
85             case BaselineSpecialParameter::PROFILE_TYPE_INFO: {
86                 assembler.Movq(x64::Operand(x64::rbp, FUNCTION_OFFSET_FROM_SP), LOCAL_SCOPE_REGISTER);
87                 assembler.Movq(
88                     x64::Operand(LOCAL_SCOPE_REGISTER, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET),
89                     LOCAL_SCOPE_REGISTER);
90                 assembler.Movq(x64::Operand(LOCAL_SCOPE_REGISTER, ProfileTypeInfoCell::VALUE_OFFSET), paramReg);
91                 break;
92             }
93             case BaselineSpecialParameter::SP: {
94                 assembler.Movq(x64::rbp, paramReg);
95                 break;
96             }
97             case BaselineSpecialParameter::HOTNESS_COUNTER: {
98                 assembler.Movq(x64::Operand(x64::rbp, FUNCTION_OFFSET_FROM_SP), LOCAL_SCOPE_REGISTER);
99                 assembler.Movq(
100                     x64::Operand(LOCAL_SCOPE_REGISTER, JSFunctionBase::METHOD_OFFSET), LOCAL_SCOPE_REGISTER);
101                 assembler.Movzwq(x64::Operand(LOCAL_SCOPE_REGISTER, Method::LITERAL_INFO_OFFSET), paramReg);
102                 break;
103             }
104             default: {
105                 std::cout << "not supported BaselineSpecialParameter currently" << std::endl;
106                 std::abort();
107             }
108         }
109         return;
110     }
111     if (std::holds_alternative<int8_t>(param)) {
112         int16_t num = std::get<int8_t>(param);
113         assembler.Movq(panda::ecmascript::x64::Immediate(static_cast<int32_t>(num)), paramReg);
114         return;
115     }
116     if (std::holds_alternative<int16_t>(param)) {
117         int16_t num = std::get<int16_t>(param);
118         assembler.Movq(panda::ecmascript::x64::Immediate(static_cast<int32_t>(num)), paramReg);
119         return;
120     }
121     if (std::holds_alternative<int32_t>(param)) {
122         int32_t num = std::get<int32_t>(param);
123         assembler.Movq(panda::ecmascript::x64::Immediate(num), paramReg);
124         return;
125     }
126     if (std::holds_alternative<int64_t>(param)) {
127         int64_t num = std::get<int64_t>(param);
128         assembler.Movabs(num, paramReg);
129         return;
130     }
131     if (std::holds_alternative<StackSlotOperand>(param)) {
132         StackSlotOperand stackSlotOpnd = std::get<StackSlotOperand>(param);
133         x64::Register dstBaseReg = (stackSlotOpnd.IsFrameBase()) ? x64::rbp : x64::rsp;
134         x64::Operand paramOpnd(dstBaseReg, stackSlotOpnd.GetOffset());
135         assembler.Movq(paramOpnd, paramReg);
136         return;
137     }
138     std::cout << "not supported other type of baseline parameters currently" << std::endl;
139     std::abort();
140 }
141 
CallBuiltin(Address funcAddress, const std::vector<MacroParameter> &parameters)142 void MacroAssemblerX64::CallBuiltin(Address funcAddress,
143                                     const std::vector<MacroParameter> &parameters)
144 {
145     for (size_t i = 0; i < parameters.size(); ++i) {
146         auto param = parameters[i];
147         if (i == PARAM_REGISTER_COUNT) {
148             std::cout << "should not pass parameters on the stack" << std::endl;
149             std::abort();
150         }
151         MovParameterIntoParamReg(param, registerParamVec[i]);
152     }
153     assembler.Movabs(static_cast<uint64_t>(funcAddress), LOCAL_SCOPE_REGISTER);
154     assembler.Callq(LOCAL_SCOPE_REGISTER);
155 }
156 
157 }  // namespace panda::ecmascript::kungfu
158