1/* 2 * Copyright (c) 2023-2024 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 16#include "ecmascript/mem/machine_code.h" 17#include "ecmascript/compiler/aot_file/func_entry_des.h" 18#include "ecmascript/jit/jit.h" 19#if ECMASCRIPT_ENABLE_CAST_CHECK 20#include "ecmascript/js_tagged_value-inl.h" 21#endif 22 23namespace panda::ecmascript { 24 25static bool SetPageProtect(uint8_t *textStart, size_t dataSize) 26{ 27 if (!Jit::GetInstance()->IsEnableJitFort()) { 28 constexpr size_t pageSize = 4096; 29 uintptr_t startPage = AlignDown(reinterpret_cast<uintptr_t>(textStart), pageSize); 30 uintptr_t endPage = AlignUp(reinterpret_cast<uintptr_t>(textStart) + dataSize, pageSize); 31 size_t protSize = endPage - startPage; 32 return PageProtect(reinterpret_cast<void*>(startPage), protSize, PAGE_PROT_EXEC_READWRITE); 33 } 34 return true; 35} 36 37static int MachineCodeCopyToCache([[maybe_unused]] const MachineCodeDesc &desc, [[maybe_unused]] uint8_t *pText) 38{ 39#ifndef JIT_ENABLE_CODE_SIGN 40 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) { 41 LOG_JIT(ERROR) << "memcpy failed in CopyToCache"; 42 return false; 43 } 44#endif 45 return true; 46} 47 48bool MachineCode::SetText(const MachineCodeDesc &desc) 49{ 50 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 51 uint8_t *pText = textStart; 52 if (desc.rodataSizeBeforeTextAlign != 0) { 53 if (memcpy_s(pText, desc.rodataSizeBeforeTextAlign, 54 reinterpret_cast<uint8_t*>(desc.rodataAddrBeforeText), 55 desc.rodataSizeBeforeText) != EOK) { // LCOV_EXCL_BR_LINE 56 LOG_JIT(ERROR) << "memcpy fail in copy fast jit code"; 57 return false; 58 } 59 pText += desc.rodataSizeBeforeTextAlign; 60 } 61 if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() || 62 !desc.isAsyncCompileMode) { 63 if (MachineCodeCopyToCache(desc, pText) == false) { 64 return false; 65 } 66 } 67 pText += desc.codeSizeAlign; 68 if (desc.rodataSizeAfterTextAlign != 0) { 69 if (memcpy_s(pText, desc.rodataSizeAfterTextAlign, 70 reinterpret_cast<uint8_t*>(desc.rodataAddrAfterText), 71 desc.rodataSizeAfterText) != EOK) { // LCOV_EXCL_BR_LINE 72 LOG_JIT(ERROR) << "memcpy fail in copy fast jit code"; 73 return false; 74 } 75 } 76 return true; 77} 78 79bool MachineCode::SetNonText(const MachineCodeDesc &desc, EntityId methodId) 80{ 81 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 82 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 83 if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, 84 reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr), 85 desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE 86 LOG_JIT(ERROR) << "memcpy fail in copy fast jit stackmap"; 87 return false; 88 } 89 90 FuncEntryDes *funcEntry = reinterpret_cast<FuncEntryDes*>(desc.funcEntryDesAddr); 91 if (!funcEntry) { 92 LOG_JIT(ERROR) << "funcEntry is null."; 93 return false; 94 } 95 uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes); 96 ASSERT(cnt <= 2); // 2: jsfunction + deoptimize stub 97 for (uint32_t i = 0; i < cnt; i++) { 98 if (methodId == EntityId(funcEntry->indexInKindOrMethodId_)) { 99 uint64_t codeAddr = funcEntry->codeAddr_ + 100 static_cast<uint64_t>(reinterpret_cast<uintptr_t>(textStart)); 101 SetFuncAddr(codeAddr); 102 break; 103 } 104 funcEntry++; 105 } 106 107 SetIsFastCall(funcEntry->isFastCall_); 108 SetFpDeltaPrevFrameSp(funcEntry->fpDeltaPrevFrameSp_); 109 SetFuncSize(funcEntry->funcSize_); 110 SetCalleeRegisterNum(funcEntry->calleeRegisterNum_); 111 SetCalleeReg2OffsetArray(funcEntry->CalleeReg2Offset_); 112 return true; 113} 114 115bool MachineCode::SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize) 116{ 117 DISALLOW_GARBAGE_COLLECTION; 118 if (desc.codeType == MachineCodeType::BASELINE_CODE) { 119 return SetBaselineCodeData(desc, method, dataSize); 120 } 121 122 SetOSROffset(MachineCode::INVALID_OSR_OFFSET); 123 SetOsrDeoptFlag(false); 124 SetOsrExecuteCnt(0); 125 126 size_t instrSize = desc.rodataSizeBeforeTextAlign + desc.codeSizeAlign + desc.rodataSizeAfterTextAlign; 127 128 SetInstructionsSize(instrSize); 129 SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign); 130 SetPayLoadSizeInBytes(dataSize); 131 if (Jit::GetInstance()->IsEnableJitFort()) { 132 SetInstructionsAddr(desc.instructionsAddr); 133 ASSERT(desc.instructionsAddr != 0); 134 ASSERT(dataSize == (desc.funcEntryDesSizeAlign + desc.stackMapSizeAlign) || 135 dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign)); 136 } else { 137 ASSERT(dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign)); 138 } 139 if (!SetText(desc)) { 140 return false; 141 } 142 if (!SetNonText(desc, method->GetMethodId())) { 143 return false; 144 } 145 146 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 147 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 148 CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 149 LOG_JIT(DEBUG) << "Fast JIT MachineCode :" << methodName << ", " << " text addr:" << 150 reinterpret_cast<void*>(GetText()) << ", size:" << instrSize << 151 ", stackMap addr:" << reinterpret_cast<void*>(stackmapAddr) << 152 ", size:" << desc.stackMapSizeAlign; 153 154 if (!SetPageProtect(textStart, dataSize)) { 155 LOG_JIT(ERROR) << "MachineCode::SetData SetPageProtect failed"; 156 return false; 157 } 158 return true; 159} 160 161bool MachineCode::SetBaselineCodeData(const MachineCodeDesc &desc, 162 JSHandle<Method> &method, size_t dataSize) 163{ 164 DISALLOW_GARBAGE_COLLECTION; 165 166 size_t instrSizeAlign = desc.codeSizeAlign; 167 SetInstructionsSize(instrSizeAlign); 168 169 SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign); 170 if (Jit::GetInstance()->IsEnableJitFort()) { 171 ASSERT(desc.instructionsAddr != 0); 172 ASSERT(dataSize == (desc.stackMapSizeAlign) || // reg. obj 173 dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); // huge obj 174 SetInstructionsAddr(desc.instructionsAddr); 175 } else { 176 ASSERT(dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); 177 } 178 SetPayLoadSizeInBytes(dataSize); 179 180 uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 181 if (Jit::GetInstance()->IsEnableJitFort()) { 182 // relax assert for now until machine code padding for JitFort resolved 183 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN) || 184 IsAligned(reinterpret_cast<uintptr_t>(textStart), DATA_ALIGN)); 185 } else { 186 ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN)); 187 } 188 uint8_t *pText = textStart; 189 190 if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() || 191 !desc.isAsyncCompileMode) { 192 if (MachineCodeCopyToCache(desc, pText) == false) { 193 return false; 194 } 195 } 196 pText += instrSizeAlign; 197 198 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 199 if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, 200 reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr), 201 desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE 202 LOG_BASELINEJIT(ERROR) << "memcpy fail in copy fast baselineJIT offsetTable"; 203 return false; 204 } 205 206 SetFuncAddr(reinterpret_cast<uintptr_t>(textStart)); 207 208 CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 209 LOG_BASELINEJIT(DEBUG) << "BaselineCode :" << methodName << ", " << " text addr:" << 210 reinterpret_cast<void*>(GetText()) << ", size:" << instrSizeAlign << 211 ", stackMap addr: 0, size: 0"; 212 213 if (!SetPageProtect(textStart, dataSize)) { 214 LOG_BASELINEJIT(ERROR) << "MachineCode::SetBaseLineCodeData SetPageProtect failed"; 215 return false; 216 } 217 return true; 218} 219 220bool MachineCode::IsInText(const uintptr_t pc) const 221{ 222 uintptr_t textStart = GetText(); 223 uintptr_t textEnd = textStart + GetTextSize(); 224 return textStart <= pc && pc < textEnd; 225} 226 227std::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> MachineCode::CalCallSiteInfo() const 228{ 229 uintptr_t textStart = GetText(); 230 uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 231 ASSERT(stackmapAddr != nullptr); 232 233 int delta = GetFpDeltaPrevFrameSp(); 234 kungfu::CalleeRegAndOffsetVec calleeRegInfo; 235 for (uint32_t j = 0; j < GetCalleeRegisterNum(); j++) { 236 kungfu::LLVMStackMapType::DwarfRegType reg = 237 static_cast<kungfu::LLVMStackMapType::DwarfRegType>(GetCalleeReg2OffsetArray(2 * j)); 238 kungfu::LLVMStackMapType::OffsetType offset = 239 static_cast<kungfu::LLVMStackMapType::OffsetType>(GetCalleeReg2OffsetArray(2 * j + 1)); 240 kungfu::LLVMStackMapType::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset); 241 calleeRegInfo.emplace_back(regAndOffset); 242 } 243 auto ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo); 244 return ret; 245} 246 247uintptr_t MachineCode::GetText() const 248{ 249 if (Jit::GetInstance()->IsEnableJitFort()) { 250 return GetInstructionsAddr(); 251 } else { 252 return GetNonTextAddress(); 253 } 254} 255 256uint8_t *MachineCode::GetStackMapOrOffsetTableAddress() const 257{ 258 if (Jit::GetInstance()->IsEnableJitFort()) { 259 // stackmap immediately follows MachineCode NonText area 260 return reinterpret_cast<uint8_t*>(GetNonTextAddress()); 261 } else { 262 return reinterpret_cast<uint8_t*>(GetText() + GetInstructionsSize()); 263 } 264} 265 266void MachineCode::ProcessMarkObject() 267{ 268 Region *region = Region::ObjectAddressToRange(this); 269 Heap *localHeap = reinterpret_cast<Heap *>(region->GetLocalHeap()); 270 if (!localHeap) { 271 // it is a huge machine code object. skip 272 return; 273 } 274 ASSERT(localHeap->GetMachineCodeSpace()); 275 if (localHeap->GetMachineCodeSpace()) { 276 localHeap->GetMachineCodeSpace()->MarkJitFortMemAlive(this); 277 } 278} 279 280} // namespace panda::ecmascript 281