mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
commit
9ae3bad8b0
1
BUILD.gn
1
BUILD.gn
@ -711,7 +711,6 @@ ecma_source = [
|
||||
"ecmascript/extractortool/src/source_map.cpp",
|
||||
"ecmascript/frames.cpp",
|
||||
"ecmascript/free_object.cpp",
|
||||
"ecmascript/function_proto_transition_table.cpp",
|
||||
"ecmascript/generator_helper.cpp",
|
||||
"ecmascript/async_generator_helper.cpp",
|
||||
"ecmascript/global_env.cpp",
|
||||
|
@ -15,7 +15,6 @@
|
||||
|
||||
#include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
|
||||
|
||||
#include "ecmascript/function_proto_transition_table.h"
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/jspandafile/program_object.h"
|
||||
#include "ecmascript/layout_info-inl.h"
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "ecmascript/builtins/builtins_regexp.h"
|
||||
#include "ecmascript/builtins/builtins_number.h"
|
||||
#include "ecmascript/builtins/builtins_string.h"
|
||||
#include "ecmascript/function_proto_transition_table.h"
|
||||
#include "ecmascript/compiler/aot_file/an_file_data_manager.h"
|
||||
#include "ecmascript/compiler/common_stubs.h"
|
||||
#include "ecmascript/compiler/pgo_type/pgo_type_manager.h"
|
||||
|
@ -1,211 +0,0 @@
|
||||
/*
|
||||
* 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/function_proto_transition_table.h"
|
||||
|
||||
#include "ecmascript/js_hclass-inl.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
using ProtoArray = FunctionProtoTransitionTable::ProtoArray;
|
||||
FunctionProtoTransitionTable::FunctionProtoTransitionTable(const JSThread *thread)
|
||||
{
|
||||
protoTransitionTable_ = PointerToIndexDictionary::Create(thread, DEFAULT_FIRST_LEVEL_SIZE).GetTaggedValue();
|
||||
}
|
||||
|
||||
FunctionProtoTransitionTable::~FunctionProtoTransitionTable()
|
||||
{
|
||||
fakeParentMap_.clear();
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::Iterate(const RootVisitor &v)
|
||||
{
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&protoTransitionTable_)));
|
||||
for (auto &iter : fakeParentMap_) {
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
|
||||
}
|
||||
for (auto &iter : fakeChildMap_) {
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::UpdateProtoTransitionTable(const JSThread *thread,
|
||||
JSHandle<PointerToIndexDictionary> map)
|
||||
{
|
||||
// PointerToIndexDictionary's hash value is a hclass pointer,
|
||||
// and the hclass pointer could change during deserialized,
|
||||
// so rehash is needed after deserialized.
|
||||
auto newMap = PointerToIndexDictionary::Create(thread, map->Size());
|
||||
map->Rehash(thread, *newMap);
|
||||
protoTransitionTable_ = newMap.GetTaggedValue();
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::InsertTransitionItem(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc,
|
||||
JSHandle<JSTaggedValue> transIhc,
|
||||
JSHandle<JSTaggedValue> transPhc)
|
||||
{
|
||||
JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
|
||||
int32_t entry1 = protoTransitionHandle->FindEntry(ihc.GetTaggedValue());
|
||||
if (entry1 != -1) {
|
||||
JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(entry1));
|
||||
auto entry2 = protoArray->FindEntry(baseIhc.GetTaggedValue());
|
||||
if (entry2 != -1) {
|
||||
LOG_ECMA(DEBUG) << "Record prototype for current function already!";
|
||||
return;
|
||||
}
|
||||
uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
|
||||
protoArray->SetEntry(
|
||||
thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
|
||||
return;
|
||||
}
|
||||
JSHandle<ProtoArray> protoArray = ProtoArray::Create(thread);
|
||||
uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
|
||||
protoArray->SetEntry(
|
||||
thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
|
||||
JSHandle<PointerToIndexDictionary> newTransitionTable =
|
||||
PointerToIndexDictionary::PutIfAbsent(thread, protoTransitionHandle, ihc, JSHandle<JSTaggedValue>(protoArray));
|
||||
protoTransitionTable_ = newTransitionTable.GetTaggedValue();
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FunctionProtoTransitionTable::FindTransitionByHClass(
|
||||
const JSThread *thread, JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> baseIhc) const
|
||||
{
|
||||
ASSERT(ihc->IsJSHClass());
|
||||
ASSERT(baseIhc->IsJSHClass());
|
||||
JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
|
||||
int32_t entry1 = protoTransitionHandle->FindEntry(ihc.GetTaggedValue());
|
||||
if (entry1 == -1) {
|
||||
LOG_ECMA(DEBUG) << "Selected ihc not found2!";
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(entry1));
|
||||
int32_t entry2 = protoArray->FindEntry(baseIhc.GetTaggedValue());
|
||||
if (entry2 == -1) {
|
||||
LOG_ECMA(ERROR) << "Selected baseIhc not found!";
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
return protoArray->GetTransition(entry2);
|
||||
}
|
||||
|
||||
bool FunctionProtoTransitionTable::TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent)
|
||||
{
|
||||
// Situation:
|
||||
// 1: d1.prototype = p
|
||||
// 2: d2.prototype = p
|
||||
// this check is true for step 2
|
||||
auto iter1 = fakeParentMap_.find(child);
|
||||
if (child == parent && iter1 != fakeParentMap_.end()) {
|
||||
return true;
|
||||
}
|
||||
auto iter2 = fakeChildMap_.find(parent);
|
||||
if (iter2 != fakeChildMap_.end()) {
|
||||
if (iter2->second != child) {
|
||||
LOG_ECMA(DEBUG) << "Unsupported mapping for a parent to more than 1 childs!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter1 == fakeParentMap_.end()) {
|
||||
fakeParentMap_[child] = parent;
|
||||
fakeChildMap_[parent] = child;
|
||||
return true;
|
||||
}
|
||||
if (iter1->second == parent) {
|
||||
return true;
|
||||
}
|
||||
LOG_ECMA(ERROR) << "Conflict mapping for the same child";
|
||||
return false;
|
||||
}
|
||||
|
||||
JSTaggedType FunctionProtoTransitionTable::GetFakeParent(JSTaggedType child) const
|
||||
{
|
||||
auto iter = fakeParentMap_.find(child);
|
||||
if (iter != fakeParentMap_.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
JSHandle<ProtoArray> ProtoArray::Create(const JSThread *thread)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> result = factory->NewTaggedArray(ENTRY_NUMBER * ENTRY_SIZE);
|
||||
return JSHandle<ProtoArray>(result);
|
||||
}
|
||||
|
||||
// static
|
||||
bool ProtoArray::GetEntry(JSHandle<JSHClass> hclass)
|
||||
{
|
||||
return JSHandle<JSHClass>(hclass)->IsPrototype() ? ProtoArray::CLONED_ENTRY_INDEX
|
||||
: ProtoArray::INIT_ENTRY_INDEX;
|
||||
}
|
||||
|
||||
void ProtoArray::SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc,
|
||||
JSTaggedValue transPhc)
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE;
|
||||
uint32_t keyIndex = entryIndex + KEY_INDEX;
|
||||
uint32_t ihcIndex = entryIndex + TRANS_IHC_INDEX;
|
||||
uint32_t phcIndex = entryIndex + TRANS_PHC_INDEX;
|
||||
Set(thread, keyIndex, key);
|
||||
Set(thread, ihcIndex, transIhc);
|
||||
Set(thread, phcIndex, transPhc);
|
||||
}
|
||||
|
||||
JSTaggedValue ProtoArray::GetKey(uint32_t index) const
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE;
|
||||
uint32_t keyIndex = entryIndex + KEY_INDEX;
|
||||
return Get(keyIndex);
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::GetTransition(uint32_t index) const
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue transIhc = Get(entryIndex + TRANS_IHC_INDEX);
|
||||
JSTaggedValue transPhc = Get(entryIndex + TRANS_PHC_INDEX);
|
||||
return std::make_pair(transIhc, transPhc);
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::FindTransition(JSTaggedValue key) const
|
||||
{
|
||||
for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
|
||||
uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue keyValue = Get(index);
|
||||
if (keyValue == key) {
|
||||
JSTaggedValue transIhc = Get(index + TRANS_IHC_INDEX);
|
||||
JSTaggedValue transPhc = Get(index + TRANS_PHC_INDEX);
|
||||
return std::make_pair(transIhc, transPhc);
|
||||
}
|
||||
}
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
|
||||
int32_t ProtoArray::FindEntry(JSTaggedValue key) const
|
||||
{
|
||||
for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
|
||||
uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue keyValue = Get(index);
|
||||
if (keyValue == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef ECMASCRIPT_CLASS_LIKE_FUNCTION_TRANSITION_MAP_H
|
||||
#define ECMASCRIPT_CLASS_LIKE_FUNCTION_TRANSITION_MAP_H
|
||||
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
class FunctionProtoTransitionTable {
|
||||
public:
|
||||
explicit FunctionProtoTransitionTable(const JSThread *thread);
|
||||
virtual ~FunctionProtoTransitionTable();
|
||||
|
||||
void Iterate(const RootVisitor &v);
|
||||
|
||||
void InsertTransitionItem(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc,
|
||||
JSHandle<JSTaggedValue> transIhc,
|
||||
JSHandle<JSTaggedValue> transPhc);
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FindTransitionByHClass(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc) const;
|
||||
|
||||
bool TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent);
|
||||
JSTaggedType GetFakeParent(JSTaggedType child) const;
|
||||
|
||||
JSTaggedValue GetProtoTransitionTable() const
|
||||
{
|
||||
return protoTransitionTable_;
|
||||
}
|
||||
|
||||
void UpdateProtoTransitionTable(const JSThread *thread, JSHandle<PointerToIndexDictionary> map);
|
||||
|
||||
class ProtoArray : public TaggedArray {
|
||||
public:
|
||||
CAST_CHECK(ProtoArray, IsTaggedArray);
|
||||
|
||||
static JSHandle<ProtoArray> Create(const JSThread *thread);
|
||||
void SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc,
|
||||
JSTaggedValue transPhc);
|
||||
JSTaggedValue GetKey(uint32_t index) const;
|
||||
std::pair<JSTaggedValue, JSTaggedValue> GetTransition(uint32_t index) const;
|
||||
int32_t FindEntry(JSTaggedValue key) const;
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FindTransition(JSTaggedValue key) const;
|
||||
static bool GetEntry(JSHandle<JSHClass> hclass);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t ENTRY_NUMBER = 2;
|
||||
static constexpr uint32_t INIT_ENTRY_INDEX = 0;
|
||||
static constexpr uint32_t CLONED_ENTRY_INDEX = 1;
|
||||
|
||||
static constexpr uint32_t ENTRY_SIZE = 3;
|
||||
static constexpr uint32_t KEY_INDEX = 0;
|
||||
static constexpr uint32_t TRANS_IHC_INDEX = 1;
|
||||
static constexpr uint32_t TRANS_PHC_INDEX = 2;
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr uint32_t DEFAULT_FIRST_LEVEL_SIZE = 2;
|
||||
// second level table:
|
||||
// <PointerToIndexDictionary(n):
|
||||
// [ihc,
|
||||
// <ProtoArray(2):
|
||||
// [base.ihc,
|
||||
// (trans_ihc, trans_phc)
|
||||
// ]
|
||||
// [base.ihc(cloned),
|
||||
// (trans_ihc, trans_phc)
|
||||
// ]
|
||||
// >
|
||||
// ]
|
||||
// ...
|
||||
// >
|
||||
JSTaggedValue protoTransitionTable_ {JSTaggedValue::Hole()};
|
||||
// hclasses after set prototype maps to hclasses before set prototype
|
||||
CUnorderedMap<JSTaggedType, JSTaggedType> fakeParentMap_ {};
|
||||
// reverse fakeParentMap_
|
||||
CUnorderedMap<JSTaggedType, JSTaggedType> fakeChildMap_ {};
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
#endif // ECMASCRIPT_CLASS_LIKE_FUNCTION_TRANSITION_MAP_H
|
@ -16,7 +16,6 @@
|
||||
#include "ecmascript/js_function.h"
|
||||
|
||||
#include "ecmascript/base/error_type.h"
|
||||
#include "ecmascript/function_proto_transition_table.h"
|
||||
#include "ecmascript/ecma_macros.h"
|
||||
#include "ecmascript/ecma_runtime_call_info.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
|
@ -19,7 +19,6 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "ecmascript/base/config.h"
|
||||
#include "ecmascript/function_proto_transition_table.h"
|
||||
#include "ecmascript/global_env.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler.h"
|
||||
#include "ecmascript/pgo_profiler/pgo_profiler_layout.h"
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "ecmascript/function_proto_transition_table.h"
|
||||
#include "ecmascript/elements.h"
|
||||
#include "ecmascript/enum_conversion.h"
|
||||
#include "ecmascript/ic/ic_handler.h"
|
||||
|
@ -452,4 +452,195 @@ JSHandle<PointerToIndexDictionary> PointerToIndexDictionary::PutIfAbsent(
|
||||
newDictionary->IncreaseEntries(thread);
|
||||
return newDictionary;
|
||||
}
|
||||
|
||||
using ProtoArray = FunctionProtoTransitionTable::ProtoArray;
|
||||
FunctionProtoTransitionTable::FunctionProtoTransitionTable(const JSThread *thread)
|
||||
{
|
||||
protoTransitionTable_ = PointerToIndexDictionary::Create(thread, DEFAULT_FIRST_LEVEL_SIZE).GetTaggedValue();
|
||||
}
|
||||
|
||||
FunctionProtoTransitionTable::~FunctionProtoTransitionTable()
|
||||
{
|
||||
fakeParentMap_.clear();
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::Iterate(const RootVisitor &v)
|
||||
{
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&protoTransitionTable_)));
|
||||
for (auto &iter : fakeParentMap_) {
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
|
||||
}
|
||||
for (auto &iter : fakeChildMap_) {
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.first)));
|
||||
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&iter.second)));
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::UpdateProtoTransitionTable(const JSThread *thread,
|
||||
JSHandle<PointerToIndexDictionary> map)
|
||||
{
|
||||
// PointerToIndexDictionary's hash value is a hclass pointer,
|
||||
// and the hclass pointer could change during deserialized,
|
||||
// so rehash is needed after deserialized.
|
||||
auto newMap = PointerToIndexDictionary::Create(thread, map->Size());
|
||||
map->Rehash(thread, *newMap);
|
||||
protoTransitionTable_ = newMap.GetTaggedValue();
|
||||
}
|
||||
|
||||
void FunctionProtoTransitionTable::InsertTransitionItem(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc,
|
||||
JSHandle<JSTaggedValue> transIhc,
|
||||
JSHandle<JSTaggedValue> transPhc)
|
||||
{
|
||||
JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
|
||||
int32_t entry1 = protoTransitionHandle->FindEntry(ihc.GetTaggedValue());
|
||||
if (entry1 != -1) {
|
||||
JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(entry1));
|
||||
auto entry2 = protoArray->FindEntry(baseIhc.GetTaggedValue());
|
||||
if (entry2 != -1) {
|
||||
LOG_ECMA(DEBUG) << "Record prototype for current function already!";
|
||||
return;
|
||||
}
|
||||
uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
|
||||
protoArray->SetEntry(
|
||||
thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
|
||||
return;
|
||||
}
|
||||
JSHandle<ProtoArray> protoArray = ProtoArray::Create(thread);
|
||||
uint32_t insertEntry = ProtoArray::GetEntry(JSHandle<JSHClass>(baseIhc));
|
||||
protoArray->SetEntry(
|
||||
thread, insertEntry, baseIhc.GetTaggedValue(), transIhc.GetTaggedValue(), transPhc.GetTaggedValue());
|
||||
JSHandle<PointerToIndexDictionary> newTransitionTable =
|
||||
PointerToIndexDictionary::PutIfAbsent(thread, protoTransitionHandle, ihc, JSHandle<JSTaggedValue>(protoArray));
|
||||
protoTransitionTable_ = newTransitionTable.GetTaggedValue();
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FunctionProtoTransitionTable::FindTransitionByHClass(
|
||||
const JSThread *thread, JSHandle<JSTaggedValue> ihc, JSHandle<JSTaggedValue> baseIhc) const
|
||||
{
|
||||
ASSERT(ihc->IsJSHClass());
|
||||
ASSERT(baseIhc->IsJSHClass());
|
||||
JSHandle<PointerToIndexDictionary> protoTransitionHandle(thread, protoTransitionTable_);
|
||||
int32_t entry1 = protoTransitionHandle->FindEntry(ihc.GetTaggedValue());
|
||||
if (entry1 == -1) {
|
||||
LOG_ECMA(DEBUG) << "Selected ihc not found2!";
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
JSHandle<ProtoArray> protoArray(thread, protoTransitionHandle->GetValue(entry1));
|
||||
int32_t entry2 = protoArray->FindEntry(baseIhc.GetTaggedValue());
|
||||
if (entry2 == -1) {
|
||||
LOG_ECMA(ERROR) << "Selected baseIhc not found!";
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
return protoArray->GetTransition(entry2);
|
||||
}
|
||||
|
||||
bool FunctionProtoTransitionTable::TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent)
|
||||
{
|
||||
// Situation:
|
||||
// 1: d1.prototype = p
|
||||
// 2: d2.prototype = p
|
||||
// this check is true for step 2
|
||||
auto iter1 = fakeParentMap_.find(child);
|
||||
if (child == parent && iter1 != fakeParentMap_.end()) {
|
||||
return true;
|
||||
}
|
||||
auto iter2 = fakeChildMap_.find(parent);
|
||||
if (iter2 != fakeChildMap_.end()) {
|
||||
if (iter2->second != child) {
|
||||
LOG_ECMA(DEBUG) << "Unsupported mapping for a parent to more than 1 childs!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter1 == fakeParentMap_.end()) {
|
||||
fakeParentMap_[child] = parent;
|
||||
fakeChildMap_[parent] = child;
|
||||
return true;
|
||||
}
|
||||
if (iter1->second == parent) {
|
||||
return true;
|
||||
}
|
||||
LOG_ECMA(ERROR) << "Conflict mapping for the same child";
|
||||
return false;
|
||||
}
|
||||
|
||||
JSTaggedType FunctionProtoTransitionTable::GetFakeParent(JSTaggedType child) const
|
||||
{
|
||||
auto iter = fakeParentMap_.find(child);
|
||||
if (iter != fakeParentMap_.end()) {
|
||||
return iter->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// static
|
||||
JSHandle<ProtoArray> ProtoArray::Create(const JSThread *thread)
|
||||
{
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> result = factory->NewTaggedArray(ENTRY_NUMBER * ENTRY_SIZE);
|
||||
return JSHandle<ProtoArray>(result);
|
||||
}
|
||||
|
||||
// static
|
||||
bool ProtoArray::GetEntry(JSHandle<JSHClass> hclass)
|
||||
{
|
||||
return JSHandle<JSHClass>(hclass)->IsPrototype() ? ProtoArray::CLONED_ENTRY_INDEX
|
||||
: ProtoArray::INIT_ENTRY_INDEX;
|
||||
}
|
||||
|
||||
void ProtoArray::SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc,
|
||||
JSTaggedValue transPhc)
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE;
|
||||
uint32_t keyIndex = entryIndex + KEY_INDEX;
|
||||
uint32_t ihcIndex = entryIndex + TRANS_IHC_INDEX;
|
||||
uint32_t phcIndex = entryIndex + TRANS_PHC_INDEX;
|
||||
Set(thread, keyIndex, key);
|
||||
Set(thread, ihcIndex, transIhc);
|
||||
Set(thread, phcIndex, transPhc);
|
||||
}
|
||||
|
||||
JSTaggedValue ProtoArray::GetKey(uint32_t index) const
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE;
|
||||
uint32_t keyIndex = entryIndex + KEY_INDEX;
|
||||
return Get(keyIndex);
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::GetTransition(uint32_t index) const
|
||||
{
|
||||
uint32_t entryIndex = index * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue transIhc = Get(entryIndex + TRANS_IHC_INDEX);
|
||||
JSTaggedValue transPhc = Get(entryIndex + TRANS_PHC_INDEX);
|
||||
return std::make_pair(transIhc, transPhc);
|
||||
}
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> ProtoArray::FindTransition(JSTaggedValue key) const
|
||||
{
|
||||
for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
|
||||
uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue keyValue = Get(index);
|
||||
if (keyValue == key) {
|
||||
JSTaggedValue transIhc = Get(index + TRANS_IHC_INDEX);
|
||||
JSTaggedValue transPhc = Get(index + TRANS_PHC_INDEX);
|
||||
return std::make_pair(transIhc, transPhc);
|
||||
}
|
||||
}
|
||||
return std::make_pair(JSTaggedValue::Undefined(), JSTaggedValue::Undefined());
|
||||
}
|
||||
|
||||
int32_t ProtoArray::FindEntry(JSTaggedValue key) const
|
||||
{
|
||||
for (uint32_t i = 0; i < ENTRY_NUMBER; i++) {
|
||||
uint32_t index = i * ENTRY_SIZE + KEY_INDEX;
|
||||
JSTaggedValue keyValue = Get(index);
|
||||
if (keyValue == key) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
} // namespace panda::ecmascript
|
||||
|
@ -194,5 +194,79 @@ public:
|
||||
static constexpr int ENTRY_VALUE_INDEX = 1;
|
||||
static constexpr int ENTRY_SIZE = 2;
|
||||
};
|
||||
|
||||
class FunctionProtoTransitionTable {
|
||||
public:
|
||||
explicit FunctionProtoTransitionTable(const JSThread *thread);
|
||||
virtual ~FunctionProtoTransitionTable();
|
||||
|
||||
void Iterate(const RootVisitor &v);
|
||||
|
||||
void InsertTransitionItem(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc,
|
||||
JSHandle<JSTaggedValue> transIhc,
|
||||
JSHandle<JSTaggedValue> transPhc);
|
||||
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FindTransitionByHClass(const JSThread *thread,
|
||||
JSHandle<JSTaggedValue> ihc,
|
||||
JSHandle<JSTaggedValue> baseIhc) const;
|
||||
|
||||
bool TryInsertFakeParentItem(JSTaggedType child, JSTaggedType parent);
|
||||
JSTaggedType GetFakeParent(JSTaggedType child) const;
|
||||
|
||||
JSTaggedValue GetProtoTransitionTable() const
|
||||
{
|
||||
return protoTransitionTable_;
|
||||
}
|
||||
|
||||
void UpdateProtoTransitionTable(const JSThread *thread, JSHandle<PointerToIndexDictionary> map);
|
||||
|
||||
class ProtoArray : public TaggedArray {
|
||||
public:
|
||||
CAST_CHECK(ProtoArray, IsTaggedArray);
|
||||
|
||||
static JSHandle<ProtoArray> Create(const JSThread *thread);
|
||||
void SetEntry(const JSThread *thread, uint32_t index, JSTaggedValue key, JSTaggedValue transIhc,
|
||||
JSTaggedValue transPhc);
|
||||
JSTaggedValue GetKey(uint32_t index) const;
|
||||
std::pair<JSTaggedValue, JSTaggedValue> GetTransition(uint32_t index) const;
|
||||
int32_t FindEntry(JSTaggedValue key) const;
|
||||
std::pair<JSTaggedValue, JSTaggedValue> FindTransition(JSTaggedValue key) const;
|
||||
static bool GetEntry(JSHandle<JSHClass> hclass);
|
||||
|
||||
private:
|
||||
static constexpr uint32_t ENTRY_NUMBER = 2;
|
||||
static constexpr uint32_t INIT_ENTRY_INDEX = 0;
|
||||
static constexpr uint32_t CLONED_ENTRY_INDEX = 1;
|
||||
|
||||
static constexpr uint32_t ENTRY_SIZE = 3;
|
||||
static constexpr uint32_t KEY_INDEX = 0;
|
||||
static constexpr uint32_t TRANS_IHC_INDEX = 1;
|
||||
static constexpr uint32_t TRANS_PHC_INDEX = 2;
|
||||
};
|
||||
|
||||
private:
|
||||
static constexpr uint32_t DEFAULT_FIRST_LEVEL_SIZE = 2;
|
||||
// second level table:
|
||||
// <PointerToIndexDictionary(n):
|
||||
// [ihc,
|
||||
// <ProtoArray(2):
|
||||
// [base.ihc,
|
||||
// (trans_ihc, trans_phc)
|
||||
// ]
|
||||
// [base.ihc(cloned),
|
||||
// (trans_ihc, trans_phc)
|
||||
// ]
|
||||
// >
|
||||
// ]
|
||||
// ...
|
||||
// >
|
||||
JSTaggedValue protoTransitionTable_ {JSTaggedValue::Hole()};
|
||||
// hclasses after set prototype maps to hclasses before set prototype
|
||||
CUnorderedMap<JSTaggedType, JSTaggedType> fakeParentMap_ {};
|
||||
// reverse fakeParentMap_
|
||||
CUnorderedMap<JSTaggedType, JSTaggedType> fakeChildMap_ {};
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
#endif // ECMASCRIPT_NEW_DICTIONARY_H
|
||||
|
Loading…
Reference in New Issue
Block a user