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 #include "ecmascript/compiler/jit_compilation_env.h"
16 #include "ecmascript/jspandafile/program_object.h"
17 #include "ecmascript/ic/ic_handler.h"
18
19 namespace panda::ecmascript {
20 // jit
JitCompilationEnv(EcmaVM * jitVm,EcmaVM * jsVm,JSHandle<JSFunction> & jsFunction)21 JitCompilationEnv::JitCompilationEnv(EcmaVM *jitVm, EcmaVM *jsVm, JSHandle<JSFunction> &jsFunction)
22 : CompilationEnv(jitVm), hostThread_(jsVm->GetJSThreadNoCheck()), jsFunction_(jsFunction)
23 {
24 if (hostThread_ != nullptr && hostThread_->GetCurrentEcmaContext() != nullptr &&
25 hostThread_->GetCurrentEcmaContext()->GetPTManager() != nullptr) {
26 ptManager_ = hostThread_->GetCurrentEcmaContext()->GetPTManager();
27 }
28 Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
29 jsPandaFile_ = const_cast<JSPandaFile*>(method->GetJSPandaFile());
30 methodLiteral_ = method->GetMethodLiteral();
31 pcStart_ = method->GetBytecodeArray();
32 abcId_ = PGOProfiler::GetMethodAbcId(*jsFunction);
33 if (method->GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR) {
34 methodLiteral_->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR);
35 }
36 }
37
GetJSOptions()38 JSRuntimeOptions &JitCompilationEnv::GetJSOptions()
39 {
40 return hostThread_->GetEcmaVM()->GetJSOptions();
41 }
42
GetArrayHClassIndex(ElementsKind kind,bool isProtoType) const43 ConstantIndex JitCompilationEnv::GetArrayHClassIndex(ElementsKind kind, bool isProtoType) const
44 {
45 return hostThread_->GetArrayInstanceHClassIndex(kind, isProtoType);
46 }
47
GetBuiltinHClassEntries() const48 const BuiltinHClassEntries &JitCompilationEnv::GetBuiltinHClassEntries() const
49 {
50 return hostThread_->GetBuiltinHClassEntries();
51 }
52
GetBuiltinPrototypeHClass(BuiltinTypeId type) const53 JSHClass *JitCompilationEnv::GetBuiltinPrototypeHClass(BuiltinTypeId type) const
54 {
55 return hostThread_->GetBuiltinPrototypeHClass(type);
56 }
57
SetTsManagerCompilationEnv()58 void JitCompilationEnv::SetTsManagerCompilationEnv()
59 {
60 auto pt = hostThread_->GetCurrentEcmaContext()->GetPTManager();
61 ptManager_ = pt;
62 }
63
GetPGOProfiler() const64 std::shared_ptr<pgo::PGOProfiler> JitCompilationEnv::GetPGOProfiler() const
65 {
66 return hostThread_->GetEcmaVM()->GetPGOProfiler();
67 }
68
FindConstpool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id) const69 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
70 [[maybe_unused]] panda_file::File::EntityId id) const
71 {
72 ASSERT(thread_->IsInRunningState());
73 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
74 JSTaggedValue constpool = method->GetConstantPool();
75 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
76 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
77 ASSERT(method->GetMethodId() == id);
78 return constpool;
79 }
80
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index) const81 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
82 [[maybe_unused]] int32_t index) const
83 {
84 ASSERT(thread_->IsInRunningState());
85 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
86 JSTaggedValue constpool = method->GetConstantPool();
87 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
88 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
89 ASSERT(taggedPool->GetSharedConstpoolId().GetInt() == index);
90 return constpool;
91 }
92
FindOrCreateUnsharedConstpool(const uint32_t methodOffset) const93 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] const uint32_t methodOffset) const
94 {
95 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
96 if (constpool.IsUndefined()) {
97 return JSTaggedValue::Undefined();
98 }
99 ASSERT(!ConstantPool::CheckUnsharedConstpool(constpool));
100 JSTaggedValue unSharedConstpool = hostThread_->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool);
101 return unSharedConstpool;
102 }
103
FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool) const104 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] JSTaggedValue sharedConstpool) const
105 {
106 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
107 [[maybe_unused]] JSTaggedValue constpool = method->GetConstantPool();
108 ASSERT(constpool == sharedConstpool);
109 uint32_t methodOffset = method->GetMethodId().GetOffset();
110 return FindOrCreateUnsharedConstpool(methodOffset);
111 }
112
FindOrCreateConstPool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)113 JSHandle<ConstantPool> JitCompilationEnv::FindOrCreateConstPool([[maybe_unused]] const JSPandaFile *jsPandaFile,
114 [[maybe_unused]] panda_file::File::EntityId id)
115 {
116 ASSERT_PRINT(0, "jit should unreachable");
117 return JSHandle<ConstantPool>();
118 }
119
GetConstantPoolByMethodOffset(const uint32_t methodOffset) const120 JSTaggedValue JitCompilationEnv::GetConstantPoolByMethodOffset([[maybe_unused]] const uint32_t methodOffset) const
121 {
122 ASSERT(thread_->IsInRunningState());
123 JSTaggedValue constpool;
124 Method *currMethod = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
125 if (methodOffset != currMethod->GetMethodId().GetOffset()) {
126 auto calleeFunc = GetJsFunctionByMethodOffset(methodOffset);
127 if (!calleeFunc) {
128 return JSTaggedValue::Undefined();
129 }
130 constpool = Method::Cast(calleeFunc->GetMethod())->GetConstantPool();
131 } else {
132 constpool = currMethod->GetConstantPool();
133 }
134 return constpool;
135 }
136
GetArrayLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const137 JSTaggedValue JitCompilationEnv::GetArrayLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
138 {
139 ASSERT(thread_->IsInRunningState());
140 return ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(constpool, index, entry);
141 }
142
GetObjectLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const143 JSTaggedValue JitCompilationEnv::GetObjectLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
144 {
145 ASSERT(thread_->IsInRunningState());
146 return ConstantPool::GetLiteralFromCache<ConstPoolType::OBJECT_LITERAL>(constpool, index, entry);
147 }
148
GetMethodFromCache(JSTaggedValue constpool,uint32_t index) const149 JSTaggedValue JitCompilationEnv::GetMethodFromCache(JSTaggedValue constpool, uint32_t index) const
150 {
151 return ConstantPool::GetMethodFromCache(constpool, index);
152 }
153
GetIdFromCache(JSTaggedValue constpool,uint32_t index) const154 panda_file::File::EntityId JitCompilationEnv::GetIdFromCache(JSTaggedValue constpool, uint32_t index) const
155 {
156 ASSERT(thread_->IsInRunningState());
157 return ConstantPool::GetIdFromCache(constpool, index);
158 }
159
GetGlobalEnv() const160 JSHandle<GlobalEnv> JitCompilationEnv::GetGlobalEnv() const
161 {
162 ASSERT(thread_->IsInRunningState());
163 return hostThread_->GetEcmaVM()->GetGlobalEnv();
164 }
165
GlobalConstants() const166 const GlobalEnvConstants *JitCompilationEnv::GlobalConstants() const
167 {
168 ASSERT(thread_->IsInRunningState());
169 return hostThread_->GlobalConstants();
170 }
171
172 // The caller should add assessment for undefined constpool.
173 // When slotValue in profileTypeInfo is changed in main thread, constpool may be undefined.
GetStringFromConstantPool(const uint32_t methodOffset,const uint16_t cpIdx,bool allowAlloc) const174 JSTaggedValue JitCompilationEnv::GetStringFromConstantPool([[maybe_unused]] const uint32_t methodOffset,
175 const uint16_t cpIdx, bool allowAlloc) const
176 {
177 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
178 if (constpool.IsUndefined()) {
179 return JSTaggedValue::Undefined();
180 }
181 return ConstantPool::GetStringFromCacheForJit(GetJSThread(), constpool, cpIdx, allowAlloc);
182 }
183
GetJsFunctionByMethodOffset(uint32_t methodOffset) const184 JSFunction *JitCompilationEnv::GetJsFunctionByMethodOffset(uint32_t methodOffset) const
185 {
186 ASSERT(thread_->IsInRunningState());
187 Method *currMethod = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
188 auto currMethodOffset = currMethod->GetMethodId().GetOffset();
189 if (methodOffset == currMethodOffset) {
190 return *jsFunction_;
191 }
192 std::vector<std::pair<uint32_t, uint32_t>> funcSlotChain;
193 uint32_t calleeOffset = methodOffset;
194 do {
195 if (functionSlotIdMap_.find(calleeOffset) == functionSlotIdMap_.end()) {
196 return nullptr;
197 }
198 funcSlotChain.push_back({functionSlotIdMap_.at(calleeOffset), callee2CallerMap_.at(calleeOffset)});
199 calleeOffset = callee2CallerMap_.at(calleeOffset);
200 } while (calleeOffset != currMethodOffset);
201 JSFunction *currFunc = *jsFunction_;
202 ProfileTypeInfo *currFuncPTI = *profileTypeInfo_;
203 for (int i = static_cast<int>(funcSlotChain.size()) - 1; i >= 0; --i) {
204 uint32_t slotId = funcSlotChain[i].first;
205 uint32_t callerOffset = funcSlotChain[i].second;
206 if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != callerOffset) {
207 return nullptr;
208 }
209 auto slotValue = currFuncPTI->Get(slotId);
210 if (slotValue.IsJSFunction()) {
211 currFunc = JSFunction::Cast(currFuncPTI->Get(slotId).GetTaggedObject());
212 } else if (slotValue.IsPrototypeHandler()) {
213 auto prototypeHandler = PrototypeHandler::Cast(slotValue.GetTaggedObject());
214 auto accessorFunction = prototypeHandler->GetAccessorJSFunction();
215 if (!accessorFunction.IsJSFunction()) {
216 return nullptr;
217 }
218 currFunc = JSFunction::Cast(accessorFunction.GetTaggedObject());
219 } else {
220 return nullptr;
221 }
222 auto profileTypeInfoVal = currFunc->GetProfileTypeInfo();
223 if (profileTypeInfoVal.IsUndefined()) {
224 return nullptr;
225 }
226 currFuncPTI = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
227 }
228 if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != methodOffset) {
229 return nullptr;
230 }
231 return currFunc;
232 }
233 } // namespace panda::ecmascript
234