14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 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 <chrono>
174514f5e3Sopenharmony_ci#include <iostream>
184514f5e3Sopenharmony_ci#include <csignal>  // NOLINTNEXTLINE(modernize-deprecated-headers)
194514f5e3Sopenharmony_ci#include <vector>
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_ci#include "ecmascript/compiler/jit_compiler.h"
224514f5e3Sopenharmony_ci#include "ecmascript/compiler/baseline/baseline_compiler.h"
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_ci#include "ecmascript/jit/jit_task.h"
254514f5e3Sopenharmony_ci#include "ecmascript/log.h"
264514f5e3Sopenharmony_ci#include "ecmascript/napi/include/jsnapi.h"
274514f5e3Sopenharmony_ci#include "ecmascript/platform/file.h"
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_cinamespace panda::ecmascript::kungfu {
304514f5e3Sopenharmony_ciJitCompiler *JitCompiler::GetInstance(JSRuntimeOptions *options)
314514f5e3Sopenharmony_ci{
324514f5e3Sopenharmony_ci    static JitCompiler instance(options);
334514f5e3Sopenharmony_ci    return &instance;
344514f5e3Sopenharmony_ci}
354514f5e3Sopenharmony_ci
364514f5e3Sopenharmony_civoid JitCompiler::UpdatePassOptions(CompilationEnv *env)
374514f5e3Sopenharmony_ci{
384514f5e3Sopenharmony_ci    EcmaVM *vm = env->GetHostThread()->GetEcmaVM();
394514f5e3Sopenharmony_ci    bool builtinsLazyEnabled = vm->GetJSOptions().IsWorker() && vm->GetJSOptions().GetEnableBuiltinsLazy();
404514f5e3Sopenharmony_ci    if (builtinsLazyEnabled) {
414514f5e3Sopenharmony_ci        passOptions_.SetLoweringBuiltin(false);
424514f5e3Sopenharmony_ci    }
434514f5e3Sopenharmony_ci}
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_ciJitCompilationOptions::JitCompilationOptions(JSRuntimeOptions runtimeOptions)
464514f5e3Sopenharmony_ci{
474514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_AMD64)
484514f5e3Sopenharmony_ci    triple_ = TARGET_X64;
494514f5e3Sopenharmony_ci#elif defined(PANDA_TARGET_ARM64)
504514f5e3Sopenharmony_ci    triple_ = TARGET_AARCH64;
514514f5e3Sopenharmony_ci#else
524514f5e3Sopenharmony_ci    LOG_JIT(FATAL) << "jit unsupport arch";
534514f5e3Sopenharmony_ci    UNREACHABLE();
544514f5e3Sopenharmony_ci#endif
554514f5e3Sopenharmony_ci    // refactor: remove JitCompilationOptions, reuse CompilationOptions
564514f5e3Sopenharmony_ci    optLevel_ = runtimeOptions.GetOptLevel();
574514f5e3Sopenharmony_ci    relocMode_ = runtimeOptions.GetRelocMode();
584514f5e3Sopenharmony_ci    logOption_ = runtimeOptions.GetCompilerLogOption();
594514f5e3Sopenharmony_ci    logMethodsList_ = runtimeOptions.GetMethodsListForLog();
604514f5e3Sopenharmony_ci    compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime();
614514f5e3Sopenharmony_ci    deviceIsScreenOff_ = runtimeOptions.GetDeviceState();
624514f5e3Sopenharmony_ci    deviceThermalLevel_ = runtimeOptions.GetThermalLevel();
634514f5e3Sopenharmony_ci    hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold();
644514f5e3Sopenharmony_ci    profilerIn_ = std::string(runtimeOptions.GetPGOProfilerPath());
654514f5e3Sopenharmony_ci    isEnableArrayBoundsCheckElimination_ = runtimeOptions.IsEnableArrayBoundsCheckElimination();
664514f5e3Sopenharmony_ci    isEnableTypeLowering_ = (runtimeOptions.IsEnableTypeLowering()) && (!runtimeOptions.IsEnableJitFastCompile());
674514f5e3Sopenharmony_ci    isEnableEarlyElimination_ = runtimeOptions.IsEnableEarlyElimination();
684514f5e3Sopenharmony_ci    isEnableLaterElimination_ = runtimeOptions.IsEnableLaterElimination();
694514f5e3Sopenharmony_ci    isEnableValueNumbering_ = runtimeOptions.IsEnableValueNumbering();
704514f5e3Sopenharmony_ci    isEnableOptInlining_ = runtimeOptions.IsEnableAPPJIT() ? false : runtimeOptions.IsEnableOptInlining();
714514f5e3Sopenharmony_ci    isEnableOptString_ = runtimeOptions.IsEnableOptString();
724514f5e3Sopenharmony_ci    isEnableOptPGOType_ = runtimeOptions.IsEnableOptPGOType();
734514f5e3Sopenharmony_ci    isEnableOptTrackField_ = runtimeOptions.IsEnableOptTrackField();
744514f5e3Sopenharmony_ci    isEnableOptLoopPeeling_ = runtimeOptions.IsEnableOptLoopPeeling();
754514f5e3Sopenharmony_ci    isEnableOptOnHeapCheck_ = runtimeOptions.IsEnableOptOnHeapCheck();
764514f5e3Sopenharmony_ci    isEnableOptLoopInvariantCodeMotion_ = runtimeOptions.IsEnableOptLoopInvariantCodeMotion();
774514f5e3Sopenharmony_ci    isEnableOptConstantFolding_ = runtimeOptions.IsEnableOptConstantFolding();
784514f5e3Sopenharmony_ci    isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization();
794514f5e3Sopenharmony_ci    isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline();
804514f5e3Sopenharmony_ci    isEnableLoweringBuiltin_ = runtimeOptions.IsEnableLoweringBuiltin();
814514f5e3Sopenharmony_ci}
824514f5e3Sopenharmony_ci
834514f5e3Sopenharmony_civoid JitCompiler::Init(JSRuntimeOptions runtimeOptions)
844514f5e3Sopenharmony_ci{
854514f5e3Sopenharmony_ci    BytecodeStubCSigns::Initialize();
864514f5e3Sopenharmony_ci    CommonStubCSigns::Initialize();
874514f5e3Sopenharmony_ci    BuiltinsStubCSigns::Initialize();
884514f5e3Sopenharmony_ci    RuntimeStubCSigns::Initialize();
894514f5e3Sopenharmony_ci
904514f5e3Sopenharmony_ci    JitCompilationOptions jitOptions(runtimeOptions);
914514f5e3Sopenharmony_ci    jitOptions_ = jitOptions;
924514f5e3Sopenharmony_ci    PassOptions::Builder optionsBuilder;
934514f5e3Sopenharmony_ci    passOptions_ =
944514f5e3Sopenharmony_ci        optionsBuilder.EnableArrayBoundsCheckElimination(jitOptions_.isEnableArrayBoundsCheckElimination_)
954514f5e3Sopenharmony_ci            .EnableTypeLowering(jitOptions_.isEnableTypeLowering_)
964514f5e3Sopenharmony_ci            .EnableEarlyElimination(jitOptions_.isEnableEarlyElimination_)
974514f5e3Sopenharmony_ci            .EnableLaterElimination(jitOptions_.isEnableLaterElimination_)
984514f5e3Sopenharmony_ci            .EnableValueNumbering(jitOptions_.isEnableValueNumbering_)
994514f5e3Sopenharmony_ci            .EnableOptInlining(jitOptions_.isEnableOptInlining_)
1004514f5e3Sopenharmony_ci            .EnableOptString(jitOptions_.isEnableOptString_)
1014514f5e3Sopenharmony_ci            .EnableOptPGOType(jitOptions_.isEnableOptPGOType_)
1024514f5e3Sopenharmony_ci            .EnableOptTrackField(jitOptions_.isEnableOptTrackField_)
1034514f5e3Sopenharmony_ci            .EnableOptLoopPeeling(jitOptions_.isEnableOptLoopPeeling_)
1044514f5e3Sopenharmony_ci            .EnableOptLoopInvariantCodeMotion(jitOptions_.isEnableOptLoopInvariantCodeMotion_)
1054514f5e3Sopenharmony_ci            .EnableOptConstantFolding(jitOptions_.isEnableOptConstantFolding_)
1064514f5e3Sopenharmony_ci            .EnableLexenvSpecialization(jitOptions_.isEnableLexenvSpecialization_)
1074514f5e3Sopenharmony_ci            .EnableInlineNative(jitOptions_.isEnableNativeInline_)
1084514f5e3Sopenharmony_ci            .EnableLoweringBuiltin(jitOptions_.isEnableLoweringBuiltin_)
1094514f5e3Sopenharmony_ci            .Build();
1104514f5e3Sopenharmony_ci}
1114514f5e3Sopenharmony_ci
1124514f5e3Sopenharmony_ciJitCompilerTask *JitCompilerTask::CreateJitCompilerTask(JitTask *jitTask)
1134514f5e3Sopenharmony_ci{
1144514f5e3Sopenharmony_ci    return new (std::nothrow) JitCompilerTask(jitTask);
1154514f5e3Sopenharmony_ci}
1164514f5e3Sopenharmony_ci
1174514f5e3Sopenharmony_cibool JitCompilerTask::Compile()
1184514f5e3Sopenharmony_ci{
1194514f5e3Sopenharmony_ci    if (compilerTier_ == CompilerTier::BASELINE) {
1204514f5e3Sopenharmony_ci        auto baselineCompiler = new (std::nothrow) BaselineCompiler(jitCompilationEnv_->GetHostThread()->GetEcmaVM(),
1214514f5e3Sopenharmony_ci            jitCompilationEnv_.get());
1224514f5e3Sopenharmony_ci        if (baselineCompiler == nullptr) {
1234514f5e3Sopenharmony_ci            return false;
1244514f5e3Sopenharmony_ci        }
1254514f5e3Sopenharmony_ci        baselineCompiler_.reset(baselineCompiler);
1264514f5e3Sopenharmony_ci        baselineCompiler_->Compile(jitCompilationEnv_->GetJSPandaFile(), jitCompilationEnv_->GetMethodLiteral());
1274514f5e3Sopenharmony_ci        return true;
1284514f5e3Sopenharmony_ci    }
1294514f5e3Sopenharmony_ci
1304514f5e3Sopenharmony_ci    JitCompiler *jitCompiler = JitCompiler::GetInstance();
1314514f5e3Sopenharmony_ci    jitCompiler->UpdatePassOptions(jitCompilationEnv_.get());
1324514f5e3Sopenharmony_ci    auto jitPassManager = new (std::nothrow) JitPassManager(jitCompilationEnv_.get(),
1334514f5e3Sopenharmony_ci                                                            jitCompiler->GetJitOptions().triple_,
1344514f5e3Sopenharmony_ci                                                            jitCompiler->GetJitOptions().optLevel_,
1354514f5e3Sopenharmony_ci                                                            jitCompiler->GetJitOptions().relocMode_,
1364514f5e3Sopenharmony_ci                                                            &jitCompiler->GetCompilerLog(),
1374514f5e3Sopenharmony_ci                                                            &jitCompiler->GetLogList(),
1384514f5e3Sopenharmony_ci                                                            jitCompiler->GetProfilerDecoder(),
1394514f5e3Sopenharmony_ci                                                            &jitCompiler->GetPassOptions());
1404514f5e3Sopenharmony_ci    if (jitPassManager == nullptr) {
1414514f5e3Sopenharmony_ci        return false;
1424514f5e3Sopenharmony_ci    }
1434514f5e3Sopenharmony_ci    passManager_.reset(jitPassManager);
1444514f5e3Sopenharmony_ci    auto aotFileGenerator = new (std::nothrow) AOTFileGenerator(&jitCompiler->GetCompilerLog(),
1454514f5e3Sopenharmony_ci        &jitCompiler->GetLogList(), jitCompilationEnv_.get(),
1464514f5e3Sopenharmony_ci        jitCompiler->GetJitOptions().triple_, jitCompilationEnv_->GetJSOptions().IsCompilerEnableLiteCG());
1474514f5e3Sopenharmony_ci    if (aotFileGenerator == nullptr) {
1484514f5e3Sopenharmony_ci        return false;
1494514f5e3Sopenharmony_ci    }
1504514f5e3Sopenharmony_ci    jitCodeGenerator_.reset(aotFileGenerator);
1514514f5e3Sopenharmony_ci    return passManager_->Compile(profileTypeInfo_, *jitCodeGenerator_, offset_);
1524514f5e3Sopenharmony_ci}
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_civoid JitCompilerTask::ReleaseJitPassManager()
1554514f5e3Sopenharmony_ci{
1564514f5e3Sopenharmony_ci    // release passManager before jitCompilerTask release,
1574514f5e3Sopenharmony_ci    // in future release JitCompilerTask when compile finish
1584514f5e3Sopenharmony_ci    JitPassManager *passManager = passManager_.release();
1594514f5e3Sopenharmony_ci    delete passManager;
1604514f5e3Sopenharmony_ci}
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_cibool JitCompilerTask::Finalize(JitTask *jitTask)
1634514f5e3Sopenharmony_ci{
1644514f5e3Sopenharmony_ci    if (jitTask == nullptr) {
1654514f5e3Sopenharmony_ci        return false;
1664514f5e3Sopenharmony_ci    }
1674514f5e3Sopenharmony_ci    if (compilerTier_ == CompilerTier::BASELINE) {
1684514f5e3Sopenharmony_ci        return baselineCompiler_->CollectMemoryCodeInfos(jitTask->GetMachineCodeDesc());
1694514f5e3Sopenharmony_ci    }
1704514f5e3Sopenharmony_ci    jitCodeGenerator_->JitCreateLitecgModule();
1714514f5e3Sopenharmony_ci    bool result = true;
1724514f5e3Sopenharmony_ci    result &= passManager_->RunCg();
1734514f5e3Sopenharmony_ci    result &= jitCodeGenerator_->GetMemoryCodeInfos(jitTask->GetMachineCodeDesc());
1744514f5e3Sopenharmony_ci    ReleaseJitPassManager();
1754514f5e3Sopenharmony_ci    return result;
1764514f5e3Sopenharmony_ci}
1774514f5e3Sopenharmony_ci
1784514f5e3Sopenharmony_ci
1794514f5e3Sopenharmony_cistatic ARK_INLINE bool CopyCodeToFort(MachineCodeDesc &desc)
1804514f5e3Sopenharmony_ci{
1814514f5e3Sopenharmony_ci    uint8_t *pText = reinterpret_cast<uint8_t*>(desc.instructionsAddr);
1824514f5e3Sopenharmony_ci    if (desc.rodataSizeBeforeTextAlign != 0) {
1834514f5e3Sopenharmony_ci        pText += desc.rodataSizeBeforeTextAlign;
1844514f5e3Sopenharmony_ci    }
1854514f5e3Sopenharmony_ci#ifdef JIT_ENABLE_CODE_SIGN
1864514f5e3Sopenharmony_ci    if ((uintptr_t)desc.codeSigner == 0) {
1874514f5e3Sopenharmony_ci        if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
1884514f5e3Sopenharmony_ci            LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
1894514f5e3Sopenharmony_ci            return false;
1904514f5e3Sopenharmony_ci        }
1914514f5e3Sopenharmony_ci    } else {
1924514f5e3Sopenharmony_ci        LOG_JIT(DEBUG) << "Copy: "
1934514f5e3Sopenharmony_ci                       << std::hex << (uintptr_t)pText << " <- "
1944514f5e3Sopenharmony_ci                       << std::hex << (uintptr_t)desc.codeAddr << " size: " << desc.codeSize;
1954514f5e3Sopenharmony_ci        LOG_JIT(DEBUG) << "     codeSigner = " << std::hex << (uintptr_t)desc.codeSigner;
1964514f5e3Sopenharmony_ci        OHOS::Security::CodeSign::JitCodeSignerBase *signer =
1974514f5e3Sopenharmony_ci            reinterpret_cast<OHOS::Security::CodeSign::JitCodeSignerBase*>(desc.codeSigner);
1984514f5e3Sopenharmony_ci        int err = OHOS::Security::CodeSign::CopyToJitCode(
1994514f5e3Sopenharmony_ci            signer, pText, reinterpret_cast<void *>(desc.codeAddr), desc.codeSize);
2004514f5e3Sopenharmony_ci        if (err != EOK) {
2014514f5e3Sopenharmony_ci            LOG_JIT(ERROR) << "     CopyToJitCode failed, err: " << err;
2024514f5e3Sopenharmony_ci            return false;
2034514f5e3Sopenharmony_ci        } else {
2044514f5e3Sopenharmony_ci            LOG_JIT(DEBUG) << "     CopyToJitCode success!!";
2054514f5e3Sopenharmony_ci        }
2064514f5e3Sopenharmony_ci        delete reinterpret_cast<OHOS::Security::CodeSign::JitCodeSignerBase*>(desc.codeSigner);
2074514f5e3Sopenharmony_ci    }
2084514f5e3Sopenharmony_ci#else
2094514f5e3Sopenharmony_ci    if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
2104514f5e3Sopenharmony_ci        LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
2114514f5e3Sopenharmony_ci        return false;
2124514f5e3Sopenharmony_ci    }
2134514f5e3Sopenharmony_ci#endif
2144514f5e3Sopenharmony_ci    return true;
2154514f5e3Sopenharmony_ci}
2164514f5e3Sopenharmony_ci
2174514f5e3Sopenharmony_ciARK_INLINE bool JitCompiler::AllocFromFortAndCopy(CompilationEnv &compilationEnv, MachineCodeDesc &desc)
2184514f5e3Sopenharmony_ci{
2194514f5e3Sopenharmony_ci    ASSERT(compilationEnv.IsJitCompiler());
2204514f5e3Sopenharmony_ci    JSThread *hostThread = static_cast<JitCompilationEnv&>(compilationEnv).GetHostThread();
2214514f5e3Sopenharmony_ci    Jit::JitGCLockHolder lock(hostThread);
2224514f5e3Sopenharmony_ci
2234514f5e3Sopenharmony_ci    size_t size = JitTask::ComputePayLoadSize(desc);
2244514f5e3Sopenharmony_ci    const Heap *heap = hostThread->GetEcmaVM()->GetHeap();
2254514f5e3Sopenharmony_ci
2264514f5e3Sopenharmony_ci    if (desc.isHugeObj) {
2274514f5e3Sopenharmony_ci        Region *region = heap->GetHugeMachineCodeSpace()->AllocateFort(
2284514f5e3Sopenharmony_ci            size + MachineCode::SIZE, hostThread, &desc);
2294514f5e3Sopenharmony_ci        if (!region || !desc.instructionsAddr) {
2304514f5e3Sopenharmony_ci            return false;
2314514f5e3Sopenharmony_ci        }
2324514f5e3Sopenharmony_ci        desc.hugeObjRegion = ToUintPtr(region);
2334514f5e3Sopenharmony_ci    } else {
2344514f5e3Sopenharmony_ci        uintptr_t mem = heap->GetMachineCodeSpace()->JitFortAllocate(&desc);
2354514f5e3Sopenharmony_ci        if (mem == ToUintPtr(nullptr)) {
2364514f5e3Sopenharmony_ci            return false;
2374514f5e3Sopenharmony_ci        }
2384514f5e3Sopenharmony_ci        desc.instructionsAddr = mem;
2394514f5e3Sopenharmony_ci    }
2404514f5e3Sopenharmony_ci
2414514f5e3Sopenharmony_ci    if (!CopyCodeToFort(desc)) {
2424514f5e3Sopenharmony_ci        return false;
2434514f5e3Sopenharmony_ci    }
2444514f5e3Sopenharmony_ci    return true;
2454514f5e3Sopenharmony_ci}
2464514f5e3Sopenharmony_ci
2474514f5e3Sopenharmony_civoid InitJitCompiler(JSRuntimeOptions options)
2484514f5e3Sopenharmony_ci{
2494514f5e3Sopenharmony_ci    JitCompiler *jitCompiler = JitCompiler::GetInstance(&options);
2504514f5e3Sopenharmony_ci    jitCompiler->Init(options);
2514514f5e3Sopenharmony_ci}
2524514f5e3Sopenharmony_ci
2534514f5e3Sopenharmony_civoid *CreateJitCompilerTask(JitTask *jitTask)
2544514f5e3Sopenharmony_ci{
2554514f5e3Sopenharmony_ci    if (jitTask == nullptr) {
2564514f5e3Sopenharmony_ci        return nullptr;
2574514f5e3Sopenharmony_ci    }
2584514f5e3Sopenharmony_ci    return JitCompilerTask::CreateJitCompilerTask(jitTask);
2594514f5e3Sopenharmony_ci}
2604514f5e3Sopenharmony_ci
2614514f5e3Sopenharmony_cibool JitCompile(void *compilerTask, JitTask *jitTask)
2624514f5e3Sopenharmony_ci{
2634514f5e3Sopenharmony_ci    if (jitTask == nullptr || compilerTask == nullptr) {
2644514f5e3Sopenharmony_ci        return false;
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci    auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask);
2674514f5e3Sopenharmony_ci    return jitCompilerTask->Compile();
2684514f5e3Sopenharmony_ci}
2694514f5e3Sopenharmony_ci
2704514f5e3Sopenharmony_cibool JitFinalize(void *compilerTask, JitTask *jitTask)
2714514f5e3Sopenharmony_ci{
2724514f5e3Sopenharmony_ci    if (jitTask == nullptr || compilerTask == nullptr) {
2734514f5e3Sopenharmony_ci        return false;
2744514f5e3Sopenharmony_ci    }
2754514f5e3Sopenharmony_ci    auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask);
2764514f5e3Sopenharmony_ci    return jitCompilerTask->Finalize(jitTask);
2774514f5e3Sopenharmony_ci}
2784514f5e3Sopenharmony_ci
2794514f5e3Sopenharmony_civoid DeleteJitCompile(void *handle)
2804514f5e3Sopenharmony_ci{
2814514f5e3Sopenharmony_ci    if (handle == nullptr) {
2824514f5e3Sopenharmony_ci        return;
2834514f5e3Sopenharmony_ci    }
2844514f5e3Sopenharmony_ci    delete reinterpret_cast<JitCompilerTask*>(handle);
2854514f5e3Sopenharmony_ci}
2864514f5e3Sopenharmony_ci}  // namespace panda::ecmascript::kungfu
287