• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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