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
19namespace panda::ecmascript::kungfu {
20using namespace panda::ecmascript;
21
22void 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
30void 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
41void 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
49void MacroAssemblerX64::Bind(JumpLabel &label)
50{
51    assembler.Bind(&label);
52}
53
54void MacroAssemblerX64::Jz(JumpLabel &label)
55{
56    assembler.Jz(&label);
57}
58
59void MacroAssemblerX64::Jnz(JumpLabel &label)
60{
61    assembler.Jnz(&label);
62}
63
64void MacroAssemblerX64::Jump(JumpLabel &label)
65{
66    assembler.Jmp(&label);
67}
68
69void 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
76void 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
142void 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