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