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