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