• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 #ifndef ECMASCRIPT_MEM_MACHINE_CODE_H
16 #define ECMASCRIPT_MEM_MACHINE_CODE_H
17 
18 #include "ecmascript/ecma_macros.h"
19 #include "ecmascript/js_tagged_value.h"
20 #include "ecmascript/mem/barriers.h"
21 #include "ecmascript/mem/tagged_object.h"
22 #include "ecmascript/mem/visitor.h"
23 #include "ecmascript/stackmap/ark_stackmap.h"
24 #include "ecmascript/method.h"
25 #include "ecmascript/mem/jit_fort_memdesc.h"
26 #include "ecmascript/deoptimizer/calleeReg.h"
27 
28 #include "libpandabase/macros.h"
29 
30 namespace panda::ecmascript {
31 enum class MachineCodeType : uint8_t {
32     BASELINE_CODE,
33     FAST_JIT_CODE,
34 };
35 
36 enum class MachineCodeArchType : uint8_t {
37     AArch64,
38     X86,
39 };
40 
41 struct MachineCodeDesc {
42     uintptr_t rodataAddrBeforeText {0};
43     size_t rodataSizeBeforeText {0};
44     uintptr_t rodataAddrAfterText {0};
45     size_t rodataSizeAfterText {0};
46 
47     uintptr_t codeAddr {0};
48     size_t codeSize {0};
49     uintptr_t funcEntryDesAddr {0};
50     size_t funcEntryDesSize {0};
51     uintptr_t stackMapOrOffsetTableAddr {0};
52     size_t stackMapOrOffsetTableSize {0};
53     MachineCodeType codeType {MachineCodeType::FAST_JIT_CODE};
54     MachineCodeArchType archType {MachineCodeArchType::X86};
55 #ifdef JIT_ENABLE_CODE_SIGN
56     uintptr_t codeSigner {0};
57 #endif
58     uintptr_t instructionsAddr {0};
59     size_t instructionsSize {0};
60     bool isHugeObj {false};
61     uintptr_t hugeObjRegion {0};
62 
63     size_t codeSizeAlign {0};
64     size_t rodataSizeBeforeTextAlign {0};
65     size_t rodataSizeAfterTextAlign {0};
66     size_t funcEntryDesSizeAlign {0};
67     size_t stackMapSizeAlign {0};
68     MemDesc *memDesc {nullptr};
69     bool isAsyncCompileMode {false};
70 };
71 
72 class MachineCode;
73 using JitCodeVector = std::vector<std::tuple<MachineCode*, std::string, uintptr_t>>;
74 using JitCodeMapVisitor = std::function<void(std::map<JSTaggedType, JitCodeVector*>&)>;
75 
76 // BaselineCode object layout:
77 //                      +-----------------------------------+
78 //                      |              MarkWord             | 8 bytes
79 //      INS_SIZE_OFFSET +-----------------------------------+
80 //                      |          machine payload size     | 4 bytes
81 //                      +-----------------------------------+
82 //                      |          instructions size        | 4 bytes
83 //                      +-----------------------------------+
84 //                      |          instructions addr        | 8 bytes (if JitFort enabled)
85 //                      +-----------------------------------+
86 //                      |       nativePcOffsetTable size    | 4 bytes
87 //                      +-----------------------------------+
88 //                      |             func addr             | 8 bytes
89 //                      +-----------------------------------+
90 //                      |        fp deltaprevframe sp       | 8 bytes
91 //                      +-----------------------------------+
92 //                      |             func size             | 4 bytes
93 //                      +-----------------------------------+
94 //                      |        callee register num        | 4 bytes
95 //                      +-----------------------------------+
96 //                      |                                   | 64 * 4 bytes (AMD64 or ARM64)
97 //                      |      callee reg2offset array      | or 32 * 4 bytes (others)
98 //                      |                                   |
99 //                      +-----------------------------------+
100 //                      |             bit field             | 4 bytes
101 //                      +-----------------------------------+
102 //                      |              ...                  |
103 //     INSTR_OFFSET     |                                   | if JitFort enabled, will be in JitFort space
104 //   (16 byte align)    |     machine instructions(text)    | instead for non-huge sized machine code objects
105 //                      |              ...                  | and pointed to by "instructions addr"
106 //                      +-----------------------------------+
107 //                      |                                   |
108 //                      |         nativePcOffsetTable       |
109 //                      |              ...                  |
110 //                      +-----------------------------------+
111 //==================================================================
112 // JitCode object layout:
113 //                      +-----------------------------------+
114 //                      |              MarkWord             | 8 bytes
115 //      INS_SIZE_OFFSET +-----------------------------------+
116 //                      |             OSR offset            | 4 bytes
117 //                      +-----------------------------------+
118 //                      |              OSR mask             | 4 bytes
119 //                      +-----------------------------------+
120 //                      |          machine payload size     | 4 bytes
121 //                      +-----------------------------------+
122 //                      |          instructions size        | 4 bytes
123 //                      +-----------------------------------+
124 //                      |          instructions addr        | 8 bytes (if JitFort enabled)
125 //                      +-----------------------------------+
126 //                      |           stack map size          | 4 bytes
127 //                      +-----------------------------------+
128 //                      |             func addr             | 8 bytes
129 //                      +-----------------------------------+
130 //                      |        fp deltaprevframe sp       | 8 bytes
131 //                      +-----------------------------------+
132 //                      |             func size             | 4 bytes
133 //                      +-----------------------------------+
134 //                      |        callee register num        | 4 bytes
135 //                      +-----------------------------------+
136 //                      |                                   | 64 * 4 bytes (AMD64 or ARM64)
137 //                      |      callee reg2offset array      | or 32 * 4 bytes (others)
138 //                      |                                   |
139 //                      +-----------------------------------+
140 //                      |             bit field             | 4 bytes
141 //                      +-----------------------------------+
142 //                      |                                   |
143 //       INSTR_OFFSET   |                                   |
144 //       (16 byte align)|     machine instructions(text)    | if JitFort enabled, will be in JitFort space
145 //                      |              ...                  | instead for non-huge sized machine code objects
146 //      STACKMAP_OFFSET +-----------------------------------+ and pointed to by "instuctions addr"
147 //                      |            ArkStackMap            |
148 //                      |              ...                  |
149 //                      +-----------------------------------+
150 //
151 //==================================================================
152 // HugeMachineCode object layout for JitFort (see space.cpp AllocateFort())
153 //
154 //   ^                  +-----------------------------------+          +
155 //   |                  |              MarkWord             |          |
156 //   |                  +-----------------------------------+          |
157 //   |                  |             OSR offset            |          |
158 //   |                  +-----------------------------------+          |
159 //   |                  |               ...                 |          |
160 //   |                  |                                   |          |
161 // mutable              +-----------------------------------+          |
162 // Page aligned         |          instructions size        |          |
163 //   |                  +-----------------------------------+          |
164 //   |                  |          instructions addr        |---+      |
165 //   |                  +-----------------------------------+   |      | 256 kByte (Region)
166 //   |                  |               ...                 |   |      |      multiples
167 //   |                  |                                   |   |      |
168 //   |                  +-----------------------------------+   |      |  if JitFort is disabled
169 //   |                  |             ArkStackMap           |   |      |  Jit generated native code
170 //   |                  |                                   |   |      |  location is placed between
171 //   v     Page Aligned +-----------------------------------+   |      |  FuncEntryDesc and ArkStackMap
172 //   ^     if JitFort   |                                   |<--+      |  instead and is mutable
173 //   |     enabled      |            JitFort space          |          |
174 //   |                  |    (Jit generated native code)    |          |
175 // immutable            |                                   |          |
176 // JitFort space        |                                   |          |
177 //   |                  |                                   |          |
178 //   |                  |                                   |          |
179 //   |                  |                                   |          |
180 //   v                  +-----------------------------------+          v
181 //
182 //
183 class MachineCode : public TaggedObject {
184 public:
185     NO_COPY_SEMANTIC(MachineCode);
186     NO_MOVE_SEMANTIC(MachineCode);
Cast(TaggedObject * object)187     static MachineCode *Cast(TaggedObject *object)
188     {
189         ASSERT(JSTaggedValue(object).IsMachineCodeObject());
190         return static_cast<MachineCode *>(object);
191     }
192 
193     static constexpr size_t INS_SIZE_OFFSET = TaggedObjectSize();
194     static constexpr size_t INT32_SIZE = sizeof(int32_t);
195     static constexpr int CalleeReg2OffsetArraySize = 2 * kungfu::MAX_CALLEE_SAVE_REIGISTER_NUM;
196     ACCESSORS_PRIMITIVE_FIELD(OSROffset, int32_t, INS_SIZE_OFFSET, OSRMASK_OFFSET);
197     // The high 16bit is used as the flag bit, and the low 16bit is used as the count of OSR execution times.
198     ACCESSORS_PRIMITIVE_FIELD(OsrMask, uint32_t, OSRMASK_OFFSET, PAYLOADSIZE_OFFSET);
199     ACCESSORS_PRIMITIVE_FIELD(PayLoadSizeInBytes, uint32_t, PAYLOADSIZE_OFFSET, INSTRSIZ_OFFSET);
200     ACCESSORS_PRIMITIVE_FIELD(InstructionsSize, uint32_t, INSTRSIZ_OFFSET, INSTRADDR_OFFSET);
201     ACCESSORS_PRIMITIVE_FIELD(InstructionsAddr, uint64_t, INSTRADDR_OFFSET, STACKMAP_OR_OFFSETTABLE_SIZE_OFFSET);
202     ACCESSORS_PRIMITIVE_FIELD(StackMapOrOffsetTableSize, uint32_t,
203         STACKMAP_OR_OFFSETTABLE_SIZE_OFFSET, FUNCADDR_OFFSET);
204     ACCESSORS_PRIMITIVE_FIELD(FuncAddr, uint64_t, FUNCADDR_OFFSET, FPDELTA_PRVE_FRAME_SP_OFFSET);
205     ACCESSORS_PRIMITIVE_FIELD(FpDeltaPrevFrameSp, uintptr_t, FPDELTA_PRVE_FRAME_SP_OFFSET, FUNC_SIZE_OFFSET);
206     ACCESSORS_PRIMITIVE_FIELD(FuncSize, uint32_t, FUNC_SIZE_OFFSET, CALLEE_REGISTERNUM_OFFSET);
207     ACCESSORS_PRIMITIVE_FIELD(CalleeRegisterNum, uint32_t, CALLEE_REGISTERNUM_OFFSET, CALLEE_R2O_OFFSET);
208     static constexpr size_t BIT_FIELD_OFFSET = CALLEE_R2O_OFFSET + INT32_SIZE * CalleeReg2OffsetArraySize;
209     ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET);
210     DEFINE_ALIGN_SIZE(LAST_OFFSET);
211     static constexpr size_t PAYLOAD_OFFSET = SIZE;
212     static constexpr uint32_t DATA_ALIGN = 8;
213     static constexpr uint32_t TEXT_ALIGN = 16;
214     static constexpr int32_t INVALID_OSR_OFFSET = -1;
215     static constexpr uint32_t OSR_EXECUTE_CNT_OFFSET = OSRMASK_OFFSET + 2;
216     static constexpr uint16_t OSR_DEOPT_FLAG = 0x80;
217 
SetCalleeReg2OffsetArray(int32_t * calleeRegArray)218     void SetCalleeReg2OffsetArray(int32_t* calleeRegArray)
219     {
220         DASSERT_PRINT(calleeRegArray != nullptr, "Array pointer cannot be null.");
221         for (size_t i = 0; i < CalleeReg2OffsetArraySize; i++) {
222             Barriers::SetPrimitive<int32_t>(this, CALLEE_R2O_OFFSET + i * INT32_SIZE, calleeRegArray[i]);
223         }
224     }
225 
GetCalleeReg2OffsetArray(int32_t calleeRegIndex)226     int32_t GetCalleeReg2OffsetArray(int32_t calleeRegIndex) const
227     {
228         DASSERT_PRINT(calleeRegIndex < CalleeReg2OffsetArraySize, "Array index out of bounds.");
229         return Barriers::GetValue<int32_t>(this, CALLEE_R2O_OFFSET + calleeRegIndex * INT32_SIZE);
230     }
231 
232     // define BitField
233     static constexpr size_t IS_FAST_CALL_BITS = 1;
234     FIRST_BIT_FIELD(BitField, IsFastCall, bool, IS_FAST_CALL_BITS);
235 
DECL_DUMP()236     DECL_DUMP()
237 
238     uintptr_t GetNonTextAddress() const
239     {
240         return reinterpret_cast<const uintptr_t>(this) + LAST_OFFSET;
241     }
242 
243     uintptr_t GetText() const;
244     uint8_t *GetStackMapOrOffsetTableAddress() const;
245 
GetTextSize()246     size_t GetTextSize() const
247     {
248         return GetInstructionsSize();
249     }
250 
251     bool SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize, RelocMap &relocInfo);
252     bool SetText(const MachineCodeDesc &desc);
253     bool SetNonText(const MachineCodeDesc &desc, EntityId methodId);
254 
255     template <VisitType visitType, class DerivedVisitor>
VisitRangeSlot(EcmaObjectRangeVisitor<DerivedVisitor> & visitor)256     void VisitRangeSlot(EcmaObjectRangeVisitor<DerivedVisitor> &visitor)
257     {
258         ASSERT(visitType == VisitType::ALL_VISIT || visitType == VisitType::OLD_GC_VISIT);
259         if constexpr (visitType == VisitType::ALL_VISIT) {
260             visitor(this, ObjectSlot(ToUintPtr(this)),
261                 ObjectSlot(ToUintPtr(this) + GetMachineCodeObjectSize()), VisitObjectArea::RAW_DATA);
262         }
263         if constexpr (visitType == VisitType::OLD_GC_VISIT) {
264             this->ProcessMarkObject();
265         }
266     }
267 
268     void ProcessMarkObject();
269 
GetMachineCodeObjectSize()270     size_t GetMachineCodeObjectSize()
271     {
272         return SIZE + this->GetPayLoadSizeInBytes();
273     }
274 
GetInstructionSizeInBytes()275     uint32_t GetInstructionSizeInBytes() const
276     {
277         return GetPayLoadSizeInBytes();
278     }
279 
280     bool IsInText(const uintptr_t pc) const;
281 
282     std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> CalCallSiteInfo() const;
283 
SetOsrDeoptFlag(bool isDeopt)284     void SetOsrDeoptFlag(bool isDeopt)
285     {
286         uint16_t flag = Barriers::GetValue<uint16_t>(this, OSRMASK_OFFSET);
287         if (isDeopt) {
288             flag |= OSR_DEOPT_FLAG;
289         } else {
290             flag &= (~OSR_DEOPT_FLAG);
291         }
292         Barriers::SetPrimitive(this, OSRMASK_OFFSET, flag);
293     }
294 
SetOsrExecuteCnt(uint16_t count)295     void SetOsrExecuteCnt(uint16_t count)
296     {
297         Barriers::SetPrimitive(this, OSR_EXECUTE_CNT_OFFSET, count);
298     }
299 private:
300     bool SetBaselineCodeData(const MachineCodeDesc &desc, JSHandle<Method> &method,
301                              size_t dataSize, RelocMap &relocInfo);
302 };
303 }  // namespace panda::ecmascript
304 #endif  // ECMASCRIPT_MEM_MACHINE_CODE_H
305