14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2023-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/mem/machine_code.h" 174514f5e3Sopenharmony_ci#include "ecmascript/compiler/aot_file/func_entry_des.h" 184514f5e3Sopenharmony_ci#include "ecmascript/jit/jit.h" 194514f5e3Sopenharmony_ci#if ECMASCRIPT_ENABLE_CAST_CHECK 204514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h" 214514f5e3Sopenharmony_ci#endif 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_cinamespace panda::ecmascript { 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_cistatic bool SetPageProtect(uint8_t *textStart, size_t dataSize) 264514f5e3Sopenharmony_ci{ 274514f5e3Sopenharmony_ci if (!Jit::GetInstance()->IsEnableJitFort()) { 284514f5e3Sopenharmony_ci constexpr size_t pageSize = 4096; 294514f5e3Sopenharmony_ci uintptr_t startPage = AlignDown(reinterpret_cast<uintptr_t>(textStart), pageSize); 304514f5e3Sopenharmony_ci uintptr_t endPage = AlignUp(reinterpret_cast<uintptr_t>(textStart) + dataSize, pageSize); 314514f5e3Sopenharmony_ci size_t protSize = endPage - startPage; 324514f5e3Sopenharmony_ci return PageProtect(reinterpret_cast<void*>(startPage), protSize, PAGE_PROT_EXEC_READWRITE); 334514f5e3Sopenharmony_ci } 344514f5e3Sopenharmony_ci return true; 354514f5e3Sopenharmony_ci} 364514f5e3Sopenharmony_ci 374514f5e3Sopenharmony_cistatic int MachineCodeCopyToCache([[maybe_unused]] const MachineCodeDesc &desc, [[maybe_unused]] uint8_t *pText) 384514f5e3Sopenharmony_ci{ 394514f5e3Sopenharmony_ci#ifndef JIT_ENABLE_CODE_SIGN 404514f5e3Sopenharmony_ci if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) { 414514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "memcpy failed in CopyToCache"; 424514f5e3Sopenharmony_ci return false; 434514f5e3Sopenharmony_ci } 444514f5e3Sopenharmony_ci#endif 454514f5e3Sopenharmony_ci return true; 464514f5e3Sopenharmony_ci} 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_cibool MachineCode::SetText(const MachineCodeDesc &desc) 494514f5e3Sopenharmony_ci{ 504514f5e3Sopenharmony_ci uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 514514f5e3Sopenharmony_ci uint8_t *pText = textStart; 524514f5e3Sopenharmony_ci if (desc.rodataSizeBeforeTextAlign != 0) { 534514f5e3Sopenharmony_ci if (memcpy_s(pText, desc.rodataSizeBeforeTextAlign, 544514f5e3Sopenharmony_ci reinterpret_cast<uint8_t*>(desc.rodataAddrBeforeText), 554514f5e3Sopenharmony_ci desc.rodataSizeBeforeText) != EOK) { // LCOV_EXCL_BR_LINE 564514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "memcpy fail in copy fast jit code"; 574514f5e3Sopenharmony_ci return false; 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci pText += desc.rodataSizeBeforeTextAlign; 604514f5e3Sopenharmony_ci } 614514f5e3Sopenharmony_ci if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() || 624514f5e3Sopenharmony_ci !desc.isAsyncCompileMode) { 634514f5e3Sopenharmony_ci if (MachineCodeCopyToCache(desc, pText) == false) { 644514f5e3Sopenharmony_ci return false; 654514f5e3Sopenharmony_ci } 664514f5e3Sopenharmony_ci } 674514f5e3Sopenharmony_ci pText += desc.codeSizeAlign; 684514f5e3Sopenharmony_ci if (desc.rodataSizeAfterTextAlign != 0) { 694514f5e3Sopenharmony_ci if (memcpy_s(pText, desc.rodataSizeAfterTextAlign, 704514f5e3Sopenharmony_ci reinterpret_cast<uint8_t*>(desc.rodataAddrAfterText), 714514f5e3Sopenharmony_ci desc.rodataSizeAfterText) != EOK) { // LCOV_EXCL_BR_LINE 724514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "memcpy fail in copy fast jit code"; 734514f5e3Sopenharmony_ci return false; 744514f5e3Sopenharmony_ci } 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci return true; 774514f5e3Sopenharmony_ci} 784514f5e3Sopenharmony_ci 794514f5e3Sopenharmony_cibool MachineCode::SetNonText(const MachineCodeDesc &desc, EntityId methodId) 804514f5e3Sopenharmony_ci{ 814514f5e3Sopenharmony_ci uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 824514f5e3Sopenharmony_ci uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 834514f5e3Sopenharmony_ci if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, 844514f5e3Sopenharmony_ci reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr), 854514f5e3Sopenharmony_ci desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE 864514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "memcpy fail in copy fast jit stackmap"; 874514f5e3Sopenharmony_ci return false; 884514f5e3Sopenharmony_ci } 894514f5e3Sopenharmony_ci 904514f5e3Sopenharmony_ci FuncEntryDes *funcEntry = reinterpret_cast<FuncEntryDes*>(desc.funcEntryDesAddr); 914514f5e3Sopenharmony_ci if (!funcEntry) { 924514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "funcEntry is null."; 934514f5e3Sopenharmony_ci return false; 944514f5e3Sopenharmony_ci } 954514f5e3Sopenharmony_ci uint32_t cnt = desc.funcEntryDesSize / sizeof(FuncEntryDes); 964514f5e3Sopenharmony_ci ASSERT(cnt <= 2); // 2: jsfunction + deoptimize stub 974514f5e3Sopenharmony_ci for (uint32_t i = 0; i < cnt; i++) { 984514f5e3Sopenharmony_ci if (methodId == EntityId(funcEntry->indexInKindOrMethodId_)) { 994514f5e3Sopenharmony_ci uint64_t codeAddr = funcEntry->codeAddr_ + 1004514f5e3Sopenharmony_ci static_cast<uint64_t>(reinterpret_cast<uintptr_t>(textStart)); 1014514f5e3Sopenharmony_ci SetFuncAddr(codeAddr); 1024514f5e3Sopenharmony_ci break; 1034514f5e3Sopenharmony_ci } 1044514f5e3Sopenharmony_ci funcEntry++; 1054514f5e3Sopenharmony_ci } 1064514f5e3Sopenharmony_ci 1074514f5e3Sopenharmony_ci SetIsFastCall(funcEntry->isFastCall_); 1084514f5e3Sopenharmony_ci SetFpDeltaPrevFrameSp(funcEntry->fpDeltaPrevFrameSp_); 1094514f5e3Sopenharmony_ci SetFuncSize(funcEntry->funcSize_); 1104514f5e3Sopenharmony_ci SetCalleeRegisterNum(funcEntry->calleeRegisterNum_); 1114514f5e3Sopenharmony_ci SetCalleeReg2OffsetArray(funcEntry->CalleeReg2Offset_); 1124514f5e3Sopenharmony_ci return true; 1134514f5e3Sopenharmony_ci} 1144514f5e3Sopenharmony_ci 1154514f5e3Sopenharmony_cibool MachineCode::SetData(const MachineCodeDesc &desc, JSHandle<Method> &method, size_t dataSize) 1164514f5e3Sopenharmony_ci{ 1174514f5e3Sopenharmony_ci DISALLOW_GARBAGE_COLLECTION; 1184514f5e3Sopenharmony_ci if (desc.codeType == MachineCodeType::BASELINE_CODE) { 1194514f5e3Sopenharmony_ci return SetBaselineCodeData(desc, method, dataSize); 1204514f5e3Sopenharmony_ci } 1214514f5e3Sopenharmony_ci 1224514f5e3Sopenharmony_ci SetOSROffset(MachineCode::INVALID_OSR_OFFSET); 1234514f5e3Sopenharmony_ci SetOsrDeoptFlag(false); 1244514f5e3Sopenharmony_ci SetOsrExecuteCnt(0); 1254514f5e3Sopenharmony_ci 1264514f5e3Sopenharmony_ci size_t instrSize = desc.rodataSizeBeforeTextAlign + desc.codeSizeAlign + desc.rodataSizeAfterTextAlign; 1274514f5e3Sopenharmony_ci 1284514f5e3Sopenharmony_ci SetInstructionsSize(instrSize); 1294514f5e3Sopenharmony_ci SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign); 1304514f5e3Sopenharmony_ci SetPayLoadSizeInBytes(dataSize); 1314514f5e3Sopenharmony_ci if (Jit::GetInstance()->IsEnableJitFort()) { 1324514f5e3Sopenharmony_ci SetInstructionsAddr(desc.instructionsAddr); 1334514f5e3Sopenharmony_ci ASSERT(desc.instructionsAddr != 0); 1344514f5e3Sopenharmony_ci ASSERT(dataSize == (desc.funcEntryDesSizeAlign + desc.stackMapSizeAlign) || 1354514f5e3Sopenharmony_ci dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign)); 1364514f5e3Sopenharmony_ci } else { 1374514f5e3Sopenharmony_ci ASSERT(dataSize == (desc.funcEntryDesSizeAlign + instrSize + desc.stackMapSizeAlign)); 1384514f5e3Sopenharmony_ci } 1394514f5e3Sopenharmony_ci if (!SetText(desc)) { 1404514f5e3Sopenharmony_ci return false; 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci if (!SetNonText(desc, method->GetMethodId())) { 1434514f5e3Sopenharmony_ci return false; 1444514f5e3Sopenharmony_ci } 1454514f5e3Sopenharmony_ci 1464514f5e3Sopenharmony_ci uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 1474514f5e3Sopenharmony_ci uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 1484514f5e3Sopenharmony_ci CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 1494514f5e3Sopenharmony_ci LOG_JIT(DEBUG) << "Fast JIT MachineCode :" << methodName << ", " << " text addr:" << 1504514f5e3Sopenharmony_ci reinterpret_cast<void*>(GetText()) << ", size:" << instrSize << 1514514f5e3Sopenharmony_ci ", stackMap addr:" << reinterpret_cast<void*>(stackmapAddr) << 1524514f5e3Sopenharmony_ci ", size:" << desc.stackMapSizeAlign; 1534514f5e3Sopenharmony_ci 1544514f5e3Sopenharmony_ci if (!SetPageProtect(textStart, dataSize)) { 1554514f5e3Sopenharmony_ci LOG_JIT(ERROR) << "MachineCode::SetData SetPageProtect failed"; 1564514f5e3Sopenharmony_ci return false; 1574514f5e3Sopenharmony_ci } 1584514f5e3Sopenharmony_ci return true; 1594514f5e3Sopenharmony_ci} 1604514f5e3Sopenharmony_ci 1614514f5e3Sopenharmony_cibool MachineCode::SetBaselineCodeData(const MachineCodeDesc &desc, 1624514f5e3Sopenharmony_ci JSHandle<Method> &method, size_t dataSize) 1634514f5e3Sopenharmony_ci{ 1644514f5e3Sopenharmony_ci DISALLOW_GARBAGE_COLLECTION; 1654514f5e3Sopenharmony_ci 1664514f5e3Sopenharmony_ci size_t instrSizeAlign = desc.codeSizeAlign; 1674514f5e3Sopenharmony_ci SetInstructionsSize(instrSizeAlign); 1684514f5e3Sopenharmony_ci 1694514f5e3Sopenharmony_ci SetStackMapOrOffsetTableSize(desc.stackMapSizeAlign); 1704514f5e3Sopenharmony_ci if (Jit::GetInstance()->IsEnableJitFort()) { 1714514f5e3Sopenharmony_ci ASSERT(desc.instructionsAddr != 0); 1724514f5e3Sopenharmony_ci ASSERT(dataSize == (desc.stackMapSizeAlign) || // reg. obj 1734514f5e3Sopenharmony_ci dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); // huge obj 1744514f5e3Sopenharmony_ci SetInstructionsAddr(desc.instructionsAddr); 1754514f5e3Sopenharmony_ci } else { 1764514f5e3Sopenharmony_ci ASSERT(dataSize == (instrSizeAlign + desc.stackMapSizeAlign)); 1774514f5e3Sopenharmony_ci } 1784514f5e3Sopenharmony_ci SetPayLoadSizeInBytes(dataSize); 1794514f5e3Sopenharmony_ci 1804514f5e3Sopenharmony_ci uint8_t *textStart = reinterpret_cast<uint8_t*>(GetText()); 1814514f5e3Sopenharmony_ci if (Jit::GetInstance()->IsEnableJitFort()) { 1824514f5e3Sopenharmony_ci // relax assert for now until machine code padding for JitFort resolved 1834514f5e3Sopenharmony_ci ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN) || 1844514f5e3Sopenharmony_ci IsAligned(reinterpret_cast<uintptr_t>(textStart), DATA_ALIGN)); 1854514f5e3Sopenharmony_ci } else { 1864514f5e3Sopenharmony_ci ASSERT(IsAligned(reinterpret_cast<uintptr_t>(textStart), TEXT_ALIGN)); 1874514f5e3Sopenharmony_ci } 1884514f5e3Sopenharmony_ci uint8_t *pText = textStart; 1894514f5e3Sopenharmony_ci 1904514f5e3Sopenharmony_ci if (!Jit::GetInstance()->IsEnableJitFort() || !Jit::GetInstance()->IsEnableAsyncCopyToFort() || 1914514f5e3Sopenharmony_ci !desc.isAsyncCompileMode) { 1924514f5e3Sopenharmony_ci if (MachineCodeCopyToCache(desc, pText) == false) { 1934514f5e3Sopenharmony_ci return false; 1944514f5e3Sopenharmony_ci } 1954514f5e3Sopenharmony_ci } 1964514f5e3Sopenharmony_ci pText += instrSizeAlign; 1974514f5e3Sopenharmony_ci 1984514f5e3Sopenharmony_ci uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 1994514f5e3Sopenharmony_ci if (memcpy_s(stackmapAddr, desc.stackMapOrOffsetTableSize, 2004514f5e3Sopenharmony_ci reinterpret_cast<uint8_t*>(desc.stackMapOrOffsetTableAddr), 2014514f5e3Sopenharmony_ci desc.stackMapOrOffsetTableSize) != EOK) { // LCOV_EXCL_BR_LINE 2024514f5e3Sopenharmony_ci LOG_BASELINEJIT(ERROR) << "memcpy fail in copy fast baselineJIT offsetTable"; 2034514f5e3Sopenharmony_ci return false; 2044514f5e3Sopenharmony_ci } 2054514f5e3Sopenharmony_ci 2064514f5e3Sopenharmony_ci SetFuncAddr(reinterpret_cast<uintptr_t>(textStart)); 2074514f5e3Sopenharmony_ci 2084514f5e3Sopenharmony_ci CString methodName = method->GetRecordNameStr() + "." + CString(method->GetMethodName()); 2094514f5e3Sopenharmony_ci LOG_BASELINEJIT(DEBUG) << "BaselineCode :" << methodName << ", " << " text addr:" << 2104514f5e3Sopenharmony_ci reinterpret_cast<void*>(GetText()) << ", size:" << instrSizeAlign << 2114514f5e3Sopenharmony_ci ", stackMap addr: 0, size: 0"; 2124514f5e3Sopenharmony_ci 2134514f5e3Sopenharmony_ci if (!SetPageProtect(textStart, dataSize)) { 2144514f5e3Sopenharmony_ci LOG_BASELINEJIT(ERROR) << "MachineCode::SetBaseLineCodeData SetPageProtect failed"; 2154514f5e3Sopenharmony_ci return false; 2164514f5e3Sopenharmony_ci } 2174514f5e3Sopenharmony_ci return true; 2184514f5e3Sopenharmony_ci} 2194514f5e3Sopenharmony_ci 2204514f5e3Sopenharmony_cibool MachineCode::IsInText(const uintptr_t pc) const 2214514f5e3Sopenharmony_ci{ 2224514f5e3Sopenharmony_ci uintptr_t textStart = GetText(); 2234514f5e3Sopenharmony_ci uintptr_t textEnd = textStart + GetTextSize(); 2244514f5e3Sopenharmony_ci return textStart <= pc && pc < textEnd; 2254514f5e3Sopenharmony_ci} 2264514f5e3Sopenharmony_ci 2274514f5e3Sopenharmony_cistd::tuple<uint64_t, uint8_t*, int, kungfu::CalleeRegAndOffsetVec> MachineCode::CalCallSiteInfo() const 2284514f5e3Sopenharmony_ci{ 2294514f5e3Sopenharmony_ci uintptr_t textStart = GetText(); 2304514f5e3Sopenharmony_ci uint8_t *stackmapAddr = GetStackMapOrOffsetTableAddress(); 2314514f5e3Sopenharmony_ci ASSERT(stackmapAddr != nullptr); 2324514f5e3Sopenharmony_ci 2334514f5e3Sopenharmony_ci int delta = GetFpDeltaPrevFrameSp(); 2344514f5e3Sopenharmony_ci kungfu::CalleeRegAndOffsetVec calleeRegInfo; 2354514f5e3Sopenharmony_ci for (uint32_t j = 0; j < GetCalleeRegisterNum(); j++) { 2364514f5e3Sopenharmony_ci kungfu::LLVMStackMapType::DwarfRegType reg = 2374514f5e3Sopenharmony_ci static_cast<kungfu::LLVMStackMapType::DwarfRegType>(GetCalleeReg2OffsetArray(2 * j)); 2384514f5e3Sopenharmony_ci kungfu::LLVMStackMapType::OffsetType offset = 2394514f5e3Sopenharmony_ci static_cast<kungfu::LLVMStackMapType::OffsetType>(GetCalleeReg2OffsetArray(2 * j + 1)); 2404514f5e3Sopenharmony_ci kungfu::LLVMStackMapType::DwarfRegAndOffsetType regAndOffset = std::make_pair(reg, offset); 2414514f5e3Sopenharmony_ci calleeRegInfo.emplace_back(regAndOffset); 2424514f5e3Sopenharmony_ci } 2434514f5e3Sopenharmony_ci auto ret = std::make_tuple(textStart, stackmapAddr, delta, calleeRegInfo); 2444514f5e3Sopenharmony_ci return ret; 2454514f5e3Sopenharmony_ci} 2464514f5e3Sopenharmony_ci 2474514f5e3Sopenharmony_ciuintptr_t MachineCode::GetText() const 2484514f5e3Sopenharmony_ci{ 2494514f5e3Sopenharmony_ci if (Jit::GetInstance()->IsEnableJitFort()) { 2504514f5e3Sopenharmony_ci return GetInstructionsAddr(); 2514514f5e3Sopenharmony_ci } else { 2524514f5e3Sopenharmony_ci return GetNonTextAddress(); 2534514f5e3Sopenharmony_ci } 2544514f5e3Sopenharmony_ci} 2554514f5e3Sopenharmony_ci 2564514f5e3Sopenharmony_ciuint8_t *MachineCode::GetStackMapOrOffsetTableAddress() const 2574514f5e3Sopenharmony_ci{ 2584514f5e3Sopenharmony_ci if (Jit::GetInstance()->IsEnableJitFort()) { 2594514f5e3Sopenharmony_ci // stackmap immediately follows MachineCode NonText area 2604514f5e3Sopenharmony_ci return reinterpret_cast<uint8_t*>(GetNonTextAddress()); 2614514f5e3Sopenharmony_ci } else { 2624514f5e3Sopenharmony_ci return reinterpret_cast<uint8_t*>(GetText() + GetInstructionsSize()); 2634514f5e3Sopenharmony_ci } 2644514f5e3Sopenharmony_ci} 2654514f5e3Sopenharmony_ci 2664514f5e3Sopenharmony_civoid MachineCode::ProcessMarkObject() 2674514f5e3Sopenharmony_ci{ 2684514f5e3Sopenharmony_ci Region *region = Region::ObjectAddressToRange(this); 2694514f5e3Sopenharmony_ci Heap *localHeap = reinterpret_cast<Heap *>(region->GetLocalHeap()); 2704514f5e3Sopenharmony_ci if (!localHeap) { 2714514f5e3Sopenharmony_ci // it is a huge machine code object. skip 2724514f5e3Sopenharmony_ci return; 2734514f5e3Sopenharmony_ci } 2744514f5e3Sopenharmony_ci ASSERT(localHeap->GetMachineCodeSpace()); 2754514f5e3Sopenharmony_ci if (localHeap->GetMachineCodeSpace()) { 2764514f5e3Sopenharmony_ci localHeap->GetMachineCodeSpace()->MarkJitFortMemAlive(this); 2774514f5e3Sopenharmony_ci } 2784514f5e3Sopenharmony_ci} 2794514f5e3Sopenharmony_ci 2804514f5e3Sopenharmony_ci} // namespace panda::ecmascript 281