• 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 
27 #include "libpandabase/macros.h"
28 
29 namespace panda::ecmascript {
30 enum class MachineCodeType : uint8_t {
31     BASELINE_CODE,
32     FAST_JIT_CODE,
33 };
34 
35 struct MachineCodeDesc {
36     uintptr_t rodataAddrBeforeText {0};
37     size_t rodataSizeBeforeText {0};
38     uintptr_t rodataAddrAfterText {0};
39     size_t rodataSizeAfterText {0};
40 
41     uintptr_t codeAddr {0};
42     size_t codeSize {0};
43     uintptr_t funcEntryDesAddr {0};
44     size_t funcEntryDesSize {0};
45     uintptr_t stackMapOrOffsetTableAddr {0};
46     size_t stackMapOrOffsetTableSize {0};
47     MachineCodeType codeType {MachineCodeType::FAST_JIT_CODE};
48 #ifdef JIT_ENABLE_CODE_SIGN
49     uintptr_t codeSigner {0};
50 #endif
51     uintptr_t instructionsAddr {0};
52     size_t instructionsSize {0};
53     bool isHugeObj {false};
54     uintptr_t hugeObjRegion {0};
55 
56     size_t codeSizeAlign {0};
57     size_t rodataSizeBeforeTextAlign {0};
58     size_t rodataSizeAfterTextAlign {0};
59     size_t funcEntryDesSizeAlign {0};
60     size_t stackMapSizeAlign {0};
61     MemDesc *memDesc {nullptr};
62     bool isAsyncCompileMode {false};
63 };
64 
65 class MachineCode;
66 using JitCodeVector = std::vector<std::tuple<MachineCode*, std::string, uintptr_t>>;
67 using JitCodeMapVisitor = std::function<void(std::map<JSTaggedType, JitCodeVector*>&)>;
68 
69 // BaselineCode object layout:
70 //                      +-----------------------------------+
71 //                      |              MarkWord             | 8 bytes
72 //      INS_SIZE_OFFSET +-----------------------------------+
73 //                      |          machine payload size     | 4 bytes
74 //                      +-----------------------------------+
75 //                      |          FuncEntryDesc size (0)   | 4 bytes
76 //                      +-----------------------------------+
77 //                      |          instructions size        | 4 bytes
78 //                      +-----------------------------------+
79 //                      |          instructions addr        | 8 bytes (if JitFort enabled)
80 //                      +-----------------------------------+
81 //                      |       nativePcOffsetTable size    | 4 bytes
82 //                      +-----------------------------------+
83 //                      |             func addr             | 8 bytes
84 //    PAYLOAD_OFFSET/   +-----------------------------------+
85 //                      |              ...                  |
86 //     INSTR_OFFSET     |                                   | if JitFort enabled, will be in JitFort space
87 //   (16 byte align)    |     machine instructions(text)    | instead for non-huge sized machine code objects
88 //                      |              ...                  | and pointed to by "instructions addr"
89 //                      +-----------------------------------+
90 //                      |                                   |
91 //                      |         nativePcOffsetTable       |
92 //                      |              ...                  |
93 //                      +-----------------------------------+
94 //==================================================================
95 // JitCode object layout:
96 //                      +-----------------------------------+
97 //                      |              MarkWord             | 8 bytes
98 //      INS_SIZE_OFFSET +-----------------------------------+
99 //                      |             OSR offset            | 4 bytes
100 //                      +-----------------------------------+
101 //                      |              OSR mask             | 4 bytes
102 //                      +-----------------------------------+
103 //                      |          machine payload size     | 4 bytes
104 //                      +-----------------------------------+
105 //                      |          FuncEntryDesc size       | 4 bytes
106 //                      +-----------------------------------+
107 //                      |          instructions size        | 4 bytes
108 //                      +-----------------------------------+
109 //                      |          instructions addr        | 8 bytes (if JitFort enabled)
110 //                      +-----------------------------------+
111 //                      |           stack map size          | 4 bytes
112 //                      +-----------------------------------+
113 //                      |             func addr             | 8 bytes
114 //       PAYLOAD_OFFSET +-----------------------------------+
115 //       (8 byte align) |           FuncEntryDesc           |
116 //                      |              ...                  |
117 //       INSTR_OFFSET   +-----------------------------------+
118 //       (16 byte align)|     machine instructions(text)    | if JitFort enabled, will be in JitFort space
119 //                      |              ...                  | instead for non-huge sized machine code objects
120 //      STACKMAP_OFFSET +-----------------------------------+ and pointed to by "instuctions addr"
121 //                      |            ArkStackMap            |
122 //                      |              ...                  |
123 //                      +-----------------------------------+
124 //
125 //==================================================================
126 // HugeMachineCode object layout for JitFort (see space.cpp AllocateFort())
127 //
128 //   ^                  +-----------------------------------+          +
129 //   |                  |              MarkWord             |          |
130 //   |                  +-----------------------------------+          |
131 //   |                  |             OSR offset            |          |
132 //   |                  +-----------------------------------+          |
133 //   |                  |               ...                 |          |
134 //   |                  |                                   |          |
135 // mutable              +-----------------------------------+          |
136 // Page aligned         |          instructions size        |          |
137 //   |                  +-----------------------------------+          |
138 //   |                  |          instructions addr        |---+      |
139 //   |                  +-----------------------------------+   |      | 256 kByte (Region)
140 //   |                  |               ...                 |   |      |      multiples
141 //   |                  |                                   |   |      |
142 //   |                  +-----------------------------------+   |      |
143 //   |                  |            FuncEntryDesc          |   |      |
144 //   |                  |                                   |   |      |
145 //   |                  +-----------------------------------+   |      |  if JitFort is disabled
146 //   |                  |             ArkStackMap           |   |      |  Jit generated native code
147 //   |                  |                                   |   |      |  location is placed between
148 //   v     Page Aligned +-----------------------------------+   |      |  FuncEntryDesc and ArkStackMap
149 //   ^     if JitFort   |                                   |<--+      |  instead and is mutable
150 //   |     enabled      |            JitFort space          |          |
151 //   |                  |    (Jit generated native code)    |          |
152 // immutable            |                                   |          |
153 // JitFort space        |                                   |          |
154 //   |                  |                                   |          |
155 //   |                  |                                   |          |
156 //   |                  |                                   |          |
157 //   v                  +-----------------------------------+          v
158 //
159 //
160 class MachineCode : public TaggedObject {
161 public:
162     NO_COPY_SEMANTIC(MachineCode);
163     NO_MOVE_SEMANTIC(MachineCode);
Cast(TaggedObject * object)164     static MachineCode *Cast(TaggedObject *object)
165     {
166         ASSERT(JSTaggedValue(object).IsMachineCodeObject());
167         return static_cast<MachineCode *>(object);
168     }
169 
170     static constexpr size_t INS_SIZE_OFFSET = TaggedObjectSize();
171     ACCESSORS_PRIMITIVE_FIELD(OSROffset, int32_t, INS_SIZE_OFFSET, OSRMASK_OFFSET);
172     // The high 16bit is used as the flag bit, and the low 16bit is used as the count of OSR execution times.
173     ACCESSORS_PRIMITIVE_FIELD(OsrMask, uint32_t, OSRMASK_OFFSET, PAYLOADSIZE_OFFSET);
174     ACCESSORS_PRIMITIVE_FIELD(PayLoadSizeInBytes, uint32_t, PAYLOADSIZE_OFFSET, FUNCENTRYDESSIZE_OFFSET);
175     ACCESSORS_PRIMITIVE_FIELD(FuncEntryDesSize, uint32_t, FUNCENTRYDESSIZE_OFFSET, INSTRSIZ_OFFSET);
176     ACCESSORS_PRIMITIVE_FIELD(InstructionsSize, uint32_t, INSTRSIZ_OFFSET, INSTRADDR_OFFSET);
177     ACCESSORS_PRIMITIVE_FIELD(InstructionsAddr, uint64_t, INSTRADDR_OFFSET, STACKMAP_OR_OFFSETTABLE_SIZE_OFFSET);
178     ACCESSORS_PRIMITIVE_FIELD(StackMapOrOffsetTableSize, uint32_t,
179         STACKMAP_OR_OFFSETTABLE_SIZE_OFFSET, FUNCADDR_OFFSET);
180     ACCESSORS_PRIMITIVE_FIELD(FuncAddr, uint64_t, FUNCADDR_OFFSET, PADDING_OFFSET);
181     ACCESSORS_PRIMITIVE_FIELD(Padding, uint64_t, PADDING_OFFSET, LAST_OFFSET);
182     DEFINE_ALIGN_SIZE(LAST_OFFSET);
183     static constexpr size_t PAYLOAD_OFFSET = SIZE;
184     static constexpr uint32_t DATA_ALIGN = 8;
185     static constexpr uint32_t TEXT_ALIGN = 16;
186     static constexpr int32_t INVALID_OSR_OFFSET = -1;
187     static constexpr uint32_t OSR_EXECUTE_CNT_OFFSET = OSRMASK_OFFSET + 2;
188     static constexpr uint16_t OSR_DEOPT_FLAG = 0x80;
189 
DECL_DUMP()190     DECL_DUMP()
191 
192     uintptr_t GetFuncEntryDesAddress() const
193     {
194         uintptr_t paddingAddr = reinterpret_cast<const uintptr_t>(this) + PADDING_OFFSET;
195         return IsAligned(paddingAddr, TEXT_ALIGN) ? paddingAddr : reinterpret_cast<const uintptr_t>(this) +
196             PAYLOAD_OFFSET;
197     }
198 
199     uintptr_t GetText() const;
200     uint8_t *GetStackMapOrOffsetTableAddress() const;
201 
GetTextSize()202     size_t GetTextSize() const
203     {
204         return GetInstructionsSize();
205     }
206 
207     bool SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize);
208     bool SetText(const MachineCodeDesc &desc);
209     bool SetNonText(const MachineCodeDesc &desc, EntityId methodId);
210 
211     template <VisitType visitType>
VisitRangeSlot(const EcmaObjectRangeVisitor & visitor)212     void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)
213     {
214         if constexpr (visitType == VisitType::ALL_VISIT) {
215             visitor(this, ObjectSlot(ToUintPtr(this)),
216                 ObjectSlot(ToUintPtr(this) + GetMachineCodeObjectSize()), VisitObjectArea::RAW_DATA);
217         }
218     }
219 
GetMachineCodeObjectSize()220     size_t GetMachineCodeObjectSize()
221     {
222         return SIZE + this->GetPayLoadSizeInBytes();
223     }
224 
GetInstructionSizeInBytes()225     uint32_t GetInstructionSizeInBytes() const
226     {
227         return GetPayLoadSizeInBytes();
228     }
229 
230     bool IsInText(const uintptr_t pc) const;
231     uintptr_t GetFuncEntryDes() const;
232 
233     std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec> CalCallSiteInfo(uintptr_t retAddr) const;
234 
SetOsrDeoptFlag(bool isDeopt)235     void SetOsrDeoptFlag(bool isDeopt)
236     {
237         uint16_t flag = Barriers::GetValue<uint16_t>(this, OSRMASK_OFFSET);
238         if (isDeopt) {
239             flag |= OSR_DEOPT_FLAG;
240         } else {
241             flag &= (~OSR_DEOPT_FLAG);
242         }
243         Barriers::SetPrimitive(this, OSRMASK_OFFSET, flag);
244     }
245 
SetOsrExecuteCnt(uint16_t count)246     void SetOsrExecuteCnt(uint16_t count)
247     {
248         Barriers::SetPrimitive(this, OSR_EXECUTE_CNT_OFFSET, count);
249     }
250 private:
251     bool SetBaselineCodeData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize);
252 };
253 }  // namespace panda::ecmascript
254 #endif  // ECMASCRIPT_MEM_MACHINE_CODE_H
255