/* * Copyright (c) 2021-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 #include "libpandabase/utils/utf.h" #include "libpandafile/class_data_accessor-inl.h" #include "ecmascript/builtins/builtins_arraybuffer.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_set.h" #include "ecmascript/js_thread.h" #include "ecmascript/js_typed_array.h" #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/object_factory.h" #include "ecmascript/tests/test_helper.h" #include "ecmascript/serializer/value_serializer.h" #include "ecmascript/serializer/base_deserializer.h" using namespace panda::ecmascript; using namespace testing::ext; using namespace panda::ecmascript::builtins; namespace panda::test { using DeserializeFunc = void (*)(SerializeData* data); using Clock = std::chrono::high_resolution_clock; using Duration = std::chrono::duration; constexpr int32_t INITIALIZE_SIZE = 100; class JSDeserializerTest { public: JSDeserializerTest() : ecmaVm(nullptr), scope(nullptr), thread(nullptr) {} void Init() { JSRuntimeOptions options; options.SetEnableForceGC(true); ecmaVm = JSNApi::CreateEcmaVM(options); ecmaVm->SetEnableForceGC(true); EXPECT_TRUE(ecmaVm != nullptr) << "Cannot create Runtime"; thread = ecmaVm->GetJSThread(); scope = new EcmaHandleScope(thread); thread->ManagedCodeBegin(); } void Destroy() { thread->ManagedCodeEnd(); delete scope; scope = nullptr; ecmaVm->SetEnableForceGC(false); thread->ClearException(); JSNApi::DestroyJSVM(ecmaVm); } void JSSpecialValueTest(SerializeData* data) { Init(); JSHandle jsTrue(thread, JSTaggedValue::True()); JSHandle jsFalse(thread, JSTaggedValue::False()); JSHandle jsUndefined(thread, JSTaggedValue::Undefined()); JSHandle jsNull(thread, JSTaggedValue::Null()); JSHandle jsHole(thread, JSTaggedValue::Hole()); BaseDeserializer deserializer(thread, data); JSHandle retTrue = deserializer.ReadValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsTrue, retTrue)) << "Not same value for JS_TRUE"; JSHandle retFalse = deserializer.ReadValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsFalse, retFalse)) << "Not same value for JS_FALSE"; JSHandle retUndefined = deserializer.ReadValue(); JSHandle retNull = deserializer.ReadValue(); JSHandle retHole = deserializer.ReadValue(); EXPECT_TRUE(JSTaggedValue::SameValue(jsUndefined, retUndefined)) << "Not same value for JS_UNDEFINED"; EXPECT_TRUE(JSTaggedValue::SameValue(jsNull, retNull)) << "Not same value for JS_NULL"; EXPECT_TRUE(JSTaggedValue::SameValue(jsHole, retHole)) << "Not same value for JS_HOLE"; Destroy(); } void LineStringTest(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(res.IsEmpty()); EXPECT_TRUE(res->IsLineString()); Destroy(); } void TreeStringTest(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(res.IsEmpty()); EXPECT_TRUE(res->IsTreeString()); Destroy(); } void SlicedStringTest(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(res.IsEmpty()); EXPECT_TRUE(res->IsSlicedString()); Destroy(); } void JSPlainObjectTest1(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 4U); // 4 : test case double sum = 0.0; for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue()->GetNumber(); sum += a; } EXPECT_EQ(sum, 10); // 10 : test case Destroy(); } void JSPlainObjectTest2(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 10U); for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->GetTaggedObject()->GetClass()->IsJSObject()); } Destroy(); } void JSPlainObjectTest3(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); EXPECT_TRUE(retObj->GetClass()->IsDictionaryMode()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 1030U); for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->IsInt()); } Destroy(); } void JSPlainObjectTest4(SerializeData* data) { Init(); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle key(factory->NewFromASCII("str1")); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->IsTaggedArray()); TaggedArray *array = reinterpret_cast(value->GetTaggedObject()); size_t length = array->GetLength(); EXPECT_EQ(length, 102400U); // 102400: array length for (uint32_t i = 0; i < length; i++) { EXPECT_TRUE(array->Get(i).IsHole()); } Destroy(); } void JSErrorTest1(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_FALSE(objValue.IsEmpty()); EXPECT_TRUE(objValue->IsJSError()); Destroy(); } void JSErrorTest2(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 2U); for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->IsJSError()); } Destroy(); } void JSErrorTest3(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 7U); // 7 : test case for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->IsJSError()); } Destroy(); } void BigIntTest(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retObj = JSHandle::Cast(objValue); EXPECT_FALSE(retObj.IsEmpty()); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 2U); for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->GetTaggedObject()->GetClass()->IsBigInt()); } Destroy(); } void NativeBindingObjectTest1(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(objValue->IsUndefined()); Destroy(); } void NativeBindingObjectTest2(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle objValue = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(objValue->IsJSObject()); JSHandle retObj = JSHandle::Cast(objValue); JSHandle array = JSObject::GetOwnPropertyKeys(thread, retObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 2U); JSHandle key(thread, array->Get(0)); JSHandle value = JSObject::GetProperty(thread, JSHandle(retObj), key).GetValue(); EXPECT_TRUE(value->IsUndefined()); Destroy(); } void JSSetTest(SerializeData* data) { Init(); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle value1(thread, JSTaggedValue(7)); // 7 : test case JSHandle value2(thread, JSTaggedValue(9)); // 9 : test case JSHandle value3(factory->NewFromASCII("x")); JSHandle value4(factory->NewFromASCII("y")); BaseDeserializer deserializer(thread, data); JSHandle setValue = deserializer.ReadValue(); EXPECT_TRUE(!setValue.IsEmpty()); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retSet = JSHandle::Cast(setValue); JSHandle array = JSObject::GetOwnPropertyKeys(thread, JSHandle::Cast(retSet)); uint32_t propertyLength = array->GetLength(); EXPECT_EQ(propertyLength, 2U); // 2 : test case int sum = 0; for (uint32_t i = 0; i < propertyLength; i++) { JSHandle key(thread, array->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retSet), key).GetValue()->GetNumber(); sum += a; } EXPECT_EQ(sum, 16); // 16 : test case EXPECT_EQ(retSet->GetSize(), 4); // 4 : test case EXPECT_TRUE(retSet->Has(thread, value1.GetTaggedValue())); EXPECT_TRUE(retSet->Has(thread, value2.GetTaggedValue())); EXPECT_TRUE(retSet->Has(thread, value3.GetTaggedValue())); EXPECT_TRUE(retSet->Has(thread, value4.GetTaggedValue())); Destroy(); } void JSArrayTest(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle arrayValue = deserializer.ReadValue(); EXPECT_TRUE(!arrayValue.IsEmpty()); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle retArray = JSHandle::Cast(arrayValue); JSHandle keyArray = JSObject::GetOwnPropertyKeys(thread, JSHandle(retArray)); uint32_t propertyLength = keyArray->GetLength(); EXPECT_EQ(propertyLength, 23U); // 23 : test case int sum = 0; for (uint32_t i = 0; i < propertyLength; i++) { JSHandle key(thread, keyArray->Get(i)); double a = JSObject::GetProperty(thread, JSHandle(retArray), key).GetValue()->GetNumber(); sum += a; } EXPECT_EQ(sum, 226); // 226 : test case // test get value from array for (int i = 0; i < 20; i++) { // 20 : test case JSHandle value = JSArray::FastGetPropertyByValue(thread, arrayValue, i); EXPECT_EQ(i, value.GetTaggedValue().GetInt()); } Destroy(); } void EcmaStringTest1(SerializeData* data) { Init(); const char *rawStr = "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "ssssss"; JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromASCII(rawStr); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize ecmaString fail"; EXPECT_TRUE(res->IsString()) << "[NotString] Deserialize ecmaString fail"; ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle resEcmaString = JSHandle::Cast(res); auto ecmaStringCode = EcmaStringAccessor(ecmaString).GetHashcode(); auto resEcmaStringCode = EcmaStringAccessor(resEcmaString).GetHashcode(); EXPECT_TRUE(ecmaStringCode == resEcmaStringCode) << "Not same HashCode"; EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*ecmaString, *resEcmaString)) << "Not same EcmaString"; Destroy(); } void EcmaStringTest2(SerializeData* data) { Init(); JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromStdString("你好,世界"); JSHandle ecmaString1 = thread->GetEcmaVM()->GetFactory()->NewFromStdString("你好,世界"); auto ecmaStringCode1 = EcmaStringAccessor(ecmaString).GetHashcode(); auto ecmaString1Code = EcmaStringAccessor(ecmaString1).GetHashcode(); EXPECT_TRUE(ecmaStringCode1 == ecmaString1Code) << "Not same HashCode"; EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*ecmaString, *ecmaString1)) << "Not same EcmaString"; BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize ecmaString fail"; EXPECT_TRUE(res->IsString()) << "[NotString] Deserialize ecmaString fail"; ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); JSHandle resEcmaString = JSHandle::Cast(res); auto ecmaStringCode2 = EcmaStringAccessor(ecmaString).GetHashcode(); auto resEcmaStringCode = EcmaStringAccessor(resEcmaString).GetHashcode(); EXPECT_TRUE(ecmaStringCode2 == resEcmaStringCode) << "Not same HashCode"; EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*ecmaString, *resEcmaString)) << "Not same EcmaString"; Destroy(); } void Int32Test(SerializeData* data) { Init(); int32_t a = 64; int32_t min = -2147483648; int32_t b = -63; BaseDeserializer deserializer(thread, data); JSHandle resA = deserializer.ReadValue(); JSHandle resMin = deserializer.ReadValue(); JSHandle resB = deserializer.ReadValue(); EXPECT_TRUE(!resA.IsEmpty() && !resMin.IsEmpty() && !resB.IsEmpty()) << "[Empty] Deserialize Int32 fail"; EXPECT_TRUE(resA->IsInt() && resMin->IsInt() && resB->IsInt()) << "[NotInt] Deserialize Int32 fail"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resA) == a) << "Not Same Value"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resMin) == min) << "Not Same Value"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resB) == b) << "Not Same Value"; Destroy(); } void DoubleTest(SerializeData* data) { Init(); double a = 3.1415926535; double b = -3.1415926535; BaseDeserializer deserializer(thread, data); JSHandle resA = deserializer.ReadValue(); JSHandle resB = deserializer.ReadValue(); EXPECT_TRUE(!resA.IsEmpty() && !resB.IsEmpty()) << "[Empty] Deserialize double fail"; EXPECT_TRUE(resA->IsDouble() && resB->IsDouble()) << "[NotInt] Deserialize double fail"; EXPECT_TRUE(resA->GetDouble() == a) << "Not Same Value"; EXPECT_TRUE(resB->GetDouble() == b) << "Not Same Value"; Destroy(); } void JSDateTest(SerializeData* data) { Init(); double tm = 28 * 60 * 60 * 1000; // 28 * 60 * 60 * 1000 : test case BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSDate fail"; EXPECT_TRUE(res->IsDate()) << "[NotJSDate] Deserialize JSDate fail"; JSHandle resDate = JSHandle(res); EXPECT_TRUE(resDate->GetTimeValue() == JSTaggedValue(tm)) << "Not Same Time Value"; Destroy(); } void JSMapTest(SerializeData* data, const JSHandle &originMap) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSMap fail"; EXPECT_TRUE(res->IsJSMap()) << "[NotJSMap] Deserialize JSMap fail"; JSHandle resMap = JSHandle::Cast(res); EXPECT_TRUE(originMap->GetSize() == resMap->GetSize()) << "the map size Not equal"; uint32_t resSize = static_cast(resMap->GetSize()); for (uint32_t i = 0; i < resSize; i++) { JSHandle resKey(thread, resMap->GetKey(i)); JSHandle resValue(thread, resMap->GetValue(i)); JSHandle key(thread, originMap->GetKey(i)); JSHandle value(thread, originMap->GetValue(i)); JSHandle resKeyStr = JSHandle::Cast(resKey); JSHandle keyStr = JSHandle::Cast(key); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*resKeyStr, *keyStr)) << "Not same map key"; EXPECT_TRUE(JSTaggedValue::ToInt32(thread, resValue) == JSTaggedValue::ToInt32(thread, value)) << "Not same map value"; } Destroy(); } void JSSharedArrayBufferTest(SerializeData *data, int32_t byteLength, const char *msg) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSArrayBuffer fail"; EXPECT_TRUE(res->IsSharedArrayBuffer()) << "[NotJSArrayBuffer] Deserialize JSArrayBuffer fail"; JSHandle resJSArrayBuffer = JSHandle::Cast(res); int32_t resByteLength = static_cast(resJSArrayBuffer->GetArrayBufferByteLength()); EXPECT_TRUE(resByteLength == byteLength) << "Not Same ByteLength"; JSHandle resBufferData(thread, resJSArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); ASSERT_NE(resBuffer, nullptr); if (msg != nullptr) { if (memcpy_s(resBuffer, byteLength, msg, byteLength) != EOK) { EXPECT_TRUE(false) << " memcpy error!"; } } Destroy(); } void SerializeMultiSharedRegionTest(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()); EXPECT_TRUE(res->IsJSObject()); JSTaggedValue elements = JSHandle(res)->GetElements(); EXPECT_TRUE(elements.IsTaggedArray()); EXPECT_EQ(JSHandle(thread, elements)->GetLength(), 10 * 1024); // 10 * 1024: array length JSTaggedValue value = JSHandle(thread, elements)->Get(0); EXPECT_TRUE(value.IsTaggedArray()); uint32_t length = JSHandle(thread, value)->GetLength(); EXPECT_EQ(length, 11 * 1024); // 11 * 1024: array length Destroy(); } void JSSharedSetBasicTest1(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet failed"; EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet failed"; JSHandle jsSet = JSHandle::Cast(res); auto size = JSSharedSet::GetSize(thread, jsSet); EXPECT_TRUE(size == INITIALIZE_SIZE); JSSharedSet::Clear(thread, jsSet); Destroy(); } void JSSharedSetBasicTest2(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet failed"; EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet failed"; JSHandle jsSet = JSHandle::Cast(res); auto size = JSSharedSet::GetSize(thread, jsSet); EXPECT_TRUE(size == INITIALIZE_SIZE); for (int32_t i = 0; i < size; i++) { EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(i))); } JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE))); bool result = JSSharedSet::Delete(thread, jsSet, JSHandle(thread, JSTaggedValue(0))); EXPECT_TRUE(result) << "Delete failed"; Destroy(); } void JSSharedSetMultiThreadTest1(SerializeData *data) { EXPECT_TRUE(data != nullptr); Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedSet fail"; EXPECT_TRUE(res->IsJSSharedSet()) << "[NotJSSharedSet] Deserialize JSSharedSet fail"; JSHandle jsSet = JSHandle::Cast(res); EXPECT_TRUE(JSSharedSet::GetSize(thread, jsSet) == INITIALIZE_SIZE); for (int i = 0; i < INITIALIZE_SIZE; i++) { EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(i))); } Destroy(); } void JSSharedMapBasicTest1(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedMap failed"; EXPECT_TRUE(res->IsJSSharedMap()) << "[NotJSSharedMap] Deserialize JSSharedMap failed"; JSHandle jsMap = JSHandle::Cast(res); auto size = JSSharedMap::GetSize(thread, jsMap); EXPECT_TRUE(size == INITIALIZE_SIZE); JSSharedMap::Clear(thread, jsMap); Destroy(); } void JSSharedMapBasicTest2(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSSharedMap failed"; EXPECT_TRUE(res->IsJSSharedMap()) << "[NotJSSharedMap] Deserialize JSSharedMap failed"; JSHandle jsMap = JSHandle::Cast(res); auto size = JSSharedMap::GetSize(thread, jsMap); EXPECT_TRUE(size == INITIALIZE_SIZE); for (int32_t i = 0; i < size; i++) { EXPECT_TRUE(JSSharedMap::Has(thread, jsMap, JSTaggedValue(i))); } JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE)), JSHandle(thread, JSTaggedValue(INITIALIZE_SIZE))); bool result = JSSharedMap::Delete(thread, jsMap, JSHandle(thread, JSTaggedValue(0))); EXPECT_TRUE(result) << "Delete failed"; Destroy(); } void JSRegexpTest(SerializeData *data) { Init(); JSHandle pattern = thread->GetEcmaVM()->GetFactory()->NewFromASCII("key2"); JSHandle flags = thread->GetEcmaVM()->GetFactory()->NewFromASCII("i"); char buffer[] = "1234567"; // use char buffer to simulate byteCodeBuffer uint32_t bufferSize = 7; BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize JSRegExp fail"; EXPECT_TRUE(res->IsJSRegExp()) << "[NotJSRegexp] Deserialize JSRegExp fail"; JSHandle resJSRegexp(res); uint32_t resBufferSize = resJSRegexp->GetLength(); EXPECT_TRUE(resBufferSize == bufferSize) << "Not Same Length"; JSHandle originalSource(thread, resJSRegexp->GetOriginalSource()); EXPECT_TRUE(originalSource->IsString()); JSHandle originalFlags(thread, resJSRegexp->GetOriginalFlags()); EXPECT_TRUE(originalFlags->IsString()); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle(originalSource), *pattern)); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle(originalFlags), *flags)); JSHandle resBufferData(thread, resJSRegexp->GetByteCodeBuffer()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); ASSERT_NE(resBuffer, nullptr); for (uint32_t i = 0; i < resBufferSize; i++) { EXPECT_TRUE(static_cast(resBuffer)[i] == buffer[i]) << "Not Same ByteCode"; } Destroy(); } void TypedArrayTest1(SerializeData *data) { Init(); JSHandle originTypedArrayName(thread, thread->GlobalConstants()->GetInt8ArrayString()); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TypedArray fail"; EXPECT_TRUE(res->IsJSInt8Array()) << "[NotJSInt8Array] Deserialize TypedArray fail"; JSHandle resJSInt8Array = JSHandle::Cast(res); JSHandle typedArrayName(thread, resJSInt8Array->GetTypedArrayName()); uint32_t byteLength = resJSInt8Array->GetByteLength(); uint32_t byteOffset = resJSInt8Array->GetByteOffset(); uint32_t arrayLength = resJSInt8Array->GetArrayLength(); ContentType contentType = resJSInt8Array->GetContentType(); JSHandle viewedArrayBuffer(thread, resJSInt8Array->GetViewedArrayBufferOrByteArray()); EXPECT_TRUE(typedArrayName->IsString()); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle(typedArrayName), *JSHandle(originTypedArrayName))); EXPECT_EQ(byteLength, 10) << "Not Same ByteLength"; // 10: bufferLength EXPECT_EQ(byteOffset, 0) << "Not Same ByteOffset"; EXPECT_EQ(arrayLength, 10) << "Not Same ArrayLength"; // 10: arrayLength EXPECT_TRUE(contentType == ContentType::Number) << "Not Same ContentType"; // check arrayBuffer EXPECT_TRUE(viewedArrayBuffer->IsArrayBuffer()); JSHandle resJSArrayBuffer(viewedArrayBuffer); uint32_t resTaggedLength = resJSArrayBuffer->GetArrayBufferByteLength(); EXPECT_EQ(resTaggedLength, 10) << "Not same viewedBuffer length"; // 10: bufferLength JSHandle resBufferData(thread, resJSArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(resBufferData); void *resBuffer = resNp->GetExternalPointer(); for (uint32_t i = 0; i < resTaggedLength; i++) { EXPECT_EQ(static_cast(resBuffer)[i], i) << "Not same viewedBuffer"; } Destroy(); } void TypedArrayTest2(SerializeData *data) { Init(); JSHandle originTypedArrayName(thread, thread->GlobalConstants()->GetInt8ArrayString()); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TypedArray fail"; EXPECT_TRUE(res->IsJSInt8Array()) << "[NotJSInt8Array] Deserialize TypedArray fail"; JSHandle resJSInt8Array = JSHandle::Cast(res); JSHandle typedArrayName(thread, resJSInt8Array->GetTypedArrayName()); uint32_t byteLength = resJSInt8Array->GetByteLength(); uint32_t byteOffset = resJSInt8Array->GetByteOffset(); uint32_t arrayLength = resJSInt8Array->GetArrayLength(); ContentType contentType = resJSInt8Array->GetContentType(); JSHandle byteArray(thread, resJSInt8Array->GetViewedArrayBufferOrByteArray()); EXPECT_TRUE(typedArrayName->IsString()); EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle(typedArrayName), *JSHandle(originTypedArrayName))); EXPECT_EQ(byteLength, 10) << "Not Same ByteLength"; // 10: bufferLength EXPECT_EQ(byteOffset, 0) << "Not Same ByteOffset"; EXPECT_EQ(arrayLength, 10) << "Not Same ArrayLength"; // 10: arrayLength EXPECT_TRUE(contentType == ContentType::Number) << "Not Same ContentType"; // check byteArray EXPECT_TRUE(byteArray->IsByteArray()); JSHandle resByteArray(byteArray); uint32_t resTaggedLength = resByteArray->GetArrayLength(); EXPECT_EQ(resTaggedLength, 10) << "Not same viewedBuffer length"; // 10: bufferLength uint32_t resElementSize = resByteArray->GetByteLength(); EXPECT_EQ(resElementSize, 1) << "Not same byteArray size"; for (uint32_t i = 0; i < resTaggedLength; i++) { JSHandle taggedVal(thread, resByteArray->Get(thread, i, DataViewType::UINT8)); int32_t byteArrayVal = JSTaggedValue::ToInt32(thread, taggedVal); EXPECT_EQ(byteArrayVal, 255) << "Not same byteArray value"; // 255: value in byteArray } Destroy(); } void SharedObjectTest4(SerializeData* data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_FALSE(res.IsEmpty()); EXPECT_TRUE(res->IsJSSharedObject()) << "[NotJSSharedObject] Deserialize SharedObject fail"; JSHandle sObj = JSHandle::Cast(res); JSHandle array = JSObject::GetOwnPropertyKeys(thread, sObj); uint32_t length = array->GetLength(); EXPECT_EQ(length, 512U); for (uint32_t i = 0; i < length; i++) { JSHandle key(thread, array->Get(i)); JSHandle value = JSObject::GetProperty(thread, JSHandle(sObj), key).GetValue(); EXPECT_TRUE(value->IsInt()); } Destroy(); } void SerializeSharedFunctionTest(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize SharedFunction fail"; EXPECT_TRUE(res->IsJSSharedFunction()) << "[NotJSSharedFunction] Deserialize SharedFunction fail"; JSHandle sFunc = JSHandle::Cast(res); EXPECT_TRUE(sFunc->IsCallable()); EXPECT_FALSE(sFunc->GetProtoOrHClass().IsHole()); EXPECT_TRUE(sFunc->GetLexicalEnv().IsTaggedArray()); EXPECT_TRUE(sFunc->GetHomeObject().IsJSSharedObject()); JSHandle sObj(thread, sFunc->GetHomeObject()); Destroy(); } void SerializeSharedFunctionTest1(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize SharedFunction fail"; EXPECT_TRUE(res->IsJSSharedFunction()) << "[NotJSSharedFunction] Deserialize SharedFunction fail"; Destroy(); } void ObjectWithConcurrentFunctionTest(SerializeData* data) { Init(); ObjectFactory *factory = ecmaVm->GetFactory(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize ObjectWithConcurrentFunction fail"; JSHandle key1(factory->NewFromASCII("abc")); OperationResult result1 = JSObject::GetProperty(thread, res, key1); JSHandle value1 = result1.GetRawValue(); EXPECT_TRUE(value1->IsString()); JSHandle key2(factory->NewFromASCII("2")); OperationResult result2 = JSObject::GetProperty(thread, res, key2); JSHandle value2 = result2.GetRawValue(); EXPECT_TRUE(value2->IsJSFunction()); EXPECT_TRUE(JSHandle::Cast(value2)->GetWorkNodePointer() == reinterpret_cast(nullptr)); JSHandle key3(factory->NewFromASCII("key")); OperationResult result3 = JSObject::GetProperty(thread, res, key3); JSHandle value3 = result3.GetRawValue(); EXPECT_TRUE(value3->IsJSFunction()); EXPECT_TRUE(JSHandle::Cast(value3)->GetWorkNodePointer() == reinterpret_cast(nullptr)); Destroy(); } void TransferJSArrayBufferTest1(SerializeData *data, uintptr_t bufferAddrCheck) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TransferJSArrayBuffer1 fail"; EXPECT_TRUE(res->IsArrayBuffer()) << "[NotJSArrayBuffer] Deserialize TransferJSArrayBuffer1 fail"; JSHandle arrBuf = JSHandle::Cast(res); EXPECT_EQ(arrBuf->GetArrayBufferByteLength(), 5); // 5: bufferLength JSHandle nativePtr(thread, arrBuf->GetArrayBufferData()); EXPECT_TRUE(nativePtr->IsJSNativePointer()) << "[NotJSNativePointer] Deserialize TransferJSArrayBuffer1 fail"; JSHandle np = JSHandle::Cast(nativePtr); uintptr_t bufferAddr = reinterpret_cast(np->GetExternalPointer()); // The deserialized C buffer pointer shall be same to the original one EXPECT_EQ(static_cast(bufferAddr), static_cast(bufferAddrCheck)); Destroy(); } void TransferJSArrayBufferTest2(SerializeData *data, uintptr_t bufferAddrCheck) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TransferJSArrayBuffer2 fail"; EXPECT_TRUE(res->IsArrayBuffer()) << "[NotJSArrayBuffer] Deserialize TransferJSArrayBuffer2 fail"; JSHandle arrBuf = JSHandle::Cast(res); EXPECT_EQ(arrBuf->GetArrayBufferByteLength(), 5); // 5: bufferLength JSHandle nativePtr(thread, arrBuf->GetArrayBufferData()); EXPECT_TRUE(nativePtr->IsJSNativePointer()) << "[NotJSNativePointer] Deserialize TransferJSArrayBuffer2 fail"; JSHandle np = JSHandle::Cast(nativePtr); uintptr_t bufferAddr = reinterpret_cast(np->GetExternalPointer()); // The deserialized C buffer pointer shall be different to the original one EXPECT_NE(static_cast(bufferAddr), static_cast(bufferAddrCheck)); Destroy(); } void TransferJSArrayBufferTest3(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TransferJSArrayBuffer3 fail"; EXPECT_TRUE(res->IsArrayBuffer()) << "[NotJSArrayBuffer] Deserialize TransferJSArrayBuffer3 fail"; JSHandle arrBuf = JSHandle::Cast(res); EXPECT_EQ(arrBuf->GetArrayBufferByteLength(), 0); JSHandle nativePtr(thread, arrBuf->GetArrayBufferData()); EXPECT_TRUE(nativePtr->IsUndefined()) << "[NotJSNativePointer] Deserialize TransferJSArrayBuffer3 fail"; Destroy(); } void TransferJSArrayBufferTest5(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize TransferJSArrayBuffer5 fail"; EXPECT_TRUE(res->IsArrayBuffer()) << "[NotJSArrayBuffer] Deserialize TransferJSArrayBuffer5 fail"; JSHandle arrBuf = JSHandle::Cast(res); EXPECT_EQ(arrBuf->GetArrayBufferByteLength(), 5); // 5: bufferLength JSHandle nativePtr(thread, arrBuf->GetArrayBufferData()); EXPECT_TRUE(reinterpret_cast(nativePtr->GetTaggedObject())->GetDeleter()); Destroy(); } void SerializeCloneListTest1(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize CloneListTest1 fail"; Region *region = Region::ObjectAddressToRange(res->GetTaggedObject()); EXPECT_TRUE(region->InSharedHeap()); JSType resType = res->GetTaggedObject()->GetClass()->GetObjectType(); EXPECT_EQ(resType, JSType::JS_SHARED_OBJECT); ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle key(factory->NewFromASCII("str2str1")); JSHandle shareObj = JSObject::GetProperty(thread, JSHandle(res), key).GetValue(); Region *region1 = Region::ObjectAddressToRange(shareObj->GetTaggedObject()); EXPECT_TRUE(region1->InSharedHeap()); Destroy(); } void SerializeCloneListTest2(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize CloneListTest2 fail"; ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle key(factory->NewFromASCII("shareObj")); JSHandle shareObj = JSObject::GetProperty(thread, JSHandle(res), key).GetValue(); Region *region = Region::ObjectAddressToRange(shareObj->GetTaggedObject()); EXPECT_TRUE(region->InSharedHeap()); Destroy(); } void SerializeCloneListTest4(SerializeData *data) { Init(); BaseDeserializer deserializer(thread, data); JSHandle res = deserializer.ReadValue(); ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC); ecmaVm->CollectGarbage(TriggerGCType::OLD_GC); EXPECT_TRUE(!res.IsEmpty()) << "[Empty] Deserialize CloneListTest4 fail"; Destroy(); } private: EcmaVM *ecmaVm = nullptr; EcmaHandleScope *scope = nullptr; JSThread *thread = nullptr; }; class JSSerializerTest : public testing::Test { public: static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; } static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } void SetUp() override { TestHelper::CreateEcmaVMWithScope(ecmaVm, thread, scope); } void TearDown() override { TestHelper::DestroyEcmaVMWithScope(ecmaVm, scope); } JSThread *thread {nullptr}; EcmaVM *ecmaVm {nullptr}; EcmaHandleScope *scope {nullptr}; }; HWTEST_F_L0(JSSerializerTest, SerializeJSSpecialValue) { ValueSerializer *serializer = new ValueSerializer(thread); serializer->SerializeJSTaggedValue(JSTaggedValue::True()); serializer->SerializeJSTaggedValue(JSTaggedValue::False()); serializer->SerializeJSTaggedValue(JSTaggedValue::Undefined()); serializer->SerializeJSTaggedValue(JSTaggedValue::Null()); serializer->SerializeJSTaggedValue(JSTaggedValue::Hole()); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSpecialValueTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeLineString) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle str(factory->NewFromASCII("123")); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(str), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::LineStringTest, jsDeserializerTest, data.release()); { ThreadSuspensionScope suspensionScope(thread); t1.join(); } delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeTreeString) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle str1(factory->NewFromASCII("123456789")); JSHandle str2(factory->NewFromASCII("abcdefghi")); JSHandle str3 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, str1, str2)); EXPECT_TRUE(str3.GetTaggedValue().IsTreeString()); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(str3), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TreeStringTest, jsDeserializerTest, data.release()); { ThreadSuspensionScope suspensionScope(thread); t1.join(); } delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeSlicedString) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle str1(factory->NewFromASCII("123456789abcedfghijk")); JSHandle str2 = JSHandle(thread, EcmaStringAccessor::GetSubString(ecmaVm, str1, 2, 13)); // 2: start, 3: len EXPECT_TRUE(str2.GetTaggedValue().IsSlicedString()); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(str2), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SlicedStringTest, jsDeserializerTest, data.release()); { ThreadSuspensionScope suspensionScope(thread); t1.join(); } delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject1) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("2")); JSHandle key2(factory->NewFromASCII("3")); JSHandle key3(factory->NewFromASCII("x")); JSHandle key4(factory->NewFromASCII("y")); JSHandle value1(thread, JSTaggedValue(1)); JSHandle value2(thread, JSTaggedValue(2)); JSHandle value3(thread, JSTaggedValue(3)); JSHandle value4(thread, JSTaggedValue(4)); JSObject::SetProperty(thread, JSHandle(obj), key1, value1); JSObject::SetProperty(thread, JSHandle(obj), key2, value2); JSObject::SetProperty(thread, JSHandle(obj), key3, value3); JSObject::SetProperty(thread, JSHandle(obj), key4, value4); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject2) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("str1")); JSHandle key2(factory->NewFromASCII("str2")); for (int i = 0; i < 10; i++) { JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle key3(factory->NewFromASCII("str3")); for (int j = 0; j < 10; j++) { key3 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key3, key1)); JSObject::SetProperty(thread, JSHandle(obj1), JSHandle(key3), JSHandle(factory->NewEmptyJSObject())); } key2 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1)); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key2), JSHandle(obj1)); } ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; // test dictionary mode HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject3) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("str1")); JSHandle key2(factory->NewFromASCII("str2")); JSHandle value1(thread, JSTaggedValue(1)); for (int i = 0; i < 1030; i++) { key2 = JSHandle(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1)); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key2), value1); } EXPECT_TRUE(obj->GetClass()->IsDictionaryMode()); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest3, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; // test huge object serialize HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject4) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("str1")); // new huge tagged array JSHandle taggedArray = factory->NewTaggedArray(1024 * 100, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key1), JSHandle(taggedArray)); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSPlainObjectTest4, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject5) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("2")); JSHandle key2(factory->NewFromASCII("3")); JSHandle key3(factory->NewFromASCII("x")); JSHandle key4(factory->NewFromASCII("y")); JSHandle key5(factory->NewFromASCII("func")); JSHandle value1(thread, JSTaggedValue(1)); JSHandle value2(thread, JSTaggedValue(2)); JSHandle value3(thread, JSTaggedValue(3)); JSHandle value4(thread, JSTaggedValue(4)); JSHandle env = ecmaVm->GetGlobalEnv(); JSHandle function = factory->NewJSFunction(env, nullptr, FunctionKind::NORMAL_FUNCTION); EXPECT_TRUE(function->IsJSFunction()); JSHandle value5 = JSHandle::Cast(function); JSObject::SetProperty(thread, JSHandle(obj), key1, value1); JSObject::SetProperty(thread, JSHandle(obj), key2, value2); JSObject::SetProperty(thread, JSHandle(obj), key3, value3); JSObject::SetProperty(thread, JSHandle(obj), key4, value4); JSObject::SetProperty(thread, JSHandle(obj), key5, value5); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSError1) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle msg(factory->NewFromASCII("this is error")); JSHandle errorTag = JSHandle::Cast(factory->NewJSError(base::ErrorType::ERROR, msg, StackCheck::NO)); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, errorTag, JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSErrorTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSError2) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("error1")); JSHandle key2(factory->NewFromASCII("error2")); JSHandle msg(factory->NewFromASCII("this is error")); JSHandle errorTag = JSHandle::Cast(factory->NewJSError(base::ErrorType::ERROR, msg, StackCheck::NO)); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key1), errorTag); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key2), errorTag); ValueSerializer *serializer = new ValueSerializer(thread); serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSErrorTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSError3) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("error1")); JSHandle key2(factory->NewFromASCII("error2")); JSHandle key3(factory->NewFromASCII("error3")); JSHandle key4(factory->NewFromASCII("error4")); JSHandle key5(factory->NewFromASCII("error5")); JSHandle key6(factory->NewFromASCII("error6")); JSHandle key7(factory->NewFromASCII("error7")); JSHandle msg(factory->NewFromASCII("this is error")); JSHandle error1 = JSHandle::Cast(factory->NewJSError(base::ErrorType::RANGE_ERROR, msg, StackCheck::NO)); JSHandle error2 = JSHandle::Cast(factory->NewJSError(base::ErrorType::REFERENCE_ERROR, msg, StackCheck::NO)); JSHandle error3 = JSHandle::Cast(factory->NewJSError(base::ErrorType::TYPE_ERROR, msg, StackCheck::NO)); JSHandle error4 = JSHandle::Cast(factory->NewJSError(base::ErrorType::URI_ERROR, msg, StackCheck::NO)); JSHandle error5 = JSHandle::Cast(factory->NewJSError(base::ErrorType::SYNTAX_ERROR, msg, StackCheck::NO)); JSHandle error6 = JSHandle::Cast(factory->NewJSError(base::ErrorType::OOM_ERROR, msg, StackCheck::NO)); JSHandle error7 = JSHandle::Cast(factory->NewJSError(base::ErrorType::TERMINATION_ERROR, msg, StackCheck::NO)); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key1), error1); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key2), error2); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key3), error3); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key4), error4); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key5), error5); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key6), error6); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key7), error7); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSErrorTest3, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } HWTEST_F_L0(JSSerializerTest, SerializeBigInt) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle key1(factory->NewFromASCII("pss")); JSHandle key2(factory->NewFromASCII("nativeHeap")); CString value1 = "365769"; CString value2 = "139900"; JSHandle bigInt1 = BigIntHelper::SetBigInt(thread, value1); JSHandle bigInt2 = BigIntHelper::SetBigInt(thread, value1); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key1), JSHandle(bigInt1)); JSObject::SetProperty(thread, JSHandle(obj), JSHandle(key2), JSHandle(bigInt2)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize bigInt fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::BigIntTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; static void* Detach(void *param1, void *param2, void *hint, void *detachData) { GTEST_LOG_(INFO) << "detach is running"; if (param1 == nullptr && param2 == nullptr) { GTEST_LOG_(INFO) << "detach: two params is nullptr"; } if (hint == nullptr && detachData) { GTEST_LOG_(INFO) << "detach: hint is nullptr"; } return nullptr; } static void* Attach([[maybe_unused]] void *enginePointer, [[maybe_unused]] void *buffer, [[maybe_unused]] void *hint, [[maybe_unused]] void *attachData) { GTEST_LOG_(INFO) << "attach is running"; return nullptr; } static panda::JSNApi::NativeBindingInfo* CreateNativeBindingInfo(void* attach, void* detach) { GTEST_LOG_(INFO) << "CreateNativeBindingInfo"; auto info = panda::JSNApi::NativeBindingInfo::CreateNewInstance(); info->attachFunc = attach; info->detachFunc = detach; return info; } HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject1) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle env = ecmaVm->GetGlobalEnv(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle key1 = env->GetNativeBindingSymbol(); JSHandle key2(factory->NewFromASCII("x")); auto info = CreateNativeBindingInfo(reinterpret_cast(Attach), reinterpret_cast(Detach)); JSHandle value1(factory->NewJSNativePointer(reinterpret_cast(info))); JSHandle value2(thread, JSTaggedValue(1)); JSObject::SetProperty(thread, JSHandle(obj1), key1, value1); JSObject::SetProperty(thread, JSHandle(obj1), key2, value2); obj1->GetClass()->SetIsNativeBindingObject(true); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj1), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject2) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle env = ecmaVm->GetGlobalEnv(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle obj2 = factory->NewEmptyJSObject(); JSHandle key1 = env->GetNativeBindingSymbol(); JSHandle key2(factory->NewFromASCII("x")); JSHandle key3(factory->NewFromASCII("xx")); auto info = CreateNativeBindingInfo(reinterpret_cast(Attach), reinterpret_cast(Detach)); JSHandle value1(factory->NewJSNativePointer(reinterpret_cast(info))); JSHandle value2(thread, JSTaggedValue(1)); JSHandle value3(thread, JSTaggedValue(2)); JSObject::SetProperty(thread, JSHandle(obj1), key1, value1); JSObject::SetProperty(thread, JSHandle(obj1), key2, value2); obj1->GetClass()->SetIsNativeBindingObject(true); JSObject::SetProperty(thread, JSHandle(obj2), key2, JSHandle(obj1)); JSObject::SetProperty(thread, JSHandle(obj2), key3, value3); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj2), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::NativeBindingObjectTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; } HWTEST_F_L0(JSSerializerTest, SerializeNativeBindingObject3) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle env = ecmaVm->GetGlobalEnv(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle key1 = env->GetNativeBindingSymbol(); JSHandle key2(factory->NewFromASCII("x")); auto info = CreateNativeBindingInfo(reinterpret_cast(Attach), nullptr); JSHandle value1(factory->NewJSNativePointer(reinterpret_cast(info))); JSHandle value2(thread, JSTaggedValue(1)); JSObject::SetProperty(thread, JSHandle(obj1), key1, value1); JSObject::SetProperty(thread, JSHandle(obj1), key2, value2); obj1->GetClass()->SetIsNativeBindingObject(true); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj1), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; } HWTEST_F_L0(JSSerializerTest, TestSerializeJSSet) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsSetFunction(); JSHandle set = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle linkedSet = LinkedHashSet::Create(thread); set->SetLinkedSet(thread, linkedSet); // set property to set JSHandle value1(thread, JSTaggedValue(7)); JSHandle value2(thread, JSTaggedValue(9)); JSHandle value3(factory->NewFromASCII("x")); JSHandle value4(factory->NewFromASCII("y")); JSSet::Add(thread, set, value1); JSSet::Add(thread, set, value2); JSSet::Add(thread, set, value3); JSSet::Add(thread, set, value4); // set property to object JSHandle key1(factory->NewFromASCII("5")); JSHandle key2(factory->NewFromASCII("6")); JSObject::SetProperty(thread, JSHandle(set), key1, value1); JSObject::SetProperty(thread, JSHandle(set), key2, value2); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(set), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSet fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSSetTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; JSDate *JSDateCreate(EcmaVM *ecmaVM) { ObjectFactory *factory = ecmaVM->GetFactory(); JSHandle globalEnv = ecmaVM->GetGlobalEnv(); JSHandle dateFunction = globalEnv->GetDateFunction(); JSHandle dateObject = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(dateFunction), dateFunction)); return *dateObject; } HWTEST_F_L0(JSSerializerTest, SerializeDate) { double tm = 28 * 60 * 60 * 1000; JSHandle jsDate(thread, JSDateCreate(ecmaVm)); jsDate->SetTimeValue(thread, JSTaggedValue(tm)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsDate), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSDate fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSDateTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; JSMap *CreateMap(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle constructor = env->GetBuiltinsMapFunction(); JSHandle map = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); JSHandle linkedMap = LinkedHashMap::Create(thread); map->SetLinkedMap(thread, linkedMap); return *map; } HWTEST_F_L0(JSSerializerTest, SerializeJSMap) { JSHandle map(thread, CreateMap(thread)); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle key1(factory->NewFromASCII("3")); JSHandle value1(thread, JSTaggedValue(12345)); JSMap::Set(thread, map, key1, value1); JSHandle key2(factory->NewFromASCII("key1")); JSHandle value2(thread, JSTaggedValue(34567)); JSMap::Set(thread, map, key2, value2); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(map), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSMap fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSMapTest, jsDeserializerTest, data.release(), map); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSRegExp) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetRegExpFunction(); JSHandle jsRegexp = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); JSHandle pattern = thread->GetEcmaVM()->GetFactory()->NewFromASCII("key2"); JSHandle flags = thread->GetEcmaVM()->GetFactory()->NewFromASCII("i"); char buffer[] = "1234567"; // use char to simulate bytecode uint32_t bufferSize = 7; factory->NewJSRegExpByteCodeData(jsRegexp, static_cast(buffer), bufferSize); jsRegexp->SetOriginalSource(thread, JSHandle(pattern)); jsRegexp->SetOriginalFlags(thread, JSHandle(flags)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsRegexp), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSRegExp fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSRegexpTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, TestSerializeJSArray) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle array = factory->NewJSArray(); // set property to object JSHandle key1(factory->NewFromASCII("abasd")); JSHandle key2(factory->NewFromASCII("qweqwedasd")); JSHandle value1(thread, JSTaggedValue(7)); JSHandle value2(thread, JSTaggedValue(9)); JSObject::SetProperty(thread, JSHandle(array), key1, value1); JSObject::SetProperty(thread, JSHandle(array), key2, value2); // set value to array array->SetArrayLength(thread, 20); for (int i = 0; i < 20; i++) { JSHandle data(thread, JSTaggedValue(i)); JSArray::FastSetPropertyByValue(thread, JSHandle::Cast(array), i, data); } ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(array), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSArray fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::JSArrayTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeEcmaString1) { const char *rawStr = "ssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss"\ "ssssss"; JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromASCII(rawStr); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(ecmaString), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize EcmaString fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; // Test EcmaString contains Chinese Text HWTEST_F_L0(JSSerializerTest, SerializeEcmaString2) { std::string rawStr = "你好,世界"; JSHandle ecmaString = thread->GetEcmaVM()->GetFactory()->NewFromStdString(rawStr); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(ecmaString), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize EcmaString fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::EcmaStringTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeInt32_t) { int32_t a = 64, min = -2147483648, b = -63; JSTaggedValue aTag(a), minTag(min), bTag(b); ValueSerializer *serializer = new ValueSerializer(thread); serializer->SerializeJSTaggedValue(aTag); serializer->SerializeJSTaggedValue(minTag); serializer->SerializeJSTaggedValue(bTag); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::Int32Test, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeDouble) { double a = 3.1415926535, b = -3.1415926535; JSTaggedValue aTag(a), bTag(b); ValueSerializer *serializer = new ValueSerializer(thread); serializer->SerializeJSTaggedValue(aTag); serializer->SerializeJSTaggedValue(bTag); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::DoubleTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; JSArrayBuffer *CreateJSArrayBuffer(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetArrayBufferFunction(); JSHandle jsArrayBuffer = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); return *jsArrayBuffer; } HWTEST_F_L0(JSSerializerTest, SerializeObjectWithConcurrentFunction) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle concurrentFunction1 = factory->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION); EXPECT_TRUE(concurrentFunction1->IsJSFunction()); EXPECT_TRUE(concurrentFunction1->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION); JSHandle concurrentFunction2 = factory->NewJSFunction(env, nullptr, FunctionKind::CONCURRENT_FUNCTION); EXPECT_TRUE(concurrentFunction2->IsJSFunction()); EXPECT_TRUE(concurrentFunction2->GetFunctionKind() == ecmascript::FunctionKind::CONCURRENT_FUNCTION); JSHandle key1(factory->NewFromASCII("1")); JSHandle key2(factory->NewFromASCII("2")); JSHandle key3(factory->NewFromASCII("abc")); JSHandle key4(factory->NewFromASCII("4")); JSHandle key5(factory->NewFromASCII("key")); JSHandle value1(thread, JSTaggedValue(12345)); JSHandle value2(factory->NewFromASCII("def")); JSHandle value3(factory->NewFromASCII("value")); JSHandle obj = factory->NewEmptyJSObject(); JSObject::SetProperty(thread, JSHandle(obj), key1, value1); JSObject::SetProperty(thread, JSHandle(obj), key2, JSHandle(concurrentFunction1)); JSObject::SetProperty(thread, JSHandle(obj), key3, value2); JSObject::SetProperty(thread, JSHandle(obj), key4, value1); JSObject::SetProperty(thread, JSHandle(obj), key5, JSHandle(concurrentFunction2)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize concurrent function fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::ObjectWithConcurrentFunctionTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; // not support most function except concurrent function HWTEST_F_L0(JSSerializerTest, SerializeFunction) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle function = factory->NewJSFunction(env, nullptr, FunctionKind::NORMAL_FUNCTION); EXPECT_TRUE(function->IsJSFunction()); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(function), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; } // Test transfer JSArrayBuffer HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer1) { ObjectFactory *factory = ecmaVm->GetFactory(); // create a JSArrayBuffer size_t length = 5; uint8_t value = 100; void *buffer = ecmaVm->GetNativeAreaAllocator()->AllocateBuffer(length); if (memset_s(buffer, length, value, length) != EOK) { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } JSHandle arrBuf = factory->NewJSArrayBuffer(buffer, length, NativeAreaAllocator::FreeBufferFunc, ecmaVm->GetNativeAreaAllocator()); JSHandle arrBufTag = JSHandle(arrBuf); JSHandle array = factory->NewJSArray(); // set value to array array->SetArrayLength(thread, 1); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, arrBufTag); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, arrBufTag, JSHandle(array), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize transfer JSArrayBuffer fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest1, jsDeserializerTest, data.release(), reinterpret_cast(buffer)); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached EXPECT_TRUE(arrBuf->IsDetach()); }; // Test serialize JSArrayBuffer that not transfer HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer2) { ObjectFactory *factory = ecmaVm->GetFactory(); // create a JSArrayBuffer size_t length = 5; uint8_t value = 100; void *buffer = ecmaVm->GetNativeAreaAllocator()->AllocateBuffer(length); if (memset_s(buffer, length, value, length) != EOK) { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } JSHandle arrBuf = factory->NewJSArrayBuffer(buffer, length, NativeAreaAllocator::FreeBufferFunc, ecmaVm->GetNativeAreaAllocator()); JSHandle arrBufTag = JSHandle::Cast(arrBuf); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, arrBufTag, JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize not transfer JSArrayBuffer fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest2, jsDeserializerTest, data.release(), reinterpret_cast(buffer)); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached EXPECT_FALSE(arrBuf->IsDetach()); }; // Test serialize an empty JSArrayBuffer HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer3) { ObjectFactory *factory = ecmaVm->GetFactory(); // create a JSArrayBuffer JSHandle arrBuf = factory->NewJSArrayBuffer(0); JSHandle arrBufTag = JSHandle::Cast(arrBuf); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, arrBufTag, JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize empty JSArrayBuffer fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest3, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; // test if detached EXPECT_FALSE(arrBuf->IsDetach()); }; // Test serialize JSArrayBuffer with external native buffer that not transfer HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer4) { ObjectFactory *factory = ecmaVm->GetFactory(); // create a JSArrayBuffer size_t length = 5; uint8_t value = 100; void *buffer = reinterpret_cast(malloc(length)); if (memset_s(buffer, length, value, length) != EOK) { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } JSHandle arrBuf = factory->NewJSArrayBuffer(buffer, length, nullptr, nullptr); JSHandle arrBufTag = JSHandle::Cast(arrBuf); ValueSerializer *serializer = new ValueSerializer(thread); bool res = serializer->WriteValue(thread, arrBufTag, JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(res) << "serialize JSArrayBuffer with external native shall not clone it"; free(buffer); }; void ArrayBufferDeleter([[maybe_unused]] void *env, void *buf, [[maybe_unused]] void *data) { free(buf); } // Test serialize JSArrayBuffer with external native buffer that transfer HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer5) { ObjectFactory *factory = ecmaVm->GetFactory(); // create a JSArrayBuffer size_t length = 5; uint8_t value = 100; void *buffer = reinterpret_cast(malloc(length)); if (memset_s(buffer, length, value, length) != EOK) { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); } JSHandle arrBuf = factory->NewJSArrayBuffer(buffer, length, ArrayBufferDeleter, nullptr); JSHandle arrBufTag = JSHandle::Cast(arrBuf); ValueSerializer *serializer = new ValueSerializer(thread, true); bool res = serializer->WriteValue(thread, arrBufTag, JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(res) << "serialize JSArrayBuffer with external pointer fail"; EXPECT_TRUE(arrBuf->IsDetach()); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TransferJSArrayBufferTest5, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer6) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle transfer(factory->NewFromASCII("transfer")); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(transfer), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; }; HWTEST_F_L0(JSSerializerTest, TransferJSArrayBuffer7) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle transfer(factory->NewFromASCII("transfer")); JSHandle array = factory->NewJSArray(); // set value to array array->SetArrayLength(thread, 1); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(transfer)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(array), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared2) { std::string msg = "hello world"; int msgBufferLen = static_cast(msg.length()) + 1; ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsArrayBuffer = factory->NewJSSharedArrayBuffer(msgBufferLen); JSHandle BufferData(thread, jsArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(BufferData); void *buffer = resNp->GetExternalPointer(); if (memcpy_s(buffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { EXPECT_TRUE(false) << " memcpy error"; } ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsArrayBuffer), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSharedArrayBuffer fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data.release(), 12, changeStr.c_str()); ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(strcmp((char *)buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSArrayBufferShared3) { std::string msg = "hello world"; int msgBufferLen = static_cast(msg.length()) + 1; ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsArrayBuffer = factory->NewJSSharedArrayBuffer(msgBufferLen); JSHandle BufferData(thread, jsArrayBuffer->GetArrayBufferData()); JSHandle resNp = JSHandle::Cast(BufferData); void *buffer = resNp->GetExternalPointer(); if (memcpy_s(buffer, msgBufferLen, msg.c_str(), msgBufferLen) != EOK) { EXPECT_TRUE(false) << " memcpy error"; } ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsArrayBuffer), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSharedArrayBuffer fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::string changeStr = "world hello"; std::thread t1(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest, data.get(), 12, changeStr.c_str()); { ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(strcmp((char *)buffer, "world hello") == 0) << "Serialize JSArrayBuffer fail"; changeStr = "world hella"; JSDeserializerTest jsDeserializerTest1; std::thread t2(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest1, data.get(), 12, changeStr.c_str()); t2.join(); EXPECT_TRUE(strcmp((char *)buffer, "world hella") == 0) << "Serialize JSArrayBuffer fail"; changeStr = "world hellb"; JSDeserializerTest jsDeserializerTest2; std::thread t3(&JSDeserializerTest::JSSharedArrayBufferTest, jsDeserializerTest2, data.get(), 12, changeStr.c_str()); t3.join(); EXPECT_TRUE(strcmp((char *)buffer, "world hellb") == 0) << "Serialize JSArrayBuffer fail"; } delete serializer; data.reset(); EXPECT_TRUE(JSHandle(jsArrayBuffer)->IsSharedArrayBuffer()); }; HWTEST_F_L0(JSSerializerTest, SerializeJSNativePointer) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle np = factory->NewJSNativePointer(nullptr); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(np), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); // Don't support serialize JSNativePointer directly EXPECT_TRUE(!success); std::unique_ptr data = serializer->Release(); EXPECT_TRUE(data->IsIncompleteData()); delete serializer; } JSArrayBuffer *CreateTestJSArrayBuffer(JSThread *thread) { JSHandle jsArrayBuffer(thread, CreateJSArrayBuffer(thread)); int32_t byteLength = 10; thread->GetEcmaVM()->GetFactory()->NewJSArrayBufferData(jsArrayBuffer, byteLength); jsArrayBuffer->SetArrayBufferByteLength(byteLength); JSHandle obj = JSHandle(jsArrayBuffer); JSMutableHandle number(thread, JSTaggedValue::Undefined()); for (int i = 0; i < 10; i++) { // 10: arrayLength number.Update(JSTaggedValue(i)); BuiltinsArrayBuffer::SetValueInBuffer(thread, obj.GetTaggedValue(), i, DataViewType::UINT8, number, true); } return *jsArrayBuffer; } HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray1) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetInt8ArrayFunction(); JSHandle int8Array = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); JSHandle viewedArrayBuffer(thread, CreateTestJSArrayBuffer(thread)); int8Array->SetViewedArrayBufferOrByteArray(thread, viewedArrayBuffer); int byteLength = 10; int byteOffset = 0; int arrayLength = (byteLength - byteOffset) / (sizeof(int8_t)); int8Array->SetByteLength(byteLength); int8Array->SetByteOffset(byteOffset); int8Array->SetTypedArrayName(thread, thread->GlobalConstants()->GetInt8ArrayString()); int8Array->SetArrayLength(arrayLength); int8Array->SetContentType(ContentType::Number); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(int8Array), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize type array fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSTypedArray2) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle target = env->GetInt8ArrayFunction(); JSHandle int8Array = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(target), target)); uint8_t value = 255; // 255 : test case JSTaggedType val = JSTaggedValue(value).GetRawData(); int byteArrayLength = 10; // 10: arrayLength JSHandle byteArray = factory->NewByteArray(byteArrayLength, sizeof(value)); for (int i = 0; i < byteArrayLength; i++) { byteArray->Set(thread, i, DataViewType::UINT8, val); } int8Array->SetViewedArrayBufferOrByteArray(thread, byteArray); int byteLength = 10; int byteOffset = 0; int arrayLength = (byteLength - byteOffset) / (sizeof(int8_t)); int8Array->SetByteLength(byteLength); int8Array->SetByteOffset(byteOffset); int8Array->SetTypedArrayName(thread, thread->GlobalConstants()->GetInt8ArrayString()); int8Array->SetArrayLength(arrayLength); int8Array->SetContentType(ContentType::Number); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(int8Array), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize type array fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::TypedArrayTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; JSHandle CreateEmptySObject(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle nullHandle = globalConst->GetHandledNull(); JSHandle emptyLayout = factory->CreateSLayoutInfo(0); JSHandle hclass = factory->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, nullHandle, JSHandle(emptyLayout)); return factory->NewSharedOldSpaceJSObject(hclass); } JSHandle CreateSObject(JSThread *thread) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle nullHandle = globalConst->GetHandledNull(); uint32_t index = 0; PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); attributes.SetIsInlinedProps(true); attributes.SetRepresentation(Representation::TAGGED); uint32_t length = 4; JSHandle layout = factory->CreateSLayoutInfo(length); JSHandle key1(factory->NewFromASCII("str1")); JSHandle key2(factory->NewFromASCII("str2")); while (index < length) { attributes.SetOffset(index); attributes.SetIsAccessor(false); key2 = JSHandle(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), key2, key1)); auto stringTable = thread->GetEcmaVM()->GetEcmaStringTable(); stringTable->GetOrInternString(thread->GetEcmaVM(), *key2); layout->AddKey(thread, index++, key2.GetTaggedValue(), attributes); } JSHandle hclass = factory->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, nullHandle, JSHandle(layout)); JSHandle object = factory->NewSharedOldSpaceJSObject(hclass); uint32_t fieldIndex = 0; while (fieldIndex < length) { JSHandle emptyObject = CreateEmptySObject(thread); object->SetPropertyInlinedProps(thread, fieldIndex++, emptyObject.GetTaggedValue()); } return object; } JSHandle CreateSSet(JSThread *thread) { auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle proto = globalEnv->GetSharedSetPrototype(); auto emptySLayout = thread->GlobalConstants()->GetHandledEmptySLayoutInfo(); JSHandle setClass = factory->NewSEcmaHClass(JSSharedSet::SIZE, 0, JSType::JS_SHARED_SET, proto, emptySLayout); JSHandle jsSet = JSHandle::Cast(factory->NewSharedOldSpaceJSObjectWithInit(setClass)); JSHandle linkedSet( LinkedHashSet::Create(thread, LinkedHashSet::MIN_CAPACITY, MemSpaceKind::SHARED)); jsSet->SetLinkedSet(thread, linkedSet); jsSet->SetModRecord(0); return jsSet; } JSHandle CreateSMap(JSThread *thread) { auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle proto = globalEnv->GetSharedMapPrototype(); auto emptySLayout = thread->GlobalConstants()->GetHandledEmptySLayoutInfo(); JSHandle mapClass = factory->NewSEcmaHClass(JSSharedMap::SIZE, 0, JSType::JS_SHARED_MAP, proto, emptySLayout); JSHandle jsMap = JSHandle::Cast(factory->NewSharedOldSpaceJSObjectWithInit(mapClass)); JSHandle linkedMap( LinkedHashMap::Create(thread, LinkedHashSet::MIN_CAPACITY, MemSpaceKind::SHARED)); jsMap->SetLinkedMap(thread, linkedMap); jsMap->SetModRecord(0); return jsMap; } HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest1) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle shareObj = CreateSObject(thread); Region *region = Region::ObjectAddressToRange(*shareObj); EXPECT_TRUE(region->InSharedHeap()); JSHandle key(factory->NewFromASCII("str2str1")); JSHandle shareObj1 = JSObject::GetProperty(thread, JSHandle(shareObj), JSHandle(key)).GetValue(); Region *region1 = Region::ObjectAddressToRange(shareObj1->GetTaggedObject()); EXPECT_TRUE(region1->InSharedHeap()); JSHandle array = factory->NewJSArray(); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(shareObj)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(shareObj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); EXPECT_TRUE(success) << "SerializeCloneListTest1: Serialize shared obj fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SerializeCloneListTest1, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest2) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle rootObj = factory->NewEmptyJSObject(); JSHandle shareObj = CreateSObject(thread); JSHandle noShareObj = CreateSObject(thread); JSHandle key1(factory->NewFromASCII("shareObj")); JSHandle key2(factory->NewFromASCII("noShareObj")); JSObject::SetProperty(thread, JSHandle(rootObj), key1, JSHandle(shareObj)); JSObject::SetProperty(thread, JSHandle(rootObj), key2, JSHandle(noShareObj)); JSHandle array = factory->NewJSArray(); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(shareObj)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(rootObj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); EXPECT_TRUE(success) << "SerializeCloneListTest2: Serialize shared obj fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SerializeCloneListTest2, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest3) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle cloneList(factory->NewFromASCII("cloneList")); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(cloneList)); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest4) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle arrBuf = factory->NewJSArrayBuffer(0); JSHandle arrBufTag = JSHandle::Cast(arrBuf); JSHandle array = factory->NewJSArray(); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, arrBufTag); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); EXPECT_TRUE(success) << "SerializeCloneListTest4: Serialize shared obj fail"; std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SerializeCloneListTest4, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeCloneListTest5) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); JSHandle obj1 = factory->NewEmptyJSObject(); JSHandle array = factory->NewJSArray(); // set value to array array->SetArrayLength(thread, 1); JSArray::FastSetPropertyByValue(thread, JSHandle(array), 0, JSHandle(obj1)); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(obj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(array)); EXPECT_FALSE(success); std::unique_ptr data = serializer->Release(); BaseDeserializer deserializer(thread, data.release()); JSHandle res = deserializer.ReadValue(); EXPECT_TRUE(res.IsEmpty()); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSSharedSetBasic1) { JSHandle jsSet = CreateSSet(thread); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsSet), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSharedSet failed"; std::unique_ptr data = serializer->Release(); { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(i))); } JSDeserializerTest jsDeserializerTest; // The Deserializer thread will clear the shared set std::thread t1(&JSDeserializerTest::JSSharedSetBasicTest1, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(JSSharedSet::GetSize(thread, jsSet) == 0); } { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(i))); } EXPECT_TRUE(!JSSharedSet::Has(thread, jsSet, JSTaggedValue(INITIALIZE_SIZE))); JSDeserializerTest jsDeserializerTest; // The Deserializer thread will add and delete a element std::thread t1(&JSDeserializerTest::JSSharedSetBasicTest2, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(!JSSharedSet::Has(thread, jsSet, JSTaggedValue(0))); EXPECT_TRUE(JSSharedSet::Has(thread, jsSet, JSTaggedValue(INITIALIZE_SIZE))); } delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeMultiThreadJSSharedSet) { JSHandle jsSet = CreateSSet(thread); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsSet), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSharedSet fail"; std::unique_ptr data = serializer->Release(); for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedSet::Add(thread, jsSet, JSHandle(thread, JSTaggedValue(i))); } constexpr uint32_t maxNumDeserializers = 10; JSDeserializerTest jsDeserializerTests[maxNumDeserializers]; std::thread threads[maxNumDeserializers]; for (int32_t i = 0; i < maxNumDeserializers; i++) { threads[i] = std::thread(&JSDeserializerTest::JSSharedSetMultiThreadTest1, jsDeserializerTests[i], data.get()); } ThreadSuspensionScope scope(thread); for (int i = 0; i < maxNumDeserializers; i++) { threads[i].join(); } EXPECT_TRUE(jsSet->GetModRecord() == 0); delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeJSSharedMapBasic) { JSHandle jsMap = CreateSMap(thread); ValueSerializer *serializer = new ValueSerializer(thread); bool success = serializer->WriteValue(thread, JSHandle(jsMap), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success) << "Serialize JSSharedMap failed"; std::unique_ptr data = serializer->Release(); { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(i)), JSHandle(thread, JSTaggedValue(i))); } JSDeserializerTest jsDeserializerTest; // The Deserializer thread will clear the shared map std::thread t1(&JSDeserializerTest::JSSharedMapBasicTest1, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(JSSharedMap::GetSize(thread, jsMap) == 0); } { for (int i = 0; i < INITIALIZE_SIZE; i++) { JSSharedMap::Set(thread, jsMap, JSHandle(thread, JSTaggedValue(i)), JSHandle(thread, JSTaggedValue(i))); } EXPECT_TRUE(!JSSharedMap::Has(thread, jsMap, JSTaggedValue(INITIALIZE_SIZE))); JSDeserializerTest jsDeserializerTest; // The Deserializer thread will add and delete a element std::thread t1(&JSDeserializerTest::JSSharedMapBasicTest2, jsDeserializerTest, data.get()); ThreadSuspensionScope scope(thread); t1.join(); EXPECT_TRUE(!JSSharedMap::Has(thread, jsMap, JSTaggedValue(0))); EXPECT_TRUE(JSSharedMap::Has(thread, jsMap, JSTaggedValue(INITIALIZE_SIZE))); } delete serializer; }; HWTEST_F_L0(JSSerializerTest, SerializeMultiSharedRegion) { ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle array = factory->NewSTaggedArray(10 * 1024, JSTaggedValue::Hole()); // 10 * 1024: array length for (int i = 0; i < 5; i++) { JSHandle element = factory->NewSTaggedArray((11 + i) * 1024, JSTaggedValue::Hole()); array->Set(thread, i, element); } JSHandle sobj = CreateEmptySObject(thread); sobj->SetElements(thread, array); ValueSerializer *serializer = new ValueSerializer(thread, false, true); bool success = serializer->WriteValue(thread, JSHandle(sobj), JSHandle(thread, JSTaggedValue::Undefined()), JSHandle(thread, JSTaggedValue::Undefined())); EXPECT_TRUE(success); std::unique_ptr data = serializer->Release(); JSDeserializerTest jsDeserializerTest; std::thread t1(&JSDeserializerTest::SerializeMultiSharedRegionTest, jsDeserializerTest, data.release()); ThreadSuspensionScope scope(thread); t1.join(); delete serializer; }; } // namespace panda::test