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#ifndef ECMASCRIPT_BASELINE_BASELINE_ASSEMBLER_H
17#define ECMASCRIPT_BASELINE_BASELINE_ASSEMBLER_H
18
19#include "ecmascript/ecma_vm.h"
20#include "ecmascript/compiler/assembler/macro_assembler.h"
21#include "ecmascript/method.h"
22
23namespace panda::ecmascript::kungfu {
24enum class SpecialRegister : uint8_t {
25    NEW_TARGET,
26    CALL_SIZE, // jumpSizeAfterCall
27    ENV,
28    ACC_REGISTER,
29    THIS_OBJECT, // this
30    FUNC, // callTarget
31};
32
33using BaselineParameter = std::variant<int8_t, int16_t, int32_t, int64_t, BaselineSpecialParameter, VirtualRegister>;
34
35class StackOffsetDescriptor {
36public:
37    StackOffsetDescriptor(uint64_t inputCallField) : callField(inputCallField)
38    {
39        numVregs = Method::GetNumVregsWithCallField(callField);
40        haveNewTarget = Method::HaveNewTargetWithCallField(callField);
41        // Add stack slot info as required
42    }
43    ~StackOffsetDescriptor() = default;
44
45    int32_t GetVregOffset(VirtualRegister virtualReg)
46    {
47        VRegIDType vregId = virtualReg.GetId();
48        return (vregId) * FRAME_SLOT_SIZE;
49    }
50
51    int32_t GetSpecialRegisterOffset(SpecialRegister reg)
52    {
53        switch (reg) {
54            case SpecialRegister::NEW_TARGET:
55                return ((3 + numVregs) * FRAME_SLOT_SIZE);  // +3: contains numVregs, undefined, callTarget, newTarget
56            case SpecialRegister::CALL_SIZE:
57                return -(5 * FRAME_SLOT_SIZE); // -5: contains frametype, rbp, pc, sp, callsize(jumpSizeAfterCall)
58            case SpecialRegister::ENV:
59                return -(6 * FRAME_SLOT_SIZE); // -6: contains frametype, rbp, pc, sp, callsize, env,
60            case SpecialRegister::ACC_REGISTER:
61                return -(7 * FRAME_SLOT_SIZE); // -7: contains frametype, rbp, pc, sp, callsize, env, acc,
62            case SpecialRegister::THIS_OBJECT:
63                return -(8 * FRAME_SLOT_SIZE); // -8: contains frametype, rbp, pc, sp, callsize, env, acc, thisObj
64            case SpecialRegister::FUNC:
65                // -9: contains frametype, rbp, pc, sp, callsize, env, acc, thisObj, call-target
66                return -(9 * FRAME_SLOT_SIZE);
67            default:
68                LOG_ECMA(FATAL) << "this branch is unreachable";
69                UNREACHABLE();
70                return 0;
71        }
72    }
73private:
74    uint64_t callField = 0;
75    uint32_t numVregs = 0;
76    bool haveNewTarget = false;
77    static constexpr int32_t FRAME_SLOT_SIZE = 8;
78};
79
80class BaselineAssembler {
81public:
82    explicit BaselineAssembler(const std::string &tripleStr);
83    uint8_t *GetBuffer() const
84    {
85        return macroAssembler->GetBegin();
86    }
87
88    size_t GetBufferSize() const
89    {
90        return macroAssembler->GetBufferCurrentSize();
91    }
92
93    void SetStackOffsetDescriptor(const StackOffsetDescriptor &inputStackOffsetDesc)
94    {
95        stackOffsetDescriptor = inputStackOffsetDesc;
96    }
97
98    MacroAssembler &GetMacroAssembler()
99    {
100        ASSERT(macroAssembler != nullptr);
101        return *macroAssembler;
102    }
103
104    virtual ~BaselineAssembler()
105    {
106        if (macroAssembler != nullptr) {
107            delete macroAssembler;
108            macroAssembler = nullptr;
109        }
110    }
111    void Move(VirtualRegister interpreterDestReg, Immediate value);
112    void Move(SpecialRegister destReg, Immediate value);
113    void Move(SpecialRegister destReg, SpecialRegister srcReg);
114    void Move(VirtualRegister interpreterDestReg, VirtualRegister interpreterSrcReg);
115    void Move(SpecialRegister destReg, VirtualRegister interpreterSrcReg);
116    void Move(VirtualRegister interpreterDestReg, SpecialRegister srcReg);
117    void Cmp(SpecialRegister reg, Immediate value);
118
119    void Bind(JumpLabel &label)
120    {
121        macroAssembler->Bind(label);
122    }
123
124    void Jz(JumpLabel &label)
125    {
126        macroAssembler->Jz(label);
127    }
128
129    void Jnz(JumpLabel &label)
130    {
131        macroAssembler->Jnz(label);
132    }
133
134    void Jump(JumpLabel &label)
135    {
136        macroAssembler->Jump(label);
137    }
138
139    void SaveResultIntoAcc();
140    void CallBuiltin(Address funcAddress,
141                     const std::vector<BaselineParameter> &parameters);
142
143private:
144    MacroAssembler *macroAssembler;
145    StackOffsetDescriptor stackOffsetDescriptor;
146};
147}  // namespace panda::ecmascript::kungfu
148#endif  // ECMASCRIPT_BASELINE_BASELINE_ASSEMBLER_H
149