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