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