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