• 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 #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