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 
23 namespace panda::ecmascript::kungfu {
24 enum 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 
33 using BaselineParameter = std::variant<int8_t, int16_t, int32_t, int64_t, BaselineSpecialParameter, VirtualRegister>;
34 
35 class StackOffsetDescriptor {
36 public:
StackOffsetDescriptor(uint64_t inputCallField)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 
GetVregOffset(VirtualRegister virtualReg)45     int32_t GetVregOffset(VirtualRegister virtualReg)
46     {
47         VRegIDType vregId = virtualReg.GetId();
48         return (vregId) * FRAME_SLOT_SIZE;
49     }
50 
GetSpecialRegisterOffset(SpecialRegister reg)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     }
73 private:
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 
80 class BaselineAssembler {
81 public:
82     explicit BaselineAssembler(const std::string &tripleStr);
GetBuffer() const83     uint8_t *GetBuffer() const
84     {
85         return macroAssembler->GetBegin();
86     }
87 
GetBufferSize() const88     size_t GetBufferSize() const
89     {
90         return macroAssembler->GetBufferCurrentSize();
91     }
92 
SetStackOffsetDescriptor(const StackOffsetDescriptor &inputStackOffsetDesc)93     void SetStackOffsetDescriptor(const StackOffsetDescriptor &inputStackOffsetDesc)
94     {
95         stackOffsetDescriptor = inputStackOffsetDesc;
96     }
97 
GetMacroAssembler()98     MacroAssembler &GetMacroAssembler()
99     {
100         ASSERT(macroAssembler != nullptr);
101         return *macroAssembler;
102     }
103 
~BaselineAssembler()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 
Bind(JumpLabel &label)119     void Bind(JumpLabel &label)
120     {
121         macroAssembler->Bind(label);
122     }
123 
Jz(JumpLabel &label)124     void Jz(JumpLabel &label)
125     {
126         macroAssembler->Jz(label);
127     }
128 
Jnz(JumpLabel &label)129     void Jnz(JumpLabel &label)
130     {
131         macroAssembler->Jnz(label);
132     }
133 
Jump(JumpLabel &label)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 
143 private:
144     MacroAssembler *macroAssembler;
145     StackOffsetDescriptor stackOffsetDescriptor;
146 };
147 }  // namespace panda::ecmascript::kungfu
148 #endif  // ECMASCRIPT_BASELINE_BASELINE_ASSEMBLER_H
149