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