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