arkcompiler_ets_runtime/ecmascript/compiler/jit_compilation_env.cpp
yuanxupeng 2a525ef042 Ofix jit compiler inline crash
Add undefined assessment in functions which get key from constpool

Issue:     https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/IAQDDZ
Signed-off-by: yuanxupeng <yuanxupeng@huawei.com>
2024-09-11 14:24:57 +08:00

234 lines
9.3 KiB
C++

/*
* 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/ecma_context.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/pgo_profiler/pgo_profiler.h"
#include "ecmascript/ic/profile_type_info.h"
#include "ecmascript/ic/ic_handler.h"
namespace panda::ecmascript {
// jit
JitCompilationEnv::JitCompilationEnv(EcmaVM *jitVm, EcmaVM *jsVm, JSHandle<JSFunction> &jsFunction)
: CompilationEnv(jitVm), hostThread_(jsVm->GetJSThreadNoCheck()), jsFunction_(jsFunction)
{
ptManager_ = hostThread_->GetCurrentEcmaContext()->GetPTManager();
Method *method = Method::Cast(jsFunction->GetMethod().GetTaggedObject());
jsPandaFile_ = const_cast<JSPandaFile*>(method->GetJSPandaFile());
methodLiteral_ = method->GetMethodLiteral();
pcStart_ = method->GetBytecodeArray();
abcId_ = PGOProfiler::GetMethodAbcId(*jsFunction);
if (method->GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR) {
methodLiteral_->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR);
}
}
JSRuntimeOptions &JitCompilationEnv::GetJSOptions()
{
return hostThread_->GetEcmaVM()->GetJSOptions();
}
const CMap<ElementsKind, std::pair<ConstantIndex, ConstantIndex>> &JitCompilationEnv::GetArrayHClassIndexMap() const
{
return hostThread_->GetArrayHClassIndexMap();
}
const BuiltinHClassEntries &JitCompilationEnv::GetBuiltinHClassEntries() const
{
return hostThread_->GetBuiltinHClassEntries();
}
JSHClass *JitCompilationEnv::GetBuiltinPrototypeHClass(BuiltinTypeId type) const
{
return hostThread_->GetBuiltinPrototypeHClass(type);
}
void JitCompilationEnv::SetTsManagerCompilationEnv()
{
auto pt = hostThread_->GetCurrentEcmaContext()->GetPTManager();
ptManager_ = pt;
}
std::shared_ptr<pgo::PGOProfiler> 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().GetTaggedObject());
JSTaggedValue constpool = method->GetConstantPool();
[[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().GetTaggedObject());
JSTaggedValue constpool = method->GetConstantPool();
[[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_->GetCurrentEcmaContext()->FindUnsharedConstpool(constpool);
return unSharedConstpool;
}
JSTaggedValue JitCompilationEnv::FindOrCreateUnsharedConstpool([[maybe_unused]] JSTaggedValue sharedConstpool) const
{
Method *method = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
[[maybe_unused]] JSTaggedValue constpool = method->GetConstantPool();
ASSERT(constpool == sharedConstpool);
uint32_t methodOffset = method->GetMethodId().GetOffset();
return FindOrCreateUnsharedConstpool(methodOffset);
}
JSHandle<ConstantPool> JitCompilationEnv::FindOrCreateConstPool([[maybe_unused]] const JSPandaFile *jsPandaFile,
[[maybe_unused]] panda_file::File::EntityId id)
{
ASSERT_PRINT(0, "jit should unreachable");
return JSHandle<ConstantPool>();
}
JSTaggedValue JitCompilationEnv::GetConstantPoolByMethodOffset([[maybe_unused]] const uint32_t methodOffset) const
{
ASSERT(thread_->IsInRunningState());
JSTaggedValue constpool;
Method *currMethod = Method::Cast(jsFunction_->GetMethod().GetTaggedObject());
if (methodOffset != currMethod->GetMethodId().GetOffset()) {
auto calleeFunc = GetJsFunctionByMethodOffset(methodOffset);
if (!calleeFunc) {
return JSTaggedValue::Undefined();
}
constpool = Method::Cast(calleeFunc->GetMethod())->GetConstantPool();
} else {
constpool = currMethod->GetConstantPool();
}
return constpool;
}
JSTaggedValue JitCompilationEnv::GetArrayLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
{
ASSERT(thread_->IsInRunningState());
return ConstantPool::GetLiteralFromCache<ConstPoolType::ARRAY_LITERAL>(constpool, index, entry);
}
JSTaggedValue JitCompilationEnv::GetObjectLiteralFromCache(JSTaggedValue constpool, uint32_t index, CString entry) const
{
ASSERT(thread_->IsInRunningState());
return ConstantPool::GetLiteralFromCache<ConstPoolType::OBJECT_LITERAL>(constpool, index, entry);
}
JSTaggedValue JitCompilationEnv::GetMethodFromCache(JSTaggedValue constpool, uint32_t index) const
{
return ConstantPool::GetMethodFromCache(constpool, index);
}
panda_file::File::EntityId JitCompilationEnv::GetIdFromCache(JSTaggedValue constpool, uint32_t index) const
{
ASSERT(thread_->IsInRunningState());
return ConstantPool::GetIdFromCache(constpool, index);
}
JSHandle<GlobalEnv> JitCompilationEnv::GetGlobalEnv() const
{
ASSERT(thread_->IsInRunningState());
return hostThread_->GetEcmaVM()->GetGlobalEnv();
}
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().GetTaggedObject());
auto currMethodOffset = currMethod->GetMethodId().GetOffset();
if (methodOffset == currMethodOffset) {
return *jsFunction_;
}
std::vector<std::pair<uint32_t, uint32_t>> 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<int>(funcSlotChain.size()) - 1; i >= 0; --i) {
uint32_t slotId = funcSlotChain[i].first;
uint32_t callerOffset = funcSlotChain[i].second;
if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != callerOffset) {
return nullptr;
}
auto slotValue = currFuncPTI->Get(slotId);
if (slotValue.IsJSFunction()) {
currFunc = JSFunction::Cast(currFuncPTI->Get(slotId).GetTaggedObject());
} else if (slotValue.IsPrototypeHandler()) {
auto prototypeHandler = PrototypeHandler::Cast(slotValue.GetTaggedObject());
auto accessorFunction = prototypeHandler->GetAccessorJSFunction();
if (!accessorFunction.IsJSFunction()) {
return nullptr;
}
currFunc = JSFunction::Cast(accessorFunction.GetTaggedObject());
} else {
return nullptr;
}
auto profileTypeInfoVal = currFunc->GetProfileTypeInfo();
if (profileTypeInfoVal.IsUndefined()) {
return nullptr;
}
currFuncPTI = ProfileTypeInfo::Cast(profileTypeInfoVal.GetTaggedObject());
}
if (Method::Cast(currFunc->GetMethod())->GetMethodId().GetOffset() != methodOffset) {
return nullptr;
}
return currFunc;
}
} // namespace panda::ecmascript