• 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 
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