/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/compiler/jit_compilation_env.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ic/ic_handler.h" #include "ecmascript/jit/jit_thread.h" namespace panda::ecmascript { // jit JitCompilationEnv::JitCompilationEnv(EcmaVM *jitVm, EcmaVM *jsVm, JSHandle &jsFunction, kungfu::LazyDeoptAllDependencies *dependencies) : CompilationEnv(jitVm), hostThread_(jsVm->GetJSThreadNoCheck()), jsFunction_(jsFunction), dependencies_(dependencies) { if (hostThread_ != nullptr && jsVm->GetPTManager() != nullptr) { ptManager_ = jsVm->GetPTManager(); } JSTaggedValue funcEnv = jsFunction_->GetLexicalEnv(thread_); globalEnv_ = BaseEnv::Cast(funcEnv.GetTaggedObject())->GetGlobalEnv(thread_); ASSERT(globalEnv_.IsJSGlobalEnv()); Method *method = Method::Cast(jsFunction->GetMethod(thread_).GetTaggedObject()); jsPandaFile_ = const_cast(method->GetJSPandaFile(thread_)); methodLiteral_ = method->GetMethodLiteral(thread_); pcStart_ = method->GetBytecodeArray(); abcId_ = PGOProfiler::GetMethodAbcId(thread_, *jsFunction); if (method->GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR) { methodLiteral_->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR); } } JSRuntimeOptions &JitCompilationEnv::GetJSOptions() const { return hostThread_->GetEcmaVM()->GetJSOptions(); } GlobalEnvField JitCompilationEnv::GetArrayHClassIndex(ElementsKind kind, bool isProtoType) const { return hostThread_->GetArrayInstanceHClassIndex(kind, isProtoType); } const BuiltinHClassEntries &JitCompilationEnv::GetBuiltinHClassEntries() const { return hostThread_->GetBuiltinHClassEntries(); } JSHClass *JitCompilationEnv::GetBuiltinPrototypeHClass(BuiltinTypeId type) const { return hostThread_->GetBuiltinPrototypeHClass(type); } void JitCompilationEnv::SetTsManagerCompilationEnv() { auto pt = hostThread_->GetEcmaVM()->GetPTManager(); ptManager_ = pt; } std::shared_ptr JitCompilationEnv::GetPGOProfiler() const { return hostThread_->GetEcmaVM()->GetPGOProfiler(); } JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile, [[maybe_unused]] panda_file::File::EntityId id) const { ASSERT(thread_->IsInRunningState()); Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject()); JSTaggedValue constpool = method->GetConstantPool(thread_); [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile); ASSERT(method->GetMethodId() == id); return constpool; } JSTaggedValue JitCompilationEnv::FindConstpool([[maybe_unused]] const JSPandaFile *jsPandaFile, [[maybe_unused]] int32_t index) const { ASSERT(thread_->IsInRunningState()); Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject()); JSTaggedValue constpool = method->GetConstantPool(thread_); [[maybe_unused]] const ConstantPool *taggedPool = ConstantPool::Cast(constpool.GetTaggedObject()); ASSERT(taggedPool->GetJSPandaFile() == jsPandaFile); ASSERT(taggedPool->GetSharedConstpoolId().GetInt() == index); return constpool; } JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] const uint32_t methodOffset) const { JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset); if (constpool.IsUndefined()) { return JSTaggedValue::Undefined(); } ASSERT(!ConstantPool::CheckUnsharedConstpool(constpool)); JSTaggedValue unSharedConstpool = hostThread_->GetEcmaVM()->FindUnsharedConstpool(constpool); return unSharedConstpool; } JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] JSTaggedValue sharedConstpool) const { Method *method = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject()); [[maybe_unused]] JSTaggedValue constpool = method->GetConstantPool(thread_); ASSERT(constpool == sharedConstpool); uint32_t methodOffset = method->GetMethodId().GetOffset(); return FindOrCreateUnsharedConstpool(methodOffset); } JSHandle JitCompilationEnv::FindOrCreateConstPool([[maybe_unused]] const JSPandaFile *jsPandaFile, [[maybe_unused]] panda_file::File::EntityId id) { ASSERT_PRINT(0, "jit should unreachable"); return JSHandle(); } JSTaggedValue JitCompilationEnv::GetConstantPoolByMethodOffset([[maybe_unused]] const uint32_t methodOffset) const { ASSERT(thread_->IsInRunningState()); JSTaggedValue constpool; Method *currMethod = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject()); if (methodOffset != currMethod->GetMethodId().GetOffset()) { auto calleeFunc = GetJsFunctionByMethodOffset(methodOffset); if (!calleeFunc) { return JSTaggedValue::Undefined(); } constpool = Method::Cast(calleeFunc->GetMethod(thread_))->GetConstantPool(thread_); } else { constpool = currMethod->GetConstantPool(thread_); } return constpool; } JSTaggedValue JitCompilationEnv::GetArrayLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const { ASSERT(thread_->IsInRunningState()); return ConstantPool::GetLiteralFromCacheNoScope(thread_, constpool, index, entry); } JSTaggedValue JitCompilationEnv::GetObjectLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const { ASSERT(thread_->IsInRunningState()); return ConstantPool::GetLiteralFromCacheNoScope(thread_, constpool, index, entry); } JSTaggedValue JitCompilationEnv::GetMethodFromCache(JSTaggedValue constpool, uint32_t index) const { return ConstantPool::GetMethodFromCache(constpool, index, thread_); } panda_file::File::EntityId JitCompilationEnv::GetIdFromCache(JSTaggedValue constpool, uint32_t index) const { ASSERT(thread_->IsInRunningState()); return ConstantPool::GetIdFromCache(constpool, index); } JSHandle JitCompilationEnv::GetGlobalEnv() const { ASSERT(globalEnv_.IsJSGlobalEnv()); return JSHandle(ToUintPtr(&globalEnv_)); } const GlobalEnvConstants *JitCompilationEnv::GlobalConstants() const { ASSERT(thread_->IsInRunningState()); return hostThread_->GlobalConstants(); } // The caller should add assessment for undefined constpool. // When slotValue in profileTypeInfo is changed in main thread, constpool may be undefined. JSTaggedValue JitCompilationEnv::GetStringFromConstantPool([[maybe_unused]] const uint32_t methodOffset, const uint16_t cpIdx, bool allowAlloc) const { JSTaggedValue constpool = GetConstantPoolByMethodOffset(methodOffset); if (constpool.IsUndefined()) { return JSTaggedValue::Undefined(); } return ConstantPool::GetStringFromCacheForJit(GetJSThread(), constpool, cpIdx, allowAlloc); } JSFunction *JitCompilationEnv::GetJsFunctionByMethodOffset(uint32_t methodOffset) const { ASSERT(thread_->IsInRunningState()); Method *currMethod = Method::Cast(jsFunction_->GetMethod(thread_).GetTaggedObject()); auto currMethodOffset = currMethod->GetMethodId().GetOffset(); if (methodOffset == currMethodOffset) { return *jsFunction_; } std::vector> funcSlotChain; uint32_t calleeOffset = methodOffset; do { if (functionSlotIdMap_.find(calleeOffset) == functionSlotIdMap_.end()) { return nullptr; } funcSlotChain.push_back({functionSlotIdMap_.at(calleeOffset), callee2CallerMap_.at(calleeOffset)}); calleeOffset = callee2CallerMap_.at(calleeOffset); } while (calleeOffset != currMethodOffset); JSFunction *currFunc = *jsFunction_; ProfileTypeInfo *currFuncPTI = *profileTypeInfo_; for (int i = static_cast(funcSlotChain.size()) - 1; i >= 0; --i) { uint32_t slotId = funcSlotChain[i].first; uint32_t callerOffset = funcSlotChain[i].second; if (Method::Cast(currFunc->GetMethod(thread_))->GetMethodId().GetOffset() != callerOffset) { return nullptr; } auto slotValue = currFuncPTI->Get(thread_, slotId); if (slotValue.IsJSFunction()) { currFunc = JSFunction::Cast(currFuncPTI->Get(thread_, slotId).GetTaggedObject()); } else if (slotValue.IsPrototypeHandler()) { auto prototypeHandler = PrototypeHandler::Cast(slotValue.GetTaggedObject()); auto accessorFunction = prototypeHandler->GetAccessorJSFunction(thread_); if (!accessorFunction.IsJSFunction()) { return nullptr; } currFunc = JSFunction::Cast(accessorFunction.GetTaggedObject()); } else { return nullptr; } auto profileTypeInfoVal = currFunc->GetProfileTypeInfo(thread_); if (profileTypeInfoVal.IsUndefined()) { return nullptr; } currFuncPTI = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject()); } if (Method::Cast(currFunc->GetMethod(thread_))->GetMethodId().GetOffset() != methodOffset) { return nullptr; } return currFunc; } uint32_t JitCompilationEnv::RecordHeapConstant( ConstantPoolHeapConstant heapConstant, const JSHandle &heapObj) { ASSERT(SupportHeapConstant()); auto itr = heapConstantInfo_.constPoolHeapConstant2Index.find(heapConstant); if (itr != heapConstantInfo_.constPoolHeapConstant2Index.end()) { return itr->second; } heapConstantInfo_.heapConstantTable.push_back(heapObj); ASSERT(heapConstantInfo_.heapConstantTable.size() < INVALID_HEAP_CONSTANT_INDEX); uint32_t index = static_cast(heapConstantInfo_.heapConstantTable.size() - 1); heapConstantInfo_.constPoolHeapConstant2Index.insert( std::pair(heapConstant, index)); return index; } JSHandle JitCompilationEnv::GetHeapConstantHandle(uint32_t heapConstantIndex) const { ASSERT(heapConstantIndex < heapConstantInfo_.heapConstantTable.size()); return heapConstantInfo_.heapConstantTable[heapConstantIndex]; } } // namespace panda::ecmascript