1 /*
2 * Copyright (c) 2024 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 "ecmascript/jit/compile_decision.h"
17 #include "ecmascript/jspandafile/js_pandafile.h"
18 #include "ecmascript/ic/profile_type_info.h"
19
20 namespace panda::ecmascript {
CompileDecision(EcmaVM * vm,JSHandle<JSFunction> & jsFunction,CompilerTier tier,int32_t osrOffset,JitCompileMode mode)21 CompileDecision::CompileDecision(EcmaVM *vm, JSHandle<JSFunction> &jsFunction, CompilerTier tier,
22 int32_t osrOffset, JitCompileMode mode) : vm_(vm), jsFunction_(jsFunction),
23 tier_(tier), osrOffset_(osrOffset), compileMode_(mode) { }
24
GetMethodInfo() const25 CString CompileDecision::GetMethodInfo() const
26 {
27 uint32_t codeSize = GetCodeSize();
28 return GetMethodName() + ", bytecode size:" + ToCString(codeSize);
29 }
30
GetMethodName() const31 CString CompileDecision::GetMethodName() const
32 {
33 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
34 ASSERT(method != nullptr);
35 auto jSPandaFile = method->GetJSPandaFile();
36 CString fileDesc;
37 if (jSPandaFile != nullptr) {
38 fileDesc = jSPandaFile->GetJSPandaFileDesc();
39 }
40 return fileDesc + ":" + method->GetRecordNameStr() + "." + CString(method->GetMethodName());
41 }
42
GetCodeSize() const43 uint32_t CompileDecision::GetCodeSize() const
44 {
45 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
46 return method->GetCodeSize();
47 }
48
Decision()49 bool CompileDecision::Decision()
50 {
51 return IsGoodCompilationRequest();
52 }
53
IsGoodCompilationRequest() const54 bool CompileDecision::IsGoodCompilationRequest() const
55 {
56 if (!CheckJsFunctionStatus()) {
57 return false;
58 }
59
60 if (!IsJsFunctionSupportCompile()) {
61 DisableJitCompile();
62 return false;
63 }
64
65 if (!CheckVmState()) {
66 return false;
67 }
68 return true;
69 }
70
IsJsFunctionSupportCompile() const71 bool CompileDecision::IsJsFunctionSupportCompile() const
72 {
73 if (!IsSupportFunctionKind()) {
74 return false;
75 }
76
77 uint32_t maxSize = 9000;
78 if (vm_->GetJSOptions().IsEnableJitFastCompile()) {
79 maxSize = 15; // 15 is method codesize threshold during fast compiling
80 }
81 if (GetCodeSize() > maxSize && !(vm_->GetJSOptions().IsEnableForceJitCompileMain() && compileMode_.IsSync())) {
82 LOG_JIT(DEBUG) << tier_ << "skip jit task, as too large:" << GetMethodInfo();
83 return false;
84 }
85 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
86 if (vm_->IsEnableOsr() && osrOffset_ != MachineCode::INVALID_OSR_OFFSET && method->HasCatchBlock()) {
87 LOG_JIT(DEBUG) << "skip jit task, as osr does not support catch blocks: " << GetMethodInfo();
88 return false;
89 }
90 return true;
91 }
92
IsSupportFunctionKind() const93 bool CompileDecision::IsSupportFunctionKind() const
94 {
95 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
96 if (jsFunction_.GetTaggedValue().IsJSSharedFunction()) {
97 LOG_JIT(DEBUG) << tier_ << "method does not support compile shared function:" << GetMethodInfo();
98 return false;
99 }
100
101 FunctionKind kind = method->GetFunctionKind();
102 switch (kind) {
103 case FunctionKind::NORMAL_FUNCTION:
104 case FunctionKind::GETTER_FUNCTION:
105 case FunctionKind::SETTER_FUNCTION:
106 case FunctionKind::ARROW_FUNCTION:
107 case FunctionKind::BASE_CONSTRUCTOR:
108 case FunctionKind::CLASS_CONSTRUCTOR:
109 case FunctionKind::DERIVED_CONSTRUCTOR:
110 case FunctionKind::NONE_FUNCTION:
111 return true;
112 default:
113 break;
114 }
115 LOG_JIT(DEBUG) << tier_ << "method does not support jit:" << GetMethodInfo() << ", kind:" << static_cast<int>(kind);
116 return false;
117 }
118
CheckJsFunctionStatus() const119 bool CompileDecision::CheckJsFunctionStatus() const
120 {
121 if (tier_.IsFast() && jsFunction_->IsJitCompiling()) {
122 return false;
123 }
124
125 if (tier_.IsBaseLine() && jsFunction_->IsBaselinejitCompiling()) {
126 return false;
127 }
128
129 if (tier_.IsFast() && jsFunction_->IsCompiledCode()) {
130 JSTaggedValue machineCode = jsFunction_->GetMachineCode();
131 if (machineCode.IsMachineCodeObject() &&
132 MachineCode::Cast(machineCode.GetTaggedObject())->GetOSROffset() == MachineCode::INVALID_OSR_OFFSET) {
133 return false;
134 }
135 return true;
136 }
137
138 if (tier_.IsBaseLine() && !jsFunction_->GetBaselineCode().IsUndefined()) {
139 return false;
140 }
141 return true;
142 }
143
DisableJitCompile() const144 void CompileDecision::DisableJitCompile() const
145 {
146 jsFunction_->SetJitHotnessCnt(ProfileTypeInfo::JIT_DISABLE_FLAG);
147 }
148
CheckVmState() const149 bool CompileDecision::CheckVmState() const
150 {
151 if (vm_->GetJSThread()->IsMachineCodeLowMemory()) {
152 LOG_JIT(DEBUG) << tier_ << "skip jit task, as low code memory:" << GetMethodInfo();
153 return false;
154 }
155 return true;
156 }
157 } // namespace panda::ecmascript
158