Optimize Map/Set.clear

Change-Id: Ide6559f8de763eb3b09d58d9b4fa8edd6f1c9b9a
Signed-off-by: Artem Udovichenko <artem.udovichenko@huawei.com>
This commit is contained in:
Artem Udovichenko 2024-04-16 01:28:39 +08:00
parent 4ee8e5f33e
commit ce2066a698
6 changed files with 113 additions and 5 deletions

View File

@ -373,13 +373,32 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
env->SubCfgEntry(&entry);
Label exit(env);
Label setLinked(env);
DEFVARIABLE(result, VariableType::JS_ANY(), linkedTable);
GateRef newTable = Create(Int32(LinkedHashTableType::MIN_CAPACITY));
Label reuseExistingTable(env);
Label createNewTable(env);
GateRef cap = GetCapacity(linkedTable);
GateRef minCapacity = Int32(LinkedHashTableType::MIN_CAPACITY);
BRANCH(Equal(cap, minCapacity), &reuseExistingTable, &createNewTable);
Bind(&reuseExistingTable);
size_t length = LinkedHashTableType::GetLengthOfTable(LinkedHashTableType::MIN_CAPACITY);
for (size_t i = LinkedHashTableType::ELEMENTS_START_INDEX; i < length; ++i) {
SetValueToTaggedArray(VariableType::JS_NOT_POINTER(), glue_, linkedTable, Int32(i), Hole());
}
GateRef numberOfElements = GetNumberOfElements(linkedTable);
GateRef numberOfDeletedElements = GetNumberOfDeletedElements(linkedTable);
SetNumberOfElements(linkedTable, Int32(0));
SetNumberOfDeletedElements(linkedTable, Int32Add(numberOfElements, numberOfDeletedElements));
Jump(&exit);
Bind(&createNewTable);
GateRef newTable = Create(minCapacity);
result = newTable;
Label noException(env);
BRANCH(TaggedIsException(newTable), &exit, &noException);
Bind(&noException);
GateRef cap = GetCapacity(linkedTable);
Label capGreaterZero(env);
BRANCH(Int32GreaterThan(cap, Int32(0)), &capGreaterZero, &exit);
Bind(&capGreaterZero);
@ -392,8 +411,9 @@ GateRef LinkedHashTableStubBuilder<LinkedHashTableType, LinkedHashTableObject>::
}
Bind(&exit);
GateRef res = *result;
env->SubCfgExit();
return newTable;
return res;
}
template GateRef LinkedHashTableStubBuilder<LinkedHashMap, LinkedHashMapObject>::Clear(GateRef);

View File

@ -177,6 +177,13 @@ bool LinkedHashMap::Has(const JSThread *thread, JSTaggedValue key) const
JSHandle<LinkedHashMap> LinkedHashMap::Clear(const JSThread *thread, const JSHandle<LinkedHashMap> &table)
{
if (table->Capacity() == LinkedHashMap::MIN_CAPACITY) {
table->FillRangeWithSpecialValue(JSTaggedValue::Hole(), LinkedHashMap::ELEMENTS_START_INDEX,
table->GetLength());
table->SetNumberOfDeletedElements(thread, table->NumberOfDeletedElements() + table->NumberOfElements());
table->SetNumberOfElements(thread, 0);
return table;
}
JSHandle<LinkedHashMap> newMap = LinkedHashMap::Create(thread, LinkedHashMap::MIN_CAPACITY,
table.GetTaggedValue().IsInSharedHeap() ? MemSpaceKind::SHARED : MemSpaceKind::LOCAL);
if (table->Capacity() > 0) {
@ -224,6 +231,13 @@ bool LinkedHashSet::Has(const JSThread *thread, JSTaggedValue key) const
JSHandle<LinkedHashSet> LinkedHashSet::Clear(const JSThread *thread, const JSHandle<LinkedHashSet> &table)
{
if (table->Capacity() == LinkedHashSet::MIN_CAPACITY) {
table->FillRangeWithSpecialValue(JSTaggedValue::Hole(), LinkedHashSet::ELEMENTS_START_INDEX,
table->GetLength());
table->SetNumberOfDeletedElements(thread, table->NumberOfDeletedElements() + table->NumberOfElements());
table->SetNumberOfElements(thread, 0);
return table;
}
JSHandle<LinkedHashSet> newSet = LinkedHashSet::Create(thread, LinkedHashSet::MIN_CAPACITY,
table.GetTaggedValue().IsInSharedHeap() ? MemSpaceKind::SHARED : MemSpaceKind::LOCAL);
if (table->Capacity() > 0) {

View File

@ -63,6 +63,11 @@ public:
static JSHandle<Derived> Shrink(const JSThread *thread, const JSHandle<Derived> &table, int additionalCapacity = 0);
static int GetLengthOfTable(int numberOfElements)
{
return ELEMENTS_START_INDEX + numberOfElements + numberOfElements * (HashObject::ENTRY_SIZE + 1);
}
inline bool HasSufficientCapacity(int numOfAddElements) const
{
int numberOfElements = NumberOfElements();

View File

@ -141,10 +141,15 @@ inline bool TaggedArray::HasDuplicateEntry() const
void TaggedArray::InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength)
{
ASSERT(initValue.IsSpecial());
SetLength(length);
SetExtraLength(extraLength);
for (uint32_t i = 0; i < length; i++) {
FillRangeWithSpecialValue(initValue, 0, length);
}
void TaggedArray::FillRangeWithSpecialValue(JSTaggedValue initValue, uint32_t start, uint32_t end)
{
ASSERT(initValue.IsSpecial());
for (uint32_t i = start; i < end; i++) {
size_t offset = JSTaggedValue::TaggedTypeSize() * i;
Barriers::SetPrimitive<JSTaggedType>(GetData(), offset, initValue.GetRawData());
}

View File

@ -80,6 +80,7 @@ public:
JSHandle<TaggedArray> &dstElements, uint32_t effectiveLength);
inline void InitializeWithSpecialValue(JSTaggedValue initValue, uint32_t length, uint32_t extraLength = 0);
inline void FillRangeWithSpecialValue(JSTaggedValue initValue, uint32_t start, uint32_t end);
static inline bool ShouldTrim(uint32_t oldLength, uint32_t newLength)
{

View File

@ -225,3 +225,66 @@ try {
} catch (error) {
print("Caught an error: " + error);
}
// Map.clear tests
map = new Map();
map.set(1, null);
map.set(2, null);
map.set(3, null);
let beginNotTought = map.entries();
let midNotTought = map.entries();
midNotTought.next();
let begin = map.entries(); // points to (1, null)
let mid = map.entries(); // points to (2, null)
mid.next();
let last = map.entries(); // points to (3, null)
last.next();
last.next();
let end = map.entries(); // points to the end
while (end.next().done) {
}
map.clear();
if (map.size != 0) {
throw new Error("Map size must be 0");
}
if (!begin.next().done) {
throw new Error("Invalid 'begin' iterator");
}
if (!mid.next().done) {
throw new Error("Invalid 'mid' iterator");
}
if (!last.next().done) {
throw new Error("Invalid 'last' iterator");
}
if (!end.next().done) {
throw new Error("Invalid 'end' iterator");
}
map.set(-1, null);
map.set(-2, null);
map.set(-3, null);
let v = beginNotTought.next();
if (v.done) {
throw new Error("Invalid 'beginNotTought' iterator");
}
if (v.value[0] != -1) {
throw new Error("Invalid 'beginNotTought' iterator's value");
}
v = midNotTought.next();
if (v.done) {
throw new Error("Invalid 'midNotTought' iterator");
}
if (v.value[0] != -1) {
throw new Error("Invalid 'midNotTought' iterator's value");
}
if (!begin.next().done) {
throw new Error("Invalid 'begin' iterator");
}
if (!mid.next().done) {
throw new Error("Invalid 'mid' iterator");
}
if (!last.next().done) {
throw new Error("Invalid 'last' iterator");
}
if (!end.next().done) {
throw new Error("Invalid 'end' iterator");
}