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/ecma_context.h"
17 #include "ecmascript/jspandafile/program_object.h"
18 #include "ecmascript/pgo_profiler/pgo_profiler.h"
19 #include "ecmascript/ic/profile_type_info.h"
20 #include "ecmascript/ic/ic_handler.h"
21
22 namespace panda::ecmascript {
23 // jit
JitCompilationEnv(EcmaVM * jitVm,EcmaVM * jsVm,JSHandle<JSFunction> & jsFunction)24 JitCompilationEnv::JitCompilationEnv(EcmaVM *jitVm, EcmaVM *jsVm, JSHandle<JSFunction> &jsFunction)
25 : CompilationEnv(jitVm), hostThread_(jsVm->GetJSThreadNoCheck()), jsFunction_(jsFunction)
26 {
27 ptManager_ = hostThread_->GetCurrentEcmaContext()->GetPTManager();
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 ASSERT(methodLiteral_ != nullptr);
35 methodLiteral_->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR);
36 }
37 }
38
GetJSOptions()39 JSRuntimeOptions &JitCompilationEnv::GetJSOptions()
40 {
41 return hostThread_->GetEcmaVM()->GetJSOptions();
42 }
43
GetArrayHClassIndexMap() const44 const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &JitCompilationEnv::GetArrayHClassIndexMap() const
45 {
46 return hostThread_->GetArrayHClassIndexMap();
47 }
48
GetBuiltinHClassEntries() const49 const BuiltinHClassEntries &JitCompilationEnv::GetBuiltinHClassEntries() const
50 {
51 return hostThread_->GetBuiltinHClassEntries();
52 }
53
GetBuiltinPrototypeHClass(BuiltinTypeId type) const54 JSHClass *JitCompilationEnv::GetBuiltinPrototypeHClass(BuiltinTypeId type) const
55 {
56 return hostThread_->GetBuiltinPrototypeHClass(type);
57 }
58
SetTsManagerCompilationEnv()59 void JitCompilationEnv::SetTsManagerCompilationEnv()
60 {
61 auto pt = hostThread_->GetCurrentEcmaContext()->GetPTManager();
62 ptManager_ = pt;
63 }
64
GetPGOProfiler() const65 std::shared_ptr<pgo::PGOProfiler> JitCompilationEnv::GetPGOProfiler() const
66 {
67 return hostThread_->GetEcmaVM()->GetPGOProfiler();
68 }
69
FindConstpool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id) const70 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
71 [[maybe_unused]] panda_file::File::EntityId id) const
72 {
73 ASSERT(thread_->IsInRunningState());
74 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
75 JSTaggedValue constpool = method->GetConstantPool();
76 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
77 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
78 ASSERT(method->GetMethodId() == id);
79 return constpool;
80 }
81
FindConstpool(const JSPandaFile * jsPandaFile,int32_t index) const82 JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile,
83 [[maybe_unused]] int32_t index) const
84 {
85 ASSERT(thread_->IsInRunningState());
86 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
87 JSTaggedValue constpool = method->GetConstantPool();
88 [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject());
89 ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile);
90 ASSERT(taggedPool->GetSharedConstpoolId().GetInt() == index);
91 return constpool;
92 }
93
FindOrCreateUnsharedConstpool(const uint32_t methodOffset) const94 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] const uint32_t methodOffset) const
95 {
96 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
97 if (constpool.IsUndefined()) {
98 return JSTaggedValue::Undefined();
99 }
100 ASSERT(!ConstantPool::CheckUnsharedConstpool(constpool));
101 JSTaggedValue unSharedConstpool = hostThread_->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool);
102 return unSharedConstpool;
103 }
104
FindOrCreateUnsharedConstpool(JSTaggedValue sharedConstpool) const105 JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] JSTaggedValue sharedConstpool) const
106 {
107 Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
108 [[maybe_unused]] JSTaggedValue constpool = method->GetConstantPool();
109 ASSERT(constpool == sharedConstpool);
110 uint32_t methodOffset = method->GetMethodId().GetOffset();
111 return FindOrCreateUnsharedConstpool(methodOffset);
112 }
113
FindOrCreateConstPool(const JSPandaFile * jsPandaFile,panda_file::File::EntityId id)114 JSHandle<ConstantPool> JitCompilationEnv::FindOrCreateConstPool([[maybe_unused]] const JSPandaFile *jsPandaFile,
115 [[maybe_unused]] panda_file::File::EntityId id)
116 {
117 ASSERT_PRINT(0, "jit should unreachable");
118 return JSHandle<ConstantPool>();
119 }
120
GetConstantPoolByMethodOffset(const uint32_t methodOffset) const121 JSTaggedValue JitCompilationEnv::GetConstantPoolByMethodOffset([[maybe_unused]] const uint32_t methodOffset) const
122 {
123 ASSERT(thread_->IsInRunningState());
124 JSTaggedValue constpool;
125 Method *currMethod = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
126 if (methodOffset != currMethod->GetMethodId().GetOffset()) {
127 auto calleeFunc = GetJsFunctionByMethodOffset(methodOffset);
128 if (!calleeFunc) {
129 return JSTaggedValue::Undefined();
130 }
131 constpool = Method::Cast(calleeFunc->GetMethod())->GetConstantPool();
132 } else {
133 constpool = currMethod->GetConstantPool();
134 }
135 return constpool;
136 }
137
GetArrayLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const138 JSTaggedValue JitCompilationEnv::GetArrayLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
139 {
140 ASSERT(thread_->IsInRunningState());
141 return ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(constpool, index, entry);
142 }
143
GetObjectLiteralFromCache(JSTaggedValue constpool,uint32_t index,CString entry) const144 JSTaggedValue JitCompilationEnv::GetObjectLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
145 {
146 ASSERT(thread_->IsInRunningState());
147 return ConstantPool::GetLiteralFromCache<ConstPoolType::OBJECT_LITERAL>(constpool, index, entry);
148 }
149
GetMethodFromCache(JSTaggedValue constpool,uint32_t index) const150 JSTaggedValue JitCompilationEnv::GetMethodFromCache(JSTaggedValue constpool, uint32_t index) const
151 {
152 return ConstantPool::GetMethodFromCache(constpool, index);
153 }
154
GetIdFromCache(JSTaggedValue constpool,uint32_t index) const155 panda_file::File::EntityId JitCompilationEnv::GetIdFromCache(JSTaggedValue constpool, uint32_t index) const
156 {
157 ASSERT(thread_->IsInRunningState());
158 return ConstantPool::GetIdFromCache(constpool, index);
159 }
160
GetGlobalEnv() const161 JSHandle<GlobalEnv> JitCompilationEnv::GetGlobalEnv() const
162 {
163 ASSERT(thread_->IsInRunningState());
164 return hostThread_->GetEcmaVM()->GetGlobalEnv();
165 }
166
GlobalConstants() const167 const GlobalEnvConstants *JitCompilationEnv::GlobalConstants() const
168 {
169 ASSERT(thread_->IsInRunningState());
170 return hostThread_->GlobalConstants();
171 }
172
173 // The caller should add assessment for undefined constpool.
174 // When slotValue in profileTypeInfo is changed in main thread, constpool may be undefined.
GetStringFromConstantPool(const uint32_t methodOffset,const uint16_t cpIdx,bool allowAlloc) const175 JSTaggedValue JitCompilationEnv::GetStringFromConstantPool([[maybe_unused]] const uint32_t methodOffset,
176 const uint16_t cpIdx, bool allowAlloc) const
177 {
178 JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset);
179 if (constpool.IsUndefined()) {
180 return JSTaggedValue::Undefined();
181 }
182 return ConstantPool::GetStringFromCacheForJit(GetJSThread(), constpool, cpIdx, allowAlloc);
183 }
184
GetJsFunctionByMethodOffset(uint32_t methodOffset) const185 JSFunction *JitCompilationEnv::GetJsFunctionByMethodOffset(uint32_t methodOffset) const
186 {
187 ASSERT(thread_->IsInRunningState());
188 Method *currMethod = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
189 auto currMethodOffset = currMethod->GetMethodId().GetOffset();
190 if (methodOffset == currMethodOffset) {
191 return *jsFunction_;
192 }
193 std::vector<std::pair<uint32_t, uint32_t>> funcSlotChain;
194 uint32_t calleeOffset = methodOffset;
195 do {
196 if (functionSlotIdMap_.find(calleeOffset) == functionSlotIdMap_.end()) {
197 return nullptr;
198 }
199 funcSlotChain.push_back({functionSlotIdMap_.at(calleeOffset), callee2CallerMap_.at(calleeOffset)});
200 calleeOffset = callee2CallerMap_.at(calleeOffset);
201 } while (calleeOffset != currMethodOffset);
202 JSFunction *currFunc = *jsFunction_;
203 ProfileTypeInfo *currFuncPTI = *profileTypeInfo_;
204 for (int i = static_cast<int>(funcSlotChain.size()) - 1; i >= 0; --i) {
205 uint32_t slotId = funcSlotChain[i].first;
206 uint32_t callerOffset = funcSlotChain[i].second;
207 if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != callerOffset) {
208 return nullptr;
209 }
210 auto slotValue = currFuncPTI->Get(slotId);
211 if (slotValue.IsJSFunction()) {
212 currFunc = JSFunction::Cast(currFuncPTI->Get(slotId).GetTaggedObject());
213 } else if (slotValue.IsPrototypeHandler()) {
214 auto prototypeHandler = PrototypeHandler::Cast(slotValue.GetTaggedObject());
215 auto accessorFunction = prototypeHandler->GetAccessorJSFunction();
216 if (!accessorFunction.IsJSFunction()) {
217 return nullptr;
218 }
219 currFunc = JSFunction::Cast(accessorFunction.GetTaggedObject());
220 } else {
221 return nullptr;
222 }
223 auto profileTypeInfoVal = currFunc->GetProfileTypeInfo();
224 if (profileTypeInfoVal.IsUndefined()) {
225 return nullptr;
226 }
227 currFuncPTI = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
228 }
229 if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != methodOffset) {
230 return nullptr;
231 }
232 return currFunc;
233 }
234 } // namespace panda::ecmascript
235