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 #include "ecmascript/jit/jit_thread.h"
19
20 namespace panda::ecmascript {
21 // jit
JitCompilationEnv(EcmaVM * jitVm,EcmaVM * jsVm,JSHandle<JSFunction> & jsFunction,kungfu::LazyDeoptAllDependencies * dependencies)22 JitCompilationEnv::JitCompilationEnv(EcmaVM *jitVm, EcmaVM *jsVm,
23 JSHandle<JSFunction> &jsFunction,
24 kungfu::LazyDeoptAllDependencies *dependencies)
25 : CompilationEnv(jitVm), hostThread_(jsVm->GetJSThreadNoCheck()),
26 jsFunction_(jsFunction), dependencies_(dependencies)
27 {
28 if (hostThread_ != nullptr && jsVm->GetPTManager() != nullptr) {
29 ptManager_ = jsVm->GetPTManager();
30 }
31 JSTaggedValue funcEnv = jsFunction_->GetLexicalEnv(thread_);
32 globalEnv_ = BaseEnv::Cast(funcEnv.GetTaggedObject())->GetGlobalEnv(thread_);
33 ASSERT(globalEnv_.IsJSGlobalEnv());
34 Method *method = Method::Cast(jsFunction->GetMethod(thread_).GetTaggedObject());
35 jsPandaFile_ = const_cast<JSPandaFile*>(method->GetJSPandaFile(thread_));
36 methodLiteral_ = method->GetMethodLiteral(thread_);
37 pcStart_ = method->GetBytecodeArray();
38 abcId_ = PGOProfiler::GetMethodAbcId(thread_, *jsFunction);
39 if (method->GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR) {
40 methodLiteral_->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR);
41 }
42 }
43
GetJSOptions() const44 JSRuntimeOptions &JitCompilationEnv::GetJSOptions() const
45 {
46 return hostThread_->GetEcmaVM()->GetJSOptions();
47 }
48
GetArrayHClassIndex(ElementsKind kind,bool isProtoType) const49 GlobalEnvField JitCompilationEnv::GetArrayHClassIndex(ElementsKind kind, bool isProtoType) const
50 {
51 return hostThread_->GetArrayInstanceHClassIndex(kind, isProtoType);
52 }
53
GetBuiltinHClassEntries() const54 const BuiltinHClassEntries &JitCompilationEnv::GetBuiltinHClassEntries() const
55 {
56 return hostThread_->GetBuiltinHClassEntries();
57 }
58
GetBuiltinPrototypeHClass(BuiltinTypeId type) const59 JSHClass *JitCompilationEnv::GetBuiltinPrototypeHClass(BuiltinTypeId type) const
60 {
61 return hostThread_->GetBuiltinPrototypeHClass(type);
62 }
63
SetTsManagerCompilationEnv()64 void JitCompilationEnv::SetTsManagerCompilationEnv()
65 {
66 auto pt = hostThread_->GetEcmaVM()->GetPTManager();
67 ptManager_ = pt;
68 }
69
GetPGOProfiler() const70 std::shared_ptr<pgo::PGOProfiler> JitCompilationEnv::GetPGOProfiler() const
71 {
72 return hostThread_->GetEcmaVM()->GetPGOProfiler();
73 }
74
FindConstpool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id) const75 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
76 [[maybe_unused]] panda_file::File::EntityId id) const
77 {
78 ASSERT(thread_->IsInRunningState());
79 Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject());
80 JSTaggedValue constpool = method->GetConstantPool(thread_);
81 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
82 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
83 ASSERT(method->GetMethodId() == id);
84 return constpool;
85 }
86
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index) const87 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
88 [[maybe_unused]] int32_t index) const
89 {
90 ASSERT(thread_->IsInRunningState());
91 Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject());
92 JSTaggedValue constpool = method->GetConstantPool(thread_);
93 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
94 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
95 ASSERT(taggedPool->GetSharedConstpoolId().GetInt() == index);
96 return constpool;
97 }
98
FindOrCreateUnsharedConstpool(const uint32_t methodOffset) const99 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] const uint32_t methodOffset) const
100 {
101 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
102 if (constpool.IsUndefined()) {
103 return JSTaggedValue::Undefined();
104 }
105 ASSERT(!ConstantPool::CheckUnsharedConstpool(constpool));
106 JSTaggedValue unSharedConstpool = hostThread_->GetEcmaVM()->FindUnsharedConstpool(constpool);
107 return unSharedConstpool;
108 }
109
FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool) const110 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] JSTaggedValue sharedConstpool) const
111 {
112 Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject());
113 [[maybe_unused]] JSTaggedValue constpool = method->GetConstantPool(thread_);
114 ASSERT(constpool == sharedConstpool);
115 uint32_t methodOffset = method->GetMethodId().GetOffset();
116 return FindOrCreateUnsharedConstpool(methodOffset);
117 }
118
FindOrCreateConstPool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)119 JSHandle<ConstantPool> JitCompilationEnv::FindOrCreateConstPool([[maybe_unused]] const JSPandaFile *jsPandaFile,
120 [[maybe_unused]] panda_file::File::EntityId id)
121 {
122 ASSERT_PRINT(0, "jit should unreachable");
123 return JSHandle<ConstantPool>();
124 }
125
GetConstantPoolByMethodOffset(const uint32_t methodOffset) const126 JSTaggedValue JitCompilationEnv::GetConstantPoolByMethodOffset([[maybe_unused]] const uint32_t methodOffset) const
127 {
128 ASSERT(thread_->IsInRunningState());
129 JSTaggedValue constpool;
130 Method *currMethod = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject());
131 if (methodOffset != currMethod->GetMethodId().GetOffset()) {
132 auto calleeFunc = GetJsFunctionByMethodOffset(methodOffset);
133 if (!calleeFunc) {
134 return JSTaggedValue::Undefined();
135 }
136 constpool = Method::Cast(calleeFunc->GetMethod(thread_))->GetConstantPool(thread_);
137 } else {
138 constpool = currMethod->GetConstantPool(thread_);
139 }
140 return constpool;
141 }
142
GetArrayLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const143 JSTaggedValue JitCompilationEnv::GetArrayLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
144 {
145 ASSERT(thread_->IsInRunningState());
146 return ConstantPool::GetLiteralFromCacheNoScope<ConstPoolType::ARRAY_LITERAL>(thread_, constpool, index, entry);
147 }
148
GetObjectLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const149 JSTaggedValue JitCompilationEnv::GetObjectLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
150 {
151 ASSERT(thread_->IsInRunningState());
152 return ConstantPool::GetLiteralFromCacheNoScope<ConstPoolType::OBJECT_LITERAL>(thread_, constpool, index, entry);
153 }
154
GetMethodFromCache(JSTaggedValue constpool,uint32_t index) const155 JSTaggedValue JitCompilationEnv::GetMethodFromCache(JSTaggedValue constpool, uint32_t index) const
156 {
157 return ConstantPool::GetMethodFromCache(constpool, index, thread_);
158 }
159
GetIdFromCache(JSTaggedValue constpool,uint32_t index) const160 panda_file::File::EntityId JitCompilationEnv::GetIdFromCache(JSTaggedValue constpool, uint32_t index) const
161 {
162 ASSERT(thread_->IsInRunningState());
163 return ConstantPool::GetIdFromCache(constpool, index);
164 }
165
GetGlobalEnv() const166 JSHandle<GlobalEnv> JitCompilationEnv::GetGlobalEnv() const
167 {
168 ASSERT(globalEnv_.IsJSGlobalEnv());
169 return JSHandle<GlobalEnv>(ToUintPtr(&globalEnv_));
170 }
171
GlobalConstants() const172 const GlobalEnvConstants *JitCompilationEnv::GlobalConstants() const
173 {
174 ASSERT(thread_->IsInRunningState());
175 return hostThread_->GlobalConstants();
176 }
177
178 // The caller should add assessment for undefined constpool.
179 // When slotValue in profileTypeInfo is changed in main thread, constpool may be undefined.
GetStringFromConstantPool(const uint32_t methodOffset,const uint16_t cpIdx,bool allowAlloc) const180 JSTaggedValue JitCompilationEnv::GetStringFromConstantPool([[maybe_unused]] const uint32_t methodOffset,
181 const uint16_t cpIdx, bool allowAlloc) const
182 {
183 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
184 if (constpool.IsUndefined()) {
185 return JSTaggedValue::Undefined();
186 }
187 return ConstantPool::GetStringFromCacheForJit(GetJSThread(), constpool, cpIdx, allowAlloc);
188 }
189
GetJsFunctionByMethodOffset(uint32_t methodOffset) const190 JSFunction *JitCompilationEnv::GetJsFunctionByMethodOffset(uint32_t methodOffset) const
191 {
192 ASSERT(thread_->IsInRunningState());
193 Method *currMethod = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject());
194 auto currMethodOffset = currMethod->GetMethodId().GetOffset();
195 if (methodOffset == currMethodOffset) {
196 return *jsFunction_;
197 }
198 std::vector<std::pair<uint32_t, uint32_t>> funcSlotChain;
199 uint32_t calleeOffset = methodOffset;
200 do {
201 if (functionSlotIdMap_.find(calleeOffset) == functionSlotIdMap_.end()) {
202 return nullptr;
203 }
204 funcSlotChain.push_back({functionSlotIdMap_.at(calleeOffset), callee2CallerMap_.at(calleeOffset)});
205 calleeOffset = callee2CallerMap_.at(calleeOffset);
206 } while (calleeOffset != currMethodOffset);
207 JSFunction *currFunc = *jsFunction_;
208 ProfileTypeInfo *currFuncPTI = *profileTypeInfo_;
209 for (int i = static_cast<int>(funcSlotChain.size()) - 1; i >= 0; --i) {
210 uint32_t slotId = funcSlotChain[i].first;
211 uint32_t callerOffset = funcSlotChain[i].second;
212 if (Method::Cast(currFunc->GetMethod(thread_))->GetMethodId().GetOffset() != callerOffset) {
213 return nullptr;
214 }
215 auto slotValue = currFuncPTI->Get(thread_, slotId);
216 if (slotValue.IsJSFunction()) {
217 currFunc = JSFunction::Cast(currFuncPTI->Get(thread_, slotId).GetTaggedObject());
218 } else if (slotValue.IsPrototypeHandler()) {
219 auto prototypeHandler = PrototypeHandler::Cast(slotValue.GetTaggedObject());
220 auto accessorFunction = prototypeHandler->GetAccessorJSFunction(thread_);
221 if (!accessorFunction.IsJSFunction()) {
222 return nullptr;
223 }
224 currFunc = JSFunction::Cast(accessorFunction.GetTaggedObject());
225 } else {
226 return nullptr;
227 }
228 auto profileTypeInfoVal = currFunc->GetProfileTypeInfo(thread_);
229 if (profileTypeInfoVal.IsUndefined()) {
230 return nullptr;
231 }
232 currFuncPTI = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
233 }
234 if (Method::Cast(currFunc->GetMethod(thread_))->GetMethodId().GetOffset() != methodOffset) {
235 return nullptr;
236 }
237 return currFunc;
238 }
239
RecordHeapConstant(ConstantPoolHeapConstant heapConstant,const JSHandle<JSTaggedValue> & heapObj)240 uint32_t JitCompilationEnv::RecordHeapConstant(
241 ConstantPoolHeapConstant heapConstant, const JSHandle<JSTaggedValue> &heapObj)
242 {
243 ASSERT(SupportHeapConstant());
244 auto itr = heapConstantInfo_.constPoolHeapConstant2Index.find(heapConstant);
245 if (itr != heapConstantInfo_.constPoolHeapConstant2Index.end()) {
246 return itr->second;
247 }
248 heapConstantInfo_.heapConstantTable.push_back(heapObj);
249 ASSERT(heapConstantInfo_.heapConstantTable.size() < INVALID_HEAP_CONSTANT_INDEX);
250 uint32_t index = static_cast<uint32_t>(heapConstantInfo_.heapConstantTable.size() - 1);
251 heapConstantInfo_.constPoolHeapConstant2Index.insert(
252 std::pair<ConstantPoolHeapConstant, uint32_t>(heapConstant, index));
253 return index;
254 }
255
GetHeapConstantHandle(uint32_t heapConstantIndex) const256 JSHandle<JSTaggedValue> JitCompilationEnv::GetHeapConstantHandle(uint32_t heapConstantIndex) const
257 {
258 ASSERT(heapConstantIndex < heapConstantInfo_.heapConstantTable.size());
259 return heapConstantInfo_.heapConstantTable[heapConstantIndex];
260 }
261 } // namespace panda::ecmascript
262