1/* 2 * Copyright (c) 2023 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 <chrono> 17#include <iostream> 18#include <csignal> // NOLINTNEXTLINE(modernize-deprecated-headers) 19#include <vector> 20 21#include "ecmascript/compiler/jit_compiler.h" 22#include "ecmascript/compiler/baseline/baseline_compiler.h" 23 24#include "ecmascript/jit/jit_task.h" 25#include "ecmascript/log.h" 26#include "ecmascript/napi/include/jsnapi.h" 27#include "ecmascript/platform/file.h" 28 29namespace panda::ecmascript::kungfu { 30JitCompiler *JitCompiler::GetInstance(JSRuntimeOptions *options) 31{ 32 static JitCompiler instance(options); 33 return &instance; 34} 35 36void JitCompiler::UpdatePassOptions(CompilationEnv *env) 37{ 38 EcmaVM *vm = env->GetHostThread()->GetEcmaVM(); 39 bool builtinsLazyEnabled = vm->GetJSOptions().IsWorker() && vm->GetJSOptions().GetEnableBuiltinsLazy(); 40 if (builtinsLazyEnabled) { 41 passOptions_.SetLoweringBuiltin(false); 42 } 43} 44 45JitCompilationOptions::JitCompilationOptions(JSRuntimeOptions runtimeOptions) 46{ 47#if defined(PANDA_TARGET_AMD64) 48 triple_ = TARGET_X64; 49#elif defined(PANDA_TARGET_ARM64) 50 triple_ = TARGET_AARCH64; 51#else 52 LOG_JIT(FATAL) << "jit unsupport arch"; 53 UNREACHABLE(); 54#endif 55 // refactor: remove JitCompilationOptions, reuse CompilationOptions 56 optLevel_ = runtimeOptions.GetOptLevel(); 57 relocMode_ = runtimeOptions.GetRelocMode(); 58 logOption_ = runtimeOptions.GetCompilerLogOption(); 59 logMethodsList_ = runtimeOptions.GetMethodsListForLog(); 60 compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime(); 61 deviceIsScreenOff_ = runtimeOptions.GetDeviceState(); 62 deviceThermalLevel_ = runtimeOptions.GetThermalLevel(); 63 hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold(); 64 profilerIn_ = std::string(runtimeOptions.GetPGOProfilerPath()); 65 isEnableArrayBoundsCheckElimination_ = runtimeOptions.IsEnableArrayBoundsCheckElimination(); 66 isEnableTypeLowering_ = (runtimeOptions.IsEnableTypeLowering()) && (!runtimeOptions.IsEnableJitFastCompile()); 67 isEnableEarlyElimination_ = runtimeOptions.IsEnableEarlyElimination(); 68 isEnableLaterElimination_ = runtimeOptions.IsEnableLaterElimination(); 69 isEnableValueNumbering_ = runtimeOptions.IsEnableValueNumbering(); 70 isEnableOptInlining_ = runtimeOptions.IsEnableAPPJIT() ? false : runtimeOptions.IsEnableOptInlining(); 71 isEnableOptString_ = runtimeOptions.IsEnableOptString(); 72 isEnableOptPGOType_ = runtimeOptions.IsEnableOptPGOType(); 73 isEnableOptTrackField_ = runtimeOptions.IsEnableOptTrackField(); 74 isEnableOptLoopPeeling_ = runtimeOptions.IsEnableOptLoopPeeling(); 75 isEnableOptOnHeapCheck_ = runtimeOptions.IsEnableOptOnHeapCheck(); 76 isEnableOptLoopInvariantCodeMotion_ = runtimeOptions.IsEnableOptLoopInvariantCodeMotion(); 77 isEnableOptConstantFolding_ = runtimeOptions.IsEnableOptConstantFolding(); 78 isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization(); 79 isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline(); 80 isEnableLoweringBuiltin_ = runtimeOptions.IsEnableLoweringBuiltin(); 81} 82 83void JitCompiler::Init(JSRuntimeOptions runtimeOptions) 84{ 85 BytecodeStubCSigns::Initialize(); 86 CommonStubCSigns::Initialize(); 87 BuiltinsStubCSigns::Initialize(); 88 RuntimeStubCSigns::Initialize(); 89 90 JitCompilationOptions jitOptions(runtimeOptions); 91 jitOptions_ = jitOptions; 92 PassOptions::Builder optionsBuilder; 93 passOptions_ = 94 optionsBuilder.EnableArrayBoundsCheckElimination(jitOptions_.isEnableArrayBoundsCheckElimination_) 95 .EnableTypeLowering(jitOptions_.isEnableTypeLowering_) 96 .EnableEarlyElimination(jitOptions_.isEnableEarlyElimination_) 97 .EnableLaterElimination(jitOptions_.isEnableLaterElimination_) 98 .EnableValueNumbering(jitOptions_.isEnableValueNumbering_) 99 .EnableOptInlining(jitOptions_.isEnableOptInlining_) 100 .EnableOptString(jitOptions_.isEnableOptString_) 101 .EnableOptPGOType(jitOptions_.isEnableOptPGOType_) 102 .EnableOptTrackField(jitOptions_.isEnableOptTrackField_) 103 .EnableOptLoopPeeling(jitOptions_.isEnableOptLoopPeeling_) 104 .EnableOptLoopInvariantCodeMotion(jitOptions_.isEnableOptLoopInvariantCodeMotion_) 105 .EnableOptConstantFolding(jitOptions_.isEnableOptConstantFolding_) 106 .EnableLexenvSpecialization(jitOptions_.isEnableLexenvSpecialization_) 107 .EnableInlineNative(jitOptions_.isEnableNativeInline_) 108 .EnableLoweringBuiltin(jitOptions_.isEnableLoweringBuiltin_) 109 .Build(); 110} 111 112JitCompilerTask *JitCompilerTask::CreateJitCompilerTask(JitTask *jitTask) 113{ 114 return new (std::nothrow) JitCompilerTask(jitTask); 115} 116 117bool JitCompilerTask::Compile() 118{ 119 if (compilerTier_ == CompilerTier::BASELINE) { 120 auto baselineCompiler = new (std::nothrow) BaselineCompiler(jitCompilationEnv_->GetHostThread()->GetEcmaVM(), 121 jitCompilationEnv_.get()); 122 if (baselineCompiler == nullptr) { 123 return false; 124 } 125 baselineCompiler_.reset(baselineCompiler); 126 baselineCompiler_->Compile(jitCompilationEnv_->GetJSPandaFile(), jitCompilationEnv_->GetMethodLiteral()); 127 return true; 128 } 129 130 JitCompiler *jitCompiler = JitCompiler::GetInstance(); 131 jitCompiler->UpdatePassOptions(jitCompilationEnv_.get()); 132 auto jitPassManager = new (std::nothrow) JitPassManager(jitCompilationEnv_.get(), 133 jitCompiler->GetJitOptions().triple_, 134 jitCompiler->GetJitOptions().optLevel_, 135 jitCompiler->GetJitOptions().relocMode_, 136 &jitCompiler->GetCompilerLog(), 137 &jitCompiler->GetLogList(), 138 jitCompiler->GetProfilerDecoder(), 139 &jitCompiler->GetPassOptions()); 140 if (jitPassManager == nullptr) { 141 return false; 142 } 143 passManager_.reset(jitPassManager); 144 auto aotFileGenerator = new (std::nothrow) AOTFileGenerator(&jitCompiler->GetCompilerLog(), 145 &jitCompiler->GetLogList(), jitCompilationEnv_.get(), 146 jitCompiler->GetJitOptions().triple_, jitCompilationEnv_->GetJSOptions().IsCompilerEnableLiteCG()); 147 if (aotFileGenerator == nullptr) { 148 return false; 149 } 150 jitCodeGenerator_.reset(aotFileGenerator); 151 return passManager_->Compile(profileTypeInfo_, *jitCodeGenerator_, offset_); 152} 153 154void JitCompilerTask::ReleaseJitPassManager() 155{ 156 // release passManager before jitCompilerTask release, 157 // in future release JitCompilerTask when compile finish 158 JitPassManager *passManager = passManager_.release(); 159 delete passManager; 160} 161 162bool JitCompilerTask::Finalize(JitTask *jitTask) 163{ 164 if (jitTask == nullptr) { 165 return false; 166 } 167 if (compilerTier_ == CompilerTier::BASELINE) { 168 return baselineCompiler_->CollectMemoryCodeInfos(jitTask->GetMachineCodeDesc()); 169 } 170 jitCodeGenerator_->JitCreateLitecgModule(); 171 bool result = true; 172 result &= passManager_->RunCg(); 173 result &= jitCodeGenerator_->GetMemoryCodeInfos(jitTask->GetMachineCodeDesc()); 174 ReleaseJitPassManager(); 175 return result; 176} 177 178 179static ARK_INLINE bool CopyCodeToFort(MachineCodeDesc &desc) 180{ 181 uint8_t *pText = reinterpret_cast<uint8_t*>(desc.instructionsAddr); 182 if (desc.rodataSizeBeforeTextAlign != 0) { 183 pText += desc.rodataSizeBeforeTextAlign; 184 } 185#ifdef JIT_ENABLE_CODE_SIGN 186 if ((uintptr_t)desc.codeSigner == 0) { 187 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) { 188 LOG_JIT(ERROR) << "memcpy failed in CopyToCache"; 189 return false; 190 } 191 } else { 192 LOG_JIT(DEBUG) << "Copy: " 193 << std::hex << (uintptr_t)pText << " <- " 194 << std::hex << (uintptr_t)desc.codeAddr << " size: " << desc.codeSize; 195 LOG_JIT(DEBUG) << " codeSigner = " << std::hex << (uintptr_t)desc.codeSigner; 196 OHOS::Security::CodeSign::JitCodeSignerBase *signer = 197 reinterpret_cast<OHOS::Security::CodeSign::JitCodeSignerBase*>(desc.codeSigner); 198 int err = OHOS::Security::CodeSign::CopyToJitCode( 199 signer, pText, reinterpret_cast<void *>(desc.codeAddr), desc.codeSize); 200 if (err != EOK) { 201 LOG_JIT(ERROR) << " CopyToJitCode failed, err: " << err; 202 return false; 203 } else { 204 LOG_JIT(DEBUG) << " CopyToJitCode success!!"; 205 } 206 delete reinterpret_cast<OHOS::Security::CodeSign::JitCodeSignerBase*>(desc.codeSigner); 207 } 208#else 209 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) { 210 LOG_JIT(ERROR) << "memcpy failed in CopyToCache"; 211 return false; 212 } 213#endif 214 return true; 215} 216 217ARK_INLINE bool JitCompiler::AllocFromFortAndCopy(CompilationEnv &compilationEnv, MachineCodeDesc &desc) 218{ 219 ASSERT(compilationEnv.IsJitCompiler()); 220 JSThread *hostThread = static_cast<JitCompilationEnv&>(compilationEnv).GetHostThread(); 221 Jit::JitGCLockHolder lock(hostThread); 222 223 size_t size = JitTask::ComputePayLoadSize(desc); 224 const Heap *heap = hostThread->GetEcmaVM()->GetHeap(); 225 226 if (desc.isHugeObj) { 227 Region *region = heap->GetHugeMachineCodeSpace()->AllocateFort( 228 size + MachineCode::SIZE, hostThread, &desc); 229 if (!region || !desc.instructionsAddr) { 230 return false; 231 } 232 desc.hugeObjRegion = ToUintPtr(region); 233 } else { 234 uintptr_t mem = heap->GetMachineCodeSpace()->JitFortAllocate(&desc); 235 if (mem == ToUintPtr(nullptr)) { 236 return false; 237 } 238 desc.instructionsAddr = mem; 239 } 240 241 if (!CopyCodeToFort(desc)) { 242 return false; 243 } 244 return true; 245} 246 247void InitJitCompiler(JSRuntimeOptions options) 248{ 249 JitCompiler *jitCompiler = JitCompiler::GetInstance(&options); 250 jitCompiler->Init(options); 251} 252 253void *CreateJitCompilerTask(JitTask *jitTask) 254{ 255 if (jitTask == nullptr) { 256 return nullptr; 257 } 258 return JitCompilerTask::CreateJitCompilerTask(jitTask); 259} 260 261bool JitCompile(void *compilerTask, JitTask *jitTask) 262{ 263 if (jitTask == nullptr || compilerTask == nullptr) { 264 return false; 265 } 266 auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask); 267 return jitCompilerTask->Compile(); 268} 269 270bool JitFinalize(void *compilerTask, JitTask *jitTask) 271{ 272 if (jitTask == nullptr || compilerTask == nullptr) { 273 return false; 274 } 275 auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask); 276 return jitCompilerTask->Finalize(jitTask); 277} 278 279void DeleteJitCompile(void *handle) 280{ 281 if (handle == nullptr) { 282 return; 283 } 284 delete reinterpret_cast<JitCompilerTask*>(handle); 285} 286} // namespace panda::ecmascript::kungfu 287