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 #include "ecmascript/jit/rewriter/reloc_rewriter.h"
19 #include "ecmascript/jit/rewriter/reloc_rewriter_aarch64.h"
20
21
22 namespace panda::ecmascript::kungfu {
GetInstance(JSRuntimeOptions * options)23 JitCompiler *JitCompiler::GetInstance(JSRuntimeOptions *options)
24 {
25 static JitCompiler instance(options);
26 return &instance;
27 }
28
UpdatePassOptions(CompilationEnv * env)29 void JitCompiler::UpdatePassOptions(CompilationEnv *env)
30 {
31 EcmaVM *vm = env->GetHostThread()->GetEcmaVM();
32 bool builtinsLazyEnabled = vm->GetJSOptions().IsWorker() && vm->GetJSOptions().GetEnableBuiltinsLazy();
33 passOptions_.SetLoweringBuiltin(!builtinsLazyEnabled);
34 }
35
JitCompilationOptions(JSRuntimeOptions runtimeOptions)36 JitCompilationOptions::JitCompilationOptions(JSRuntimeOptions runtimeOptions)
37 {
38 #if defined(PANDA_TARGET_AMD64)
39 triple_ = TARGET_X64;
40 #elif defined(PANDA_TARGET_ARM64)
41 triple_ = TARGET_AARCH64;
42 #else
43 LOG_JIT(FATAL) << "jit unsupport arch";
44 UNREACHABLE();
45 #endif
46 // refactor: remove JitCompilationOptions, reuse CompilationOptions
47 optLevel_ = runtimeOptions.GetOptLevel();
48 relocMode_ = runtimeOptions.GetRelocMode();
49 logOption_ = runtimeOptions.GetCompilerLogOption();
50 logMethodsList_ = runtimeOptions.GetMethodsListForLog();
51 compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime();
52 deviceIsScreenOff_ = runtimeOptions.GetDeviceState();
53 deviceThermalLevel_ = runtimeOptions.GetThermalLevel();
54 hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold();
55 profilerIn_ = std::string(runtimeOptions.GetPGOProfilerPath());
56 isEnableArrayBoundsCheckElimination_ = runtimeOptions.IsEnableArrayBoundsCheckElimination();
57 isEnableTypeLowering_ = (runtimeOptions.IsEnableTypeLowering()) && (!runtimeOptions.IsEnableJitFastCompile());
58 isEnableEarlyElimination_ = runtimeOptions.IsEnableEarlyElimination();
59 isEnableLaterElimination_ = runtimeOptions.IsEnableLaterElimination();
60 isEnableValueNumbering_ = runtimeOptions.IsEnableValueNumbering();
61 isEnableOptInlining_ = runtimeOptions.IsEnableAPPJIT() ? false : runtimeOptions.IsEnableOptInlining();
62 isEnableOptString_ = runtimeOptions.IsEnableOptString();
63 isEnableOptPGOType_ = runtimeOptions.IsEnableOptPGOType();
64 isEnableOptTrackField_ = runtimeOptions.IsEnableOptTrackField();
65 isEnableOptLoopPeeling_ = runtimeOptions.IsEnableOptLoopPeeling();
66 isEnableOptOnHeapCheck_ = runtimeOptions.IsEnableOptOnHeapCheck();
67 isEnableOptLoopInvariantCodeMotion_ = runtimeOptions.IsEnableOptLoopInvariantCodeMotion();
68 isEnableOptConstantFolding_ = runtimeOptions.IsEnableOptConstantFolding();
69 isEnableLexenvSpecialization_ = runtimeOptions.IsEnableLexenvSpecialization();
70 isEnableNativeInline_ = runtimeOptions.IsEnableNativeInline();
71 isEnableLoweringBuiltin_ = runtimeOptions.IsEnableLoweringBuiltin();
72 }
73
Init(JSRuntimeOptions runtimeOptions)74 void JitCompiler::Init(JSRuntimeOptions runtimeOptions)
75 {
76 BytecodeStubCSigns::Initialize();
77 CommonStubCSigns::Initialize();
78 BuiltinsStubCSigns::Initialize();
79 RuntimeStubCSigns::Initialize();
80
81 JitCompilationOptions jitOptions(runtimeOptions);
82 jitOptions_ = jitOptions;
83 PassOptions::Builder optionsBuilder;
84 passOptions_ =
85 optionsBuilder.EnableArrayBoundsCheckElimination(jitOptions_.isEnableArrayBoundsCheckElimination_)
86 .EnableTypeLowering(jitOptions_.isEnableTypeLowering_)
87 .EnableEarlyElimination(jitOptions_.isEnableEarlyElimination_)
88 .EnableLaterElimination(jitOptions_.isEnableLaterElimination_)
89 .EnableValueNumbering(jitOptions_.isEnableValueNumbering_)
90 .EnableOptInlining(jitOptions_.isEnableOptInlining_)
91 .EnableOptString(jitOptions_.isEnableOptString_)
92 .EnableOptPGOType(jitOptions_.isEnableOptPGOType_)
93 .EnableOptTrackField(jitOptions_.isEnableOptTrackField_)
94 .EnableOptLoopPeeling(jitOptions_.isEnableOptLoopPeeling_)
95 .EnableOptLoopInvariantCodeMotion(jitOptions_.isEnableOptLoopInvariantCodeMotion_)
96 .EnableOptConstantFolding(jitOptions_.isEnableOptConstantFolding_)
97 .EnableLexenvSpecialization(jitOptions_.isEnableLexenvSpecialization_)
98 .EnableInlineNative(jitOptions_.isEnableNativeInline_)
99 .EnableLoweringBuiltin(jitOptions_.isEnableLoweringBuiltin_)
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 baselineCompiler_->CollectBLInfo(jitTask->GetRelocInfo());
160 return baselineCompiler_->CollectMemoryCodeInfos(jitTask->GetMachineCodeDesc());
161 }
162 jitCodeGenerator_->JitCreateLitecgModule();
163 bool result = true;
164 result &= passManager_->RunCg();
165 result &= jitCodeGenerator_->GetMemoryCodeInfos(jitTask->GetMachineCodeDesc());
166 ReleaseJitPassManager();
167 return result;
168 }
169
170
CopyCodeToFort(MachineCodeDesc & desc)171 static ARK_INLINE bool CopyCodeToFort(MachineCodeDesc &desc)
172 {
173 uint8_t *pText = reinterpret_cast<uint8_t*>(desc.instructionsAddr);
174 if (desc.rodataSizeBeforeTextAlign != 0) {
175 pText += desc.rodataSizeBeforeTextAlign;
176 }
177 #ifdef JIT_ENABLE_CODE_SIGN
178 if ((uintptr_t)desc.codeSigner == 0) {
179 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
180 LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
181 return false;
182 }
183 } else {
184 LOG_JIT(DEBUG) << "Copy: "
185 << std::hex << (uintptr_t)pText << " <- "
186 << std::hex << (uintptr_t)desc.codeAddr << " size: " << desc.codeSize;
187 LOG_JIT(DEBUG) << " codeSigner = " << std::hex << (uintptr_t)desc.codeSigner;
188 OHOS::Security::CodeSign::JitCodeSigner *signer =
189 reinterpret_cast<OHOS::Security::CodeSign::JitCodeSigner*>(desc.codeSigner);
190 int err = OHOS::Security::CodeSign::CopyToJitCode(
191 signer, pText, reinterpret_cast<void *>(desc.codeAddr), desc.codeSize);
192 if (err != EOK) {
193 LOG_JIT(ERROR) << " CopyToJitCode failed, err: " << err;
194 return false;
195 } else {
196 LOG_JIT(DEBUG) << " CopyToJitCode success!!";
197 }
198 delete reinterpret_cast<OHOS::Security::CodeSign::JitCodeSigner*>(desc.codeSigner);
199 }
200 #else
201 if (memcpy_s(pText, desc.codeSizeAlign, reinterpret_cast<uint8_t*>(desc.codeAddr), desc.codeSize) != EOK) {
202 LOG_JIT(ERROR) << "memcpy failed in CopyToCache";
203 return false;
204 }
205 #endif
206 return true;
207 }
208
AllocFromFortAndCopy(CompilationEnv & compilationEnv,MachineCodeDesc & desc,RelocMap & relocInfo)209 ARK_INLINE bool JitCompiler::AllocFromFortAndCopy(CompilationEnv &compilationEnv,
210 MachineCodeDesc &desc, RelocMap &relocInfo)
211 {
212 ASSERT(compilationEnv.IsJitCompiler());
213 JSThread *hostThread = static_cast<JitCompilationEnv&>(compilationEnv).GetHostThread();
214 Jit::JitGCLockHolder lock(hostThread);
215
216 size_t size = JitTask::ComputePayLoadSize(desc);
217 const Heap *heap = hostThread->GetEcmaVM()->GetHeap();
218
219 if (desc.isHugeObj) {
220 Region *region = heap->GetHugeMachineCodeSpace()->AllocateFort(
221 size + MachineCode::SIZE, hostThread, &desc);
222 if (!region || !desc.instructionsAddr) {
223 return false;
224 }
225 desc.hugeObjRegion = ToUintPtr(region);
226 } else {
227 uintptr_t mem = heap->GetMachineCodeSpace()->JitFortAllocate(&desc);
228 if (mem == ToUintPtr(nullptr)) {
229 return false;
230 }
231 desc.instructionsAddr = mem;
232 }
233
234 if (desc.archType == MachineCodeArchType::AArch64) {
235 kungfu::RelocWriterAArch64 reWriter;
236 reWriter.RewriteRelocInfo((uint8_t*)desc.codeAddr, (uint8_t*)desc.instructionsAddr, relocInfo);
237 }
238
239 if (!CopyCodeToFort(desc)) {
240 return false;
241 }
242 return true;
243 }
244
InitJitCompiler(JSRuntimeOptions options)245 void InitJitCompiler(JSRuntimeOptions options)
246 {
247 JitCompiler *jitCompiler = JitCompiler::GetInstance(&options);
248 jitCompiler->Init(options);
249 }
250
CreateJitCompilerTask(JitTask * jitTask)251 void *CreateJitCompilerTask(JitTask *jitTask)
252 {
253 if (jitTask == nullptr) {
254 return nullptr;
255 }
256 return JitCompilerTask::CreateJitCompilerTask(jitTask);
257 }
258
JitCompile(void * compilerTask,JitTask * jitTask)259 bool JitCompile(void *compilerTask, JitTask *jitTask)
260 {
261 if (jitTask == nullptr || compilerTask == nullptr) {
262 return false;
263 }
264 auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask);
265 return jitCompilerTask->Compile();
266 }
267
JitFinalize(void * compilerTask,JitTask * jitTask)268 bool JitFinalize(void *compilerTask, JitTask *jitTask)
269 {
270 if (jitTask == nullptr || compilerTask == nullptr) {
271 return false;
272 }
273 auto jitCompilerTask = reinterpret_cast<JitCompilerTask*>(compilerTask);
274 return jitCompilerTask->Finalize(jitTask);
275 }
276
DeleteJitCompilerTask(void * compilerTask)277 void DeleteJitCompilerTask(void *compilerTask)
278 {
279 if (compilerTask == nullptr) {
280 return;
281 }
282 delete reinterpret_cast<JitCompilerTask*>(compilerTask);
283 }
284 } // namespace panda::ecmascript::kungfu
285