add unittest case for transitions dictionary

Signed-off-by: zhaozhibo <zhaozhibo3@huawei.com>
This commit is contained in:
zhaozhibo 2022-08-17 17:59:35 +08:00
parent 385ec6fee8
commit a1e5795fbd
4 changed files with 292 additions and 2 deletions

View File

@ -187,7 +187,7 @@ public:
value_ = value_ & (~TAG_WEAK);
}
inline JSTaggedValue CreateAndGetWeakRef()
inline JSTaggedValue CreateAndGetWeakRef() const
{
ASSERT_PRINT(IsHeapObject() && ((value_ & TAG_WEAK) == 0U),
"The least significant two bits of JSTaggedValue are not zero.");

View File

@ -151,6 +151,7 @@ host_unittest_action("EcmaVm_003_Test") {
"tagged_value_test.cpp",
"template_map_test.cpp",
"template_string_test.cpp",
"transitions_dictionary_test.cpp",
"weak_ref_old_gc_test.cpp",
"weak_ref_semi_gc_test.cpp",
"weak_vector_test.cpp",

View File

@ -0,0 +1,289 @@
/*
* Copyright (c) 2022 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/ecma_vm.h"
#include "ecmascript/js_symbol.h"
#include "ecmascript/object_factory.h"
#include "ecmascript/property_attributes.h"
#include "ecmascript/tagged_hash_table.h"
#include "ecmascript/tests/test_helper.h"
#include "ecmascript/transitions_dictionary.h"
using namespace panda::ecmascript;
namespace panda::test {
class TransitionsDictionaryTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
};
HWTEST_F_L0(TransitionsDictionaryTest, IsMatch)
{
JSHandle<JSTaggedValue> key(thread, JSTaggedValue::True());
JSHandle<JSTaggedValue> otherKey(thread, JSTaggedValue::False());
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
JSHandle<JSTaggedValue> otherDetails(thread, JSTaggedValue::Null());
bool result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(),
otherKey.GetTaggedValue(), otherDetails.GetTaggedValue());
EXPECT_FALSE(result);
result = TransitionsDictionary::IsMatch(key.GetTaggedValue(), metaData.GetTaggedValue(),
key.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_TRUE(result);
}
HWTEST_F_L0(TransitionsDictionaryTest, Hash)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
// test when key is string.
JSHandle<JSTaggedValue> key1(factory->NewFromStdString("k"));
JSHandle<JSTaggedValue> metaData1(thread, JSTaggedValue(1)); // test metaData : 1
int hash = TransitionsDictionary::Hash(key1.GetTaggedValue(), metaData1.GetTaggedValue());
// "k" : 107, hashSeed : 0, shift : 5, metaData : 1
EXPECT_EQ(hash, 108); // 108 : (0 << 5) - 0 + 107 + 1
JSHandle<JSTaggedValue> key2(factory->NewFromStdString("key"));
hash = TransitionsDictionary::Hash(key2.GetTaggedValue(), metaData1.GetTaggedValue());
EXPECT_EQ(hash, 106080);
// test when key is symbol.
JSHandle<JSTaggedValue> symbolName(factory->NewFromStdString("s"));
JSHandle<JSSymbol> privateNameSymbol = factory->NewPrivateNameSymbol(symbolName);
JSHandle<JSTaggedValue> symbolValue = JSHandle<JSTaggedValue>::Cast(privateNameSymbol);
JSHandle<JSTaggedValue> metaData2(thread, JSTaggedValue(2)); // test metaData : 2
hash = TransitionsDictionary::Hash(symbolValue.GetTaggedValue(), metaData2.GetTaggedValue());
EXPECT_EQ(hash, 117); // 117 : 115 + 2
}
HWTEST_F_L0(TransitionsDictionaryTest, GetKeyIndex)
{
int entry = 10;
EXPECT_EQ(TransitionsDictionary::GetKeyIndex(entry), 33); // 33 : 3 + 10 * 3 + 0
}
HWTEST_F_L0(TransitionsDictionaryTest, GetValueIndex)
{
int entry = 10;
EXPECT_EQ(TransitionsDictionary::GetValueIndex(entry), 34); // 34 : 3 + 10 * 3 + 1
}
HWTEST_F_L0(TransitionsDictionaryTest, GetEntryIndex)
{
int entry = 10;
EXPECT_EQ(TransitionsDictionary::GetEntryIndex(entry), 33); // 33 : 3 + 10 * 3
}
HWTEST_F_L0(TransitionsDictionaryTest, Create)
{
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
EXPECT_EQ(transDic->GetLength(), 27U); // 27 : 3 + 8 * 3
EXPECT_EQ(transDic->EntriesCount(), 0);
EXPECT_EQ(transDic->HoleEntriesCount(), 0);
}
HWTEST_F_L0(TransitionsDictionaryTest, Shrink)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 64;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3
EXPECT_EQ(transDic->EntriesCount(), 0);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
int eleNum = 7;
for (int index = 0; index < eleNum; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
}
JSHandle<TransitionsDictionary> transDicAfterShink = TransitionsDictionary::Shrink(thread, transDic);
EXPECT_EQ(transDicAfterShink->GetLength(), 51U); // (1 << (32 - Clz((7 + (7 >> 1)) - 1))) * 3 + 3
EXPECT_EQ(transDic->EntriesCount(), eleNum);
}
HWTEST_F_L0(TransitionsDictionaryTest, Get_Set_Attributes)
{
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
uint32_t length = transDic->GetLength();
EXPECT_EQ(length, 27U); // 27 : 3 + 8 * 3
for (int index = 0; index < numberOfElements; index++) {
transDic->SetAttributes(thread, index, JSTaggedValue(index));
JSTaggedValue value = transDic->GetAttributes(index);
EXPECT_EQ(value, JSTaggedValue(index));
}
}
HWTEST_F_L0(TransitionsDictionaryTest, SetEntry)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < numberOfElements; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic->SetEntry(thread, index, key.GetTaggedValue(), value.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_EQ(transDic->GetKey(index), key.GetTaggedValue());
}
}
HWTEST_F_L0(TransitionsDictionaryTest, FindEntry)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < numberOfElements; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_EQ(index + 3, foundEntry); // 3 : table header size
}
}
HWTEST_F_L0(TransitionsDictionaryTest, RemoveElement)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < numberOfElements; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
}
JSHandle<JSTaggedValue> key7(factory->NewFromStdString("key7")); // test remove element by "key7"
int foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_EQ(foundEntry, 7 + 3);
EXPECT_EQ(transDic->EntriesCount(), 8);
transDic->RemoveElement(thread, foundEntry);
foundEntry = transDic->FindEntry(key7.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_EQ(foundEntry, -1); // -1 : not found entry
EXPECT_EQ(transDic->EntriesCount(), 7);
}
HWTEST_F_L0(TransitionsDictionaryTest, PutIfAbsent)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 8;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < numberOfElements; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
int foundEntry = transDic->FindEntry(key.GetTaggedValue(), metaData.GetTaggedValue());
EXPECT_EQ(foundEntry, index + 3);
JSHandle<JSTaggedValue> foundValue(thread, transDic->GetValue(foundEntry));
JSHandle<JSTaggedValue> weakValue(thread, value->CreateAndGetWeakRef());
vm->SetEnableForceGC(false);
EXPECT_EQ(foundValue.GetTaggedValue(), weakValue.GetTaggedValue());
}
}
HWTEST_F_L0(TransitionsDictionaryTest, Remove)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 64;
int eleNum = 7;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < eleNum; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
}
JSHandle<JSTaggedValue> key6(factory->NewFromStdString("key6")); // test remove element by "key6"
EXPECT_EQ(transDic->EntriesCount(), 7);
EXPECT_EQ(transDic->GetLength(), 195U); // 195 : 3 + 64 * 3
transDic = TransitionsDictionary::Remove(thread, transDic, key6, metaData.GetTaggedValue());
EXPECT_EQ(transDic->EntriesCount(), 6); // 6 : 7 - 1
EXPECT_EQ(transDic->GetLength(), 51U); // (1 << (32 - Clz((6 + (6 >> 1)) - 1))) * 3 + 3
}
HWTEST_F_L0(TransitionsDictionaryTest, Rehash)
{
auto vm = thread->GetEcmaVM();
auto factory = vm->GetFactory();
int numberOfElements = 64;
int eleNum = 7;
JSHandle<TransitionsDictionary> transDic = TransitionsDictionary::Create(thread, numberOfElements);
JSHandle<JSTaggedValue> metaData(thread, JSTaggedValue::Undefined());
for (int index = 0; index < eleNum; index++) {
std::string keyStr = "key" + std::to_string(index);
std::string valueStr = "value" + std::to_string(index);
JSHandle<JSTaggedValue> key(factory->NewFromStdString(keyStr));
JSHandle<JSTaggedValue> value(factory->NewFromStdString(valueStr));
transDic = TransitionsDictionary::PutIfAbsent(thread, transDic, key, value, metaData);
}
EXPECT_EQ(transDic->HoleEntriesCount(), 0);
int lastEntry = 7 + 3;
transDic->RemoveElement(thread, lastEntry); // remove one element
EXPECT_EQ(transDic->HoleEntriesCount(), 1);
transDic->Rehash(thread, *transDic);
EXPECT_EQ(transDic->HoleEntriesCount(), 0);
}
} // namespace panda::test

View File

@ -103,7 +103,7 @@ public:
HashTableT::Set(thread, index, metaData);
}
inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, JSTaggedValue &value,
inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
const JSTaggedValue &metaData)
{
SetKey(thread, entry, key);