mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-06 23:54:03 +00:00
Dictionary to array for fills
Issues: https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8C4I2?from=project-issue Signed-off-by: liuzhijie <jay.lau2020.work@outlook.com> Change-Id: Ie79be53b1ec05381ca6339edb0e94ddfc63d09ea
This commit is contained in:
parent
bba3353ad5
commit
b7a21e857d
@ -745,6 +745,16 @@ JSTaggedValue BuiltinsArray::Fill(EcmaRuntimeCallInfo *argv)
|
||||
// 1. Let O be ToObject(this value).
|
||||
JSHandle<JSTaggedValue> thisHandle = GetThis(argv);
|
||||
JSHandle<JSObject> thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle);
|
||||
|
||||
bool isDictionary = thisObjHandle->GetJSHClass()->IsDictionaryElement();
|
||||
if (isDictionary && thisObjHandle->IsJSArray()) {
|
||||
uint32_t length = JSArray::Cast(*thisObjHandle)->GetLength();
|
||||
uint32_t size = thisObjHandle->GetNumberOfElements();
|
||||
if (length - size > JSObject::MAX_GAP) {
|
||||
JSObject::TryOptimizeAsFastElements(thread, thisObjHandle);
|
||||
}
|
||||
}
|
||||
|
||||
// 2. ReturnIfAbrupt(O).
|
||||
RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
|
||||
JSHandle<JSTaggedValue> thisObjVal(thisObjHandle);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "ecmascript/mem/c_containers.h"
|
||||
#include "ecmascript/subtyping_operator.h"
|
||||
#include "ecmascript/tagged_array-inl.h"
|
||||
#include "ecmascript/tagged_dictionary.h"
|
||||
#include "ecmascript/weak_vector.h"
|
||||
|
||||
namespace panda::ecmascript {
|
||||
@ -220,6 +221,18 @@ void JSHClass::TransitionElementsToDictionary(const JSThread *thread, const JSHa
|
||||
obj->GetJSHClass()->SetElementsKind(ElementsKind::GENERIC);
|
||||
}
|
||||
|
||||
void JSHClass::OptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
|
||||
{
|
||||
if (obj->GetJSHClass()->IsDictionaryMode()) {
|
||||
JSObject::OptimizeAsFastProperties(thread, obj);
|
||||
} else {
|
||||
OptimizeAsFastProperties(thread, obj);
|
||||
}
|
||||
obj->GetJSHClass()->SetIsDictionaryElement(false);
|
||||
obj->GetJSHClass()->SetIsStableElements(true);
|
||||
obj->GetJSHClass()->SetElementsKind(ElementsKind::HOLE_TAGGED);
|
||||
}
|
||||
|
||||
JSHandle<JSHClass> JSHClass::SetPropertyOfObjHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
|
||||
const JSHandle<JSTaggedValue> &key,
|
||||
const PropertyAttributes &attr)
|
||||
@ -454,6 +467,52 @@ void JSHClass::TransitionToDictionary(const JSThread *thread, const JSHandle<JSO
|
||||
}
|
||||
}
|
||||
|
||||
void JSHClass::OptimizeAsFastProperties(const JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
const std::vector<int> &indexOrder, bool isDictionary)
|
||||
{
|
||||
// 1. new a hclass
|
||||
JSHandle<JSHClass> jshclass(thread, obj->GetJSHClass());
|
||||
JSHandle<JSHClass> newJsHClass = Clone(thread, jshclass, isDictionary);
|
||||
UpdateRootHClass(thread, jshclass, newJsHClass);
|
||||
|
||||
// 2. If it is dictionary, migrate should change layout. otherwise, copy the hclass only.
|
||||
JSHandle<NameDictionary> properties(thread, obj->GetProperties());
|
||||
int numberOfProperties = properties->EntriesCount();
|
||||
if (isDictionary) {
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<LayoutInfo> layoutInfoHandle = factory->CreateLayoutInfo(numberOfProperties);
|
||||
int numberOfInlinedProps = newJsHClass->GetInlinedProperties();
|
||||
for (int i = 0; i < numberOfProperties; i++) {
|
||||
JSTaggedValue key = properties->GetKey(indexOrder[i]);
|
||||
PropertyAttributes attributes = properties->GetAttributes(indexOrder[i]);
|
||||
if (i < numberOfInlinedProps) {
|
||||
attributes.SetIsInlinedProps(true);
|
||||
} else {
|
||||
attributes.SetIsInlinedProps(false);
|
||||
}
|
||||
attributes.SetOffset(i);
|
||||
layoutInfoHandle->AddKey(thread, i, key, attributes);
|
||||
}
|
||||
|
||||
{
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
newJsHClass->SetNumberOfProps(numberOfProperties);
|
||||
newJsHClass->SetLayout(thread, layoutInfoHandle);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DISALLOW_GARBAGE_COLLECTION;
|
||||
// 3. Copy
|
||||
newJsHClass->SetIsDictionaryMode(false);
|
||||
// 4. Add newJsHClass to ?
|
||||
#if ECMASCRIPT_ENABLE_IC
|
||||
JSHClass::NotifyHclassChanged(thread, JSHandle<JSHClass>(thread, obj->GetJSHClass()), newJsHClass);
|
||||
#endif
|
||||
obj->SynchronizedSetClass(*newJsHClass);
|
||||
}
|
||||
}
|
||||
|
||||
void JSHClass::TransitionForRepChange(const JSThread *thread, const JSHandle<JSObject> &receiver,
|
||||
const JSHandle<JSTaggedValue> &key, PropertyAttributes attr)
|
||||
{
|
||||
|
@ -386,6 +386,9 @@ public:
|
||||
static JSHandle<JSHClass> CloneWithoutInlinedProperties(const JSThread *thread, const JSHandle<JSHClass> &jshclass);
|
||||
|
||||
static void TransitionElementsToDictionary(const JSThread *thread, const JSHandle<JSObject> &obj);
|
||||
static void OptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
static void OptimizeAsFastProperties(const JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
const std::vector<int> &indexArray = {}, bool isDictionary = false);
|
||||
static JSHandle<JSHClass> SetPropertyOfObjHClass(const JSThread *thread, JSHandle<JSHClass> &jshclass,
|
||||
const JSHandle<JSTaggedValue> &key,
|
||||
const PropertyAttributes &attr);
|
||||
|
@ -239,6 +239,82 @@ void JSObject::ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> o
|
||||
JSHClass::TransitionElementsToDictionary(thread, obj);
|
||||
}
|
||||
|
||||
inline bool JSObject::ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
|
||||
{
|
||||
JSHandle<NumberDictionary> elements(thread, obj->GetElements());
|
||||
uint32_t size = elements->Size();
|
||||
for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
|
||||
JSTaggedValue key = elements->GetKey(hashIndex);
|
||||
if (key.IsUndefined() || key.IsHole()) {
|
||||
continue;
|
||||
}
|
||||
PropertyAttributes attr = elements->GetAttributes(hashIndex);
|
||||
if (!attr.IsDefaultAttributes()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSObject::TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj)
|
||||
{
|
||||
ASSERT(obj->GetJSHClass()->IsDictionaryElement() && obj->IsJSArray());
|
||||
if (ShouldOptimizeAsFastElements(thread, obj)) {
|
||||
uint32_t length = JSArray::Cast(*obj)->GetLength();
|
||||
JSHandle<NumberDictionary> elements(thread, obj->GetElements());
|
||||
uint32_t size = elements->Size();
|
||||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||||
JSHandle<TaggedArray> array = factory->NewTaggedArray(length);
|
||||
for (uint32_t hashIndex = 0; hashIndex < size; hashIndex++) {
|
||||
JSTaggedValue key = elements->GetKey(hashIndex);
|
||||
JSTaggedValue value = elements->GetValue(hashIndex);
|
||||
if (key.IsUndefined() || key.IsHole()) {
|
||||
continue;
|
||||
}
|
||||
array->Set(thread, key.GetNumber(), value);
|
||||
}
|
||||
obj->SetElements(thread, array);
|
||||
JSHClass::OptimizeAsFastElements(thread, obj);
|
||||
}
|
||||
}
|
||||
|
||||
void JSObject::OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj)
|
||||
{
|
||||
ASSERT(obj->GetJSHClass()->IsDictionaryMode());
|
||||
// 1. Get NameDictionary properties
|
||||
JSHandle<NameDictionary> properties(thread, obj->GetProperties());
|
||||
|
||||
int numberOfProperties = properties->EntriesCount();
|
||||
// Make sure we preserve enough capacity
|
||||
if (numberOfProperties > static_cast<int>(PropertyAttributes::MAX_FAST_PROPS_CAPACITY)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
// 2. iteration indices
|
||||
std::vector<int> indexOrder = properties->GetEnumerationOrder();
|
||||
ASSERT(static_cast<int>(indexOrder.size()) == numberOfProperties);
|
||||
|
||||
// 3. Change Hclass
|
||||
int numberOfInlinedProps = obj->GetJSHClass()->GetInlinedProperties();
|
||||
JSHClass::OptimizeAsFastProperties(thread, obj, indexOrder, true);
|
||||
|
||||
// 4. New out-properties
|
||||
int numberOfOutProperties = numberOfProperties - numberOfInlinedProps;
|
||||
ASSERT(numberOfOutProperties >= 0);
|
||||
JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(numberOfOutProperties);
|
||||
|
||||
// 5. Fill properties
|
||||
for (int i = 0; i < numberOfProperties; i++) {
|
||||
JSTaggedValue value = properties->GetValue(indexOrder[i]);
|
||||
if (i < numberOfInlinedProps) {
|
||||
obj->SetPropertyInlinedPropsWithRep(thread, i, value);
|
||||
} else {
|
||||
array->Set(thread, i - numberOfInlinedProps, value);
|
||||
}
|
||||
}
|
||||
obj->SetProperties(thread, array);
|
||||
}
|
||||
|
||||
bool JSObject::IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver)
|
||||
{
|
||||
auto *hclass = receiver->GetJSHClass();
|
||||
|
@ -655,6 +655,7 @@ public:
|
||||
static bool IsArrayLengthWritable(JSThread *thread, const JSHandle<JSObject> &receiver);
|
||||
bool UpdatePropertyInDictionary(const JSThread *thread, JSTaggedValue key, JSTaggedValue value);
|
||||
static bool ShouldTransToDict(uint32_t capacity, uint32_t index);
|
||||
static bool ShouldOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
static JSHandle<TaggedArray> GrowElementsCapacity(const JSThread *thread, const JSHandle<JSObject> &obj,
|
||||
uint32_t capacity, bool highGrowth = false, bool isNew = false);
|
||||
|
||||
@ -670,6 +671,9 @@ public:
|
||||
static JSHandle<JSTaggedValue> IterableToList(JSThread *thread, const JSHandle<JSTaggedValue> &items,
|
||||
JSTaggedValue method = JSTaggedValue::Undefined());
|
||||
|
||||
static void TryOptimizeAsFastElements(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
static void OptimizeAsFastProperties(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
|
||||
protected:
|
||||
static void ElementsToDictionary(const JSThread *thread, JSHandle<JSObject> obj);
|
||||
|
||||
|
@ -16,7 +16,6 @@
|
||||
#ifndef ECMASCRIPT_TAGGED_DICTIONARY_H
|
||||
#define ECMASCRIPT_TAGGED_DICTIONARY_H
|
||||
|
||||
#include "ecmascript/ecma_vm.h"
|
||||
#include "ecmascript/js_tagged_value-inl.h"
|
||||
#include "ecmascript/tagged_array-inl.h"
|
||||
#include "ecmascript/tagged_hash_table.h"
|
||||
@ -76,6 +75,11 @@ public:
|
||||
{
|
||||
return a.second.GetDictionaryOrder() < b.second.GetDictionaryOrder();
|
||||
}
|
||||
static inline bool CompIndex(const PropertyAttributes &a,
|
||||
const PropertyAttributes &b)
|
||||
{
|
||||
return a.GetDictionaryOrder() < b.GetDictionaryOrder();
|
||||
}
|
||||
DECL_DUMP()
|
||||
|
||||
static constexpr int ENTRY_KEY_INDEX = 0;
|
||||
|
@ -18,6 +18,7 @@ group("object_test") {
|
||||
"object_assign",
|
||||
"object_hasOwnProperty",
|
||||
"object_toString",
|
||||
"object_transition",
|
||||
]
|
||||
|
||||
deps = []
|
||||
|
18
test/aottest/object/object_transition/BUILD.gn
Normal file
18
test/aottest/object/object_transition/BUILD.gn
Normal file
@ -0,0 +1,18 @@
|
||||
# Copyright (c) 2023 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.
|
||||
|
||||
import("//arkcompiler/ets_runtime/test/test_helper.gni")
|
||||
|
||||
host_aot_test_action("object_transition") {
|
||||
deps = []
|
||||
}
|
63
test/aottest/object/object_transition/expect_output.txt
Normal file
63
test/aottest/object/object_transition/expect_output.txt
Normal file
@ -0,0 +1,63 @@
|
||||
# Copyright (c) 2023 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.
|
||||
|
||||
TestSample:
|
||||
1
|
||||
TestArrayWithElementsAndProperties:
|
||||
000
|
||||
000
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
2047
|
||||
TestFullArrayWithElementsAndProperties:
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
0
|
||||
undefined
|
||||
undefined
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
2047
|
||||
TestShouldNotOptimizeAsFastElements:
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
undefined
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
0
|
||||
TestStringArrayWithElementsAndProperties:
|
||||
ark
|
||||
ark
|
||||
b
|
||||
TestSpecialCase:
|
151
test/aottest/object/object_transition/object_transition.ts
Normal file
151
test/aottest/object/object_transition/object_transition.ts
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2023 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.
|
||||
*/
|
||||
|
||||
function TestSample()
|
||||
{
|
||||
print("TestSample:");
|
||||
let arr: number[] = new Array(1025).fill(0);
|
||||
arr[1] = 1;
|
||||
print(arr[1]);
|
||||
}
|
||||
|
||||
function TestArrayWithElementsAndProperties()
|
||||
{
|
||||
print("TestArrayWithElementsAndProperties:");
|
||||
let arr: number[] = new Array(2048)
|
||||
arr[1] = 2;
|
||||
arr[3] = 4;
|
||||
arr.x1 = 1;
|
||||
arr.x2 = 2;
|
||||
arr.x3 = 3;
|
||||
arr.x4 = 4;
|
||||
arr.x5 = 5;
|
||||
arr.length = 2047;
|
||||
|
||||
arr.fill("000");
|
||||
print(arr[1]);
|
||||
print(arr[3]);
|
||||
print(arr.x1);
|
||||
print(arr.x2);
|
||||
print(arr.x3);
|
||||
print(arr.x4);
|
||||
print(arr.x5);
|
||||
print(arr.length);
|
||||
}
|
||||
|
||||
function TestFullArrayWithElementsAndProperties()
|
||||
{
|
||||
print("TestFullArrayWithElementsAndProperties:");
|
||||
let arr: number[] = new Array(2048)
|
||||
arr.x1 = 1;
|
||||
arr.x2 = 2;
|
||||
arr.x3 = 3;
|
||||
arr.x4 = 4;
|
||||
arr.x5 = 5;
|
||||
for (let i: number = 0; i < 2048; i++) {
|
||||
arr[i] = "apple"
|
||||
}
|
||||
arr.length = 2047;
|
||||
arr.fill(0);
|
||||
for (let i: number = 0; i < 5; i++) {
|
||||
print(arr[i]);
|
||||
}
|
||||
for (let i: number = 2045; i < 2048; i++) {
|
||||
print(arr[i]);
|
||||
}
|
||||
print(arr.apple);
|
||||
print(arr.x1);
|
||||
print(arr.x2);
|
||||
print(arr.x3);
|
||||
print(arr.x4);
|
||||
print(arr.x5);
|
||||
print(arr.length);
|
||||
}
|
||||
|
||||
function TestShouldNotOptimizeAsFastElements()
|
||||
{
|
||||
print("TestShouldNotOptimizeAsFastElements:");
|
||||
let arr: number[] = new Array(1025)
|
||||
arr.x1 = 1;
|
||||
arr.x2 = 2;
|
||||
arr.x3 = 3;
|
||||
arr.x4 = 4;
|
||||
arr.x5 = 5;
|
||||
for (let i: number = 0; i < 1025; i++) {
|
||||
arr[i] = "apple"
|
||||
}
|
||||
arr.length = 0;
|
||||
arr.fill(0);
|
||||
for (let i: number = 0; i < 5; i++) {
|
||||
print(arr[i]);
|
||||
}
|
||||
for (let i: number = 1020; i < 1025; i++) {
|
||||
print(arr[i]);
|
||||
}
|
||||
print(arr.apple);
|
||||
print(arr.x1);
|
||||
print(arr.x2);
|
||||
print(arr.x3);
|
||||
print(arr.x4);
|
||||
print(arr.x5);
|
||||
print(arr.length);
|
||||
}
|
||||
|
||||
function TestStringArrayWithElementsAndProperties()
|
||||
{
|
||||
print("TestStringArrayWithElementsAndProperties:");
|
||||
let arr: string[] = new Array(1025)
|
||||
arr[1] = "apple"
|
||||
arr.apple = "b"
|
||||
|
||||
arr.fill("ark");
|
||||
print(arr[0]);
|
||||
print(arr[1]);
|
||||
print(arr.apple);
|
||||
}
|
||||
|
||||
function TestSpecialCase()
|
||||
{
|
||||
print("TestSpecialCase:");
|
||||
let arr: number[] = new Array(1025);
|
||||
Object.defineProperty(arr, '0', {
|
||||
value: 42,
|
||||
writable: false,
|
||||
});
|
||||
arr.fill(1);
|
||||
print(arr[0]);
|
||||
}
|
||||
|
||||
TestSample();
|
||||
TestArrayWithElementsAndProperties();
|
||||
TestFullArrayWithElementsAndProperties();
|
||||
TestShouldNotOptimizeAsFastElements();
|
||||
TestStringArrayWithElementsAndProperties();
|
||||
TestSpecialCase();
|
Loading…
Reference in New Issue
Block a user