mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 16:13:49 +00:00
!5456 Enable value serialization
Merge pull request !5456 from dingwen/master
This commit is contained in:
commit
f352b9e4ad
@ -24,10 +24,10 @@ enum class ErrorType : uint8_t {
|
||||
EVAL_ERROR,
|
||||
RANGE_ERROR,
|
||||
REFERENCE_ERROR,
|
||||
SYNTAX_ERROR,
|
||||
TYPE_ERROR,
|
||||
URI_ERROR,
|
||||
AGGREGATE_ERROR,
|
||||
URI_ERROR,
|
||||
SYNTAX_ERROR,
|
||||
OOM_ERROR,
|
||||
TERMINATION_ERROR,
|
||||
};
|
||||
|
@ -870,6 +870,7 @@ void Builtins::LazyInitializeDate(const JSHandle<GlobalEnv> &env) const
|
||||
auto accessor = factory_->NewInternalAccessor(nullptr, reinterpret_cast<void *>(BuiltinsLazyCallback::Date));
|
||||
SetLazyAccessor(globalObject, key, accessor);
|
||||
env->SetDateFunction(thread_, accessor);
|
||||
env->SetDatePrototype(thread_, accessor);
|
||||
}
|
||||
|
||||
void Builtins::InitializeBoolean(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &primRefObjHClass) const
|
||||
@ -1271,6 +1272,8 @@ void Builtins::LazyInitializeSet(const JSHandle<GlobalEnv> &env)
|
||||
auto accessor = factory_->NewInternalAccessor(nullptr, reinterpret_cast<void *>(BuiltinsLazyCallback::Set));
|
||||
SetLazyAccessor(globalObject, key, accessor);
|
||||
env->SetBuiltinsSetFunction(thread_, accessor);
|
||||
env->SetSetPrototype(thread_, accessor);
|
||||
env->SetSetProtoValuesFunction(thread_, accessor);
|
||||
}
|
||||
|
||||
void Builtins::InitializeMap(const JSHandle<GlobalEnv> &env, JSHandle<JSTaggedValue> objFuncPrototypeVal) const
|
||||
@ -1341,6 +1344,7 @@ void Builtins::LazyInitializeMap(const JSHandle<GlobalEnv> &env) const
|
||||
SetLazyAccessor(globalObject, key, accessor);
|
||||
env->SetBuiltinsMapFunction(thread_, accessor);
|
||||
env->SetMapPrototype(thread_, accessor);
|
||||
env->SetMapProtoEntriesFunction(thread_, accessor);
|
||||
}
|
||||
|
||||
void Builtins::InitializeWeakMap(const JSHandle<GlobalEnv> &env, const JSHandle<JSHClass> &objFuncClass) const
|
||||
@ -2149,6 +2153,7 @@ void Builtins::LazyInitialize##Type(const JSHandle<GlobalEnv> &env) const
|
||||
auto accessor = factory_->NewInternalAccessor(nullptr, reinterpret_cast<void *>(BuiltinsLazyCallback::Type)); \
|
||||
SetLazyAccessor(globalObject, key, accessor); \
|
||||
env->Set##Type##Function(thread_, accessor); \
|
||||
env->Set##Type##FunctionPrototype(thread_, accessor); \
|
||||
}
|
||||
|
||||
BUILTIN_TYPED_ARRAY_TYPES(BUILTIN_TYPED_ARRAY_DEFINE_LAZY_INITIALIZE)
|
||||
@ -2460,6 +2465,7 @@ void Builtins::LazyInitializeDataView(const JSHandle<GlobalEnv> &env) const
|
||||
auto accessor = factory_->NewInternalAccessor(nullptr, reinterpret_cast<void *>(BuiltinsLazyCallback::DataView));
|
||||
SetLazyAccessor(globalObject, key, accessor);
|
||||
env->SetDataViewFunction(thread_, accessor);
|
||||
env->SetDataViewPrototype(thread_, accessor);
|
||||
}
|
||||
|
||||
JSHandle<JSFunction> Builtins::NewBuiltinConstructor(const JSHandle<GlobalEnv> &env,
|
||||
|
@ -171,7 +171,7 @@ using Address = uintptr_t;
|
||||
#define WIN_OR_MAC_OR_IOS_PLATFORM false
|
||||
#endif
|
||||
|
||||
#define ECMASCRIPT_ENABLE_VALUE_SERIALIZER 0
|
||||
#define ECMASCRIPT_ENABLE_VALUE_SERIALIZER 1
|
||||
|
||||
#define STATIC_ASSERT_EQ_ARCH(expect, valueArch32, valueArch64) \
|
||||
STATIC_ASSERT_EQ_ARCH32(expect, valueArch32); \
|
||||
|
@ -813,7 +813,8 @@ public:
|
||||
// ConstantData will also point at data of bytearray data.
|
||||
ACCESSORS(RelocatedData, RELOCTAED_DATA_OFFSET, ENTITY_ID_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(EntityId, int64_t, ENTITY_ID_OFFSET, CONSTANT_DATA_OFFSET);
|
||||
ACCESSORS_NATIVE_FIELD(ConstantData, uint8_t, CONSTANT_DATA_OFFSET, SIZE);
|
||||
ACCESSORS_NATIVE_FIELD(ConstantData, uint8_t, CONSTANT_DATA_OFFSET, LAST_OFFSET);
|
||||
DEFINE_ALIGN_SIZE(LAST_OFFSET);
|
||||
|
||||
CAST_CHECK(ConstantString, IsConstantString);
|
||||
DECL_VISIT_OBJECT(RELOCTAED_DATA_OFFSET, ENTITY_ID_OFFSET);
|
||||
@ -860,7 +861,9 @@ public:
|
||||
static constexpr uint32_t MIN_SLICED_ECMASTRING_LENGTH = 13;
|
||||
static constexpr size_t PARENT_OFFSET = EcmaString::SIZE;
|
||||
ACCESSORS(Parent, PARENT_OFFSET, STARTINDEX_OFFSET);
|
||||
ACCESSORS_PRIMITIVE_FIELD(StartIndex, uint32_t, STARTINDEX_OFFSET, SIZE);
|
||||
ACCESSORS_PRIMITIVE_FIELD(StartIndex, uint32_t, STARTINDEX_OFFSET, LAST_OFFSET);
|
||||
DEFINE_ALIGN_SIZE(LAST_OFFSET);
|
||||
|
||||
DECL_VISIT_OBJECT(PARENT_OFFSET, STARTINDEX_OFFSET);
|
||||
|
||||
CAST_CHECK(SlicedString, IsSlicedString);
|
||||
|
@ -527,8 +527,9 @@ bool JSThread::CheckSafepoint()
|
||||
gcTriggered = true;
|
||||
}
|
||||
#endif
|
||||
if (IsMarkFinished() && GetEcmaVM()->GetHeap()->GetConcurrentMarker()->IsTriggeredConcurrentMark()) {
|
||||
auto heap = GetEcmaVM()->GetHeap();
|
||||
auto heap = GetEcmaVM()->GetHeap();
|
||||
if (IsMarkFinished() && heap->GetConcurrentMarker()->IsTriggeredConcurrentMark()
|
||||
&& !heap->GetOnSerializeEvent()) {
|
||||
heap->GetConcurrentMarker()->HandleMarkingFinished();
|
||||
gcTriggered = true;
|
||||
}
|
||||
|
@ -1258,6 +1258,11 @@ void Heap::NotifyHighSensitive(bool isStart)
|
||||
|
||||
bool Heap::NeedStopCollection()
|
||||
{
|
||||
// gc is not allowed during value serialize
|
||||
if (onSerializeEvent_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!InSensitiveStatus()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -236,6 +236,16 @@ public:
|
||||
LOG_GC(INFO) << "SmartGC: enter app cold start";
|
||||
}
|
||||
|
||||
void SetOnSerializeEvent(bool isSerialize)
|
||||
{
|
||||
onSerializeEvent_ = isSerialize;
|
||||
}
|
||||
|
||||
bool GetOnSerializeEvent() const
|
||||
{
|
||||
return onSerializeEvent_;
|
||||
}
|
||||
|
||||
/*
|
||||
* For object allocations.
|
||||
*/
|
||||
@ -746,6 +756,7 @@ private:
|
||||
IdleNotifyStatusCallback notifyIdleStatusCallback {nullptr};
|
||||
std::atomic_bool onHighSensitiveEvent_ {false};
|
||||
bool onStartupEvent_ {false};
|
||||
bool onSerializeEvent_ {false};
|
||||
|
||||
IdleTaskType idleTask_ {IdleTaskType::NO_TASK};
|
||||
float idlePredictDuration_ {0.0f};
|
||||
|
@ -50,9 +50,13 @@ JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
|
||||
LOG_ECMA(ERROR) << "The serialization data is incomplete";
|
||||
return JSHandle<JSTaggedValue>();
|
||||
}
|
||||
|
||||
// stop gc during deserialize
|
||||
heap_->SetOnSerializeEvent(true);
|
||||
|
||||
uint8_t encodeFlag = data_->ReadUint8();
|
||||
uintptr_t result = 0U;
|
||||
while (ReadSingleEncodeData(encodeFlag, ObjectSlot(ToUintPtr(&result)), true) == 0) {
|
||||
JSTaggedType result = 0U;
|
||||
while (ReadSingleEncodeData(encodeFlag, ToUintPtr(&result), true) == 0) {
|
||||
encodeFlag = data_->ReadUint8();
|
||||
}
|
||||
// now new constpool here if newConstPoolInfos_ is not empty
|
||||
@ -62,6 +66,12 @@ JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
|
||||
}
|
||||
newConstPoolInfos_.clear();
|
||||
|
||||
// initialize concurrent func here after constpool is set
|
||||
for (auto func : concurrentFunctions_) {
|
||||
func->InitializeForConcurrentFunction(thread_);
|
||||
}
|
||||
concurrentFunctions_.clear();
|
||||
|
||||
// new native binding object here
|
||||
for (auto nativeBindingInfo : nativeBindingInfos_) {
|
||||
DeserializeNativeBindingObject(nativeBindingInfo);
|
||||
@ -69,7 +79,17 @@ JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
|
||||
}
|
||||
nativeBindingInfos_.clear();
|
||||
|
||||
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue(static_cast<JSTaggedType>(result)));
|
||||
// new js error here
|
||||
for (auto jsErrorInfo : jsErrorInfos_) {
|
||||
DeserializeJSError(jsErrorInfo);
|
||||
delete jsErrorInfo;
|
||||
}
|
||||
jsErrorInfos_.clear();
|
||||
|
||||
// recovery gc after serialize
|
||||
heap_->SetOnSerializeEvent(false);
|
||||
|
||||
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue(result));
|
||||
}
|
||||
|
||||
uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
|
||||
@ -78,7 +98,7 @@ uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
|
||||
uintptr_t res = RelocateObjectAddr(space, objSize);
|
||||
objectVector_.push_back(res);
|
||||
size_t resIndex = objectVector_.size() - 1;
|
||||
DeserializeObjectField(ObjectSlot(res), ObjectSlot(res + objSize));
|
||||
DeserializeObjectField(res, res + objSize);
|
||||
JSType type = reinterpret_cast<TaggedObject *>(res)->GetClass()->GetObjectType();
|
||||
// String need remove duplicates if string table can find
|
||||
if (type == JSType::LINE_STRING || type == JSType::CONSTANT_STRING) {
|
||||
@ -95,7 +115,7 @@ uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
|
||||
return res;
|
||||
}
|
||||
|
||||
void BaseDeserializer::DeserializeObjectField(ObjectSlot start, ObjectSlot end)
|
||||
void BaseDeserializer::DeserializeObjectField(uintptr_t start, uintptr_t end)
|
||||
{
|
||||
while (start < end) {
|
||||
uint8_t encodeFlag = data_->ReadUint8();
|
||||
@ -114,7 +134,7 @@ void BaseDeserializer::DeserializeConstPool(NewConstPoolInfo *info)
|
||||
int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
|
||||
thread_->GetCurrentEcmaContext()->AddConstpool(jsPandaFile, constpool.GetTaggedValue(), index);
|
||||
slot.Update(constpool.GetTaggedType());
|
||||
UpdateIfExistOldToNew(constpool.GetTaggedType(), slot);
|
||||
UpdateBarrier(constpool.GetTaggedType(), slot);
|
||||
}
|
||||
|
||||
void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingInfo *info)
|
||||
@ -134,7 +154,23 @@ void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingInfo *info)
|
||||
JSTaggedType res = JSNApiHelper::ToJSHandle(attachVal).GetTaggedType();
|
||||
slot.Update(res);
|
||||
if (!root) {
|
||||
UpdateIfExistOldToNew(res, slot);
|
||||
UpdateBarrier(res, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseDeserializer::DeserializeJSError(JSErrorInfo *info)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
uint8_t type = info->errorType_;
|
||||
base::ErrorType errorType = base::ErrorType(type - static_cast<uint8_t>(JSType::JS_ERROR_FIRST));
|
||||
JSTaggedValue errorMsg = info->errorMsg_;
|
||||
ObjectSlot slot = info->slot_;
|
||||
bool root = info->root_;
|
||||
ObjectFactory *factory = thread_->GetEcmaVM()->GetFactory();
|
||||
JSHandle<JSObject> errorTag = factory->NewJSError(errorType, JSHandle<EcmaString>(thread_, errorMsg));
|
||||
slot.Update(errorTag.GetTaggedType());
|
||||
if (!root) {
|
||||
UpdateBarrier(errorTag.GetTaggedType(), slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,21 +181,28 @@ void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, Ob
|
||||
bool isTransferBuffer = GetAndResetTransferBuffer();
|
||||
void *bufferPointer = GetAndResetBufferPointer();
|
||||
ConstantPool *constpool = GetAndResetConstantPool();
|
||||
if (needNewConstPool_) {
|
||||
needNewConstPool_ = false;
|
||||
newConstPoolInfos_.back()->slotAddr_ = slot.SlotAddress();
|
||||
}
|
||||
bool needNewConstPool = GetAndResetNeedNewConstPool();
|
||||
bool isErrorMsg = GetAndResetIsErrorMsg();
|
||||
|
||||
// deserialize object here
|
||||
uintptr_t addr = DeserializeTaggedObject(space);
|
||||
|
||||
// deserialize object epilogue
|
||||
if (isErrorMsg) {
|
||||
// defer new js error
|
||||
jsErrorInfos_.back()->errorMsg_ = JSTaggedValue(static_cast<JSTaggedType>(addr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTransferBuffer) {
|
||||
TransferArrayBufferAttach(addr);
|
||||
} else if (bufferPointer != nullptr) {
|
||||
ResetArrayBufferNativePointer(addr, bufferPointer);
|
||||
ResetNativePointerBuffer(addr, bufferPointer);
|
||||
} else if (constpool != nullptr) {
|
||||
ResetMethodConstantPool(addr, constpool);
|
||||
} else if (needNewConstPool) {
|
||||
// defer new constpool
|
||||
newConstPoolInfos_.back()->slotAddr_ = addr + Method::CONSTANT_POOL_OFFSET;
|
||||
}
|
||||
TaggedObject *object = reinterpret_cast<TaggedObject *>(addr);
|
||||
if (object->GetClass()->IsJSNativePointer()) {
|
||||
@ -167,10 +210,13 @@ void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, Ob
|
||||
if (nativePointer->GetDeleter() != nullptr) {
|
||||
thread_->GetEcmaVM()->PushToNativePointerList(nativePointer);
|
||||
}
|
||||
} else if (object->GetClass()->IsJSFunction()) {
|
||||
// defer initialize concurrent function until constpool is set
|
||||
concurrentFunctions_.push_back(reinterpret_cast<JSFunction *>(object));
|
||||
}
|
||||
UpdateMaybeWeak(slot, addr, isWeak);
|
||||
if (!isRoot) {
|
||||
UpdateIfExistOldToNew(addr, slot);
|
||||
UpdateBarrier(addr, slot);
|
||||
}
|
||||
}
|
||||
|
||||
@ -202,14 +248,25 @@ void BaseDeserializer::TransferArrayBufferAttach(uintptr_t objAddr)
|
||||
arrayBuffer->Attach(thread_, arrayLength, JSTaggedValue(np), withNativeAreaAllocator);
|
||||
}
|
||||
|
||||
void BaseDeserializer::ResetArrayBufferNativePointer(uintptr_t objAddr, void *bufferPointer)
|
||||
void BaseDeserializer::ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer)
|
||||
{
|
||||
ASSERT(JSTaggedValue(static_cast<JSTaggedType>(objAddr)).IsArrayBuffer());
|
||||
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
|
||||
arrayBuffer->SetWithNativeAreaAllocator(true);
|
||||
JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
|
||||
JSTaggedValue obj = JSTaggedValue(static_cast<JSTaggedType>(objAddr));
|
||||
ASSERT(obj.IsArrayBuffer() || obj.IsJSRegExp());
|
||||
auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
|
||||
JSNativePointer *np = nullptr;
|
||||
if (obj.IsArrayBuffer()) {
|
||||
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
|
||||
arrayBuffer->SetWithNativeAreaAllocator(true);
|
||||
np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
|
||||
nativeAreaAllocator->IncreaseNativeSizeStats(arrayBuffer->GetArrayBufferByteLength(), NativeFlag::ARRAY_BUFFER);
|
||||
} else {
|
||||
JSRegExp *jsRegExp = reinterpret_cast<JSRegExp *>(objAddr);
|
||||
np = reinterpret_cast<JSNativePointer *>(jsRegExp->GetByteCodeBuffer().GetTaggedObject());
|
||||
nativeAreaAllocator->IncreaseNativeSizeStats(jsRegExp->GetLength(), NativeFlag::REGEXP_BTYECODE);
|
||||
}
|
||||
|
||||
np->SetExternalPointer(bufferPointer);
|
||||
np->SetDeleter(&NativeAreaAllocator::FreeBufferFunc);
|
||||
np->SetDeleter(NativeAreaAllocator::FreeBufferFunc);
|
||||
np->SetData(thread_->GetEcmaVM()->GetNativeAreaAllocator());
|
||||
}
|
||||
|
||||
@ -220,9 +277,10 @@ void BaseDeserializer::ResetMethodConstantPool(uintptr_t objAddr, ConstantPool *
|
||||
method->SetConstantPool(thread_, JSTaggedValue(constpool), BarrierMode::SKIP_BARRIER);
|
||||
}
|
||||
|
||||
size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slot, bool isRoot)
|
||||
size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t addr, bool isRoot)
|
||||
{
|
||||
size_t handledFieldLength = SINGLE_FILED_LENGTH;
|
||||
size_t handledFieldSize = sizeof(JSTaggedType);
|
||||
ObjectSlot slot(addr);
|
||||
switch (encodeFlag) {
|
||||
case NEW_OBJECT_ALL_SPACES(): {
|
||||
SerializedObjectSpace space = SerializeData::DecodeSpace(encodeFlag);
|
||||
@ -231,15 +289,15 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slo
|
||||
}
|
||||
case (uint8_t)EncodeFlag::REFERENCE: {
|
||||
uint32_t objIndex = data_->ReadUint32();
|
||||
uintptr_t addr = objectVector_[objIndex];
|
||||
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
|
||||
UpdateIfExistOldToNew(addr, slot);
|
||||
uintptr_t objAddr = objectVector_[objIndex];
|
||||
UpdateMaybeWeak(slot, objAddr, GetAndResetWeak());
|
||||
UpdateBarrier(objAddr, slot);
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::WEAK: {
|
||||
ASSERT(!isWeak_);
|
||||
isWeak_ = true;
|
||||
handledFieldLength = 0;
|
||||
handledFieldSize = 0;
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::PRIMITIVE: {
|
||||
@ -248,47 +306,47 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slo
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::MULTI_RAW_DATA: {
|
||||
uint32_t length = data_->ReadUint32();
|
||||
data_->ReadRawData(slot.SlotAddress(), sizeof(JSTaggedType) * length);
|
||||
handledFieldLength = length;
|
||||
uint32_t size = data_->ReadUint32();
|
||||
data_->ReadRawData(addr, size);
|
||||
handledFieldSize = size;
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::ROOT_OBJECT: {
|
||||
uint32_t index = data_->ReadUint32();
|
||||
uintptr_t addr = thread_->GetEcmaVM()->GetSnapshotEnv()->RelocateRootObjectAddr(index);
|
||||
uintptr_t objAddr = thread_->GetEcmaVM()->GetSnapshotEnv()->RelocateRootObjectAddr(index);
|
||||
if (!isRoot) {
|
||||
UpdateIfExistOldToNew(addr, slot);
|
||||
UpdateBarrier(objAddr, slot);
|
||||
}
|
||||
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
|
||||
UpdateMaybeWeak(slot, objAddr, GetAndResetWeak());
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::OBJECT_PROTO: {
|
||||
uint8_t type = data_->ReadUint8();
|
||||
uintptr_t addr = RelocateObjectProtoAddr(type);
|
||||
uintptr_t protoAddr = RelocateObjectProtoAddr(type);
|
||||
if (!isRoot) {
|
||||
UpdateIfExistOldToNew(addr, slot);
|
||||
UpdateBarrier(protoAddr, slot);
|
||||
}
|
||||
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
|
||||
UpdateMaybeWeak(slot, protoAddr, GetAndResetWeak());
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::TRANSFER_ARRAY_BUFFER: {
|
||||
isTransferArrayBuffer_ = true;
|
||||
handledFieldLength = 0;
|
||||
handledFieldSize = 0;
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::ARRAY_BUFFER: {
|
||||
case (uint8_t)EncodeFlag::ARRAY_BUFFER:
|
||||
case (uint8_t)EncodeFlag::JS_REG_EXP: {
|
||||
size_t bufferLength = data_->ReadUint32();
|
||||
auto nativeAreaAllocator = thread_->GetEcmaVM()->GetNativeAreaAllocator();
|
||||
bufferPointer_ = nativeAreaAllocator->AllocateBuffer(bufferLength);
|
||||
data_->ReadRawData(ToUintPtr(bufferPointer_), bufferLength);
|
||||
nativeAreaAllocator->IncreaseNativeSizeStats(bufferLength, NativeFlag::ARRAY_BUFFER);
|
||||
heap_->IncreaseNativeBindingSize(bufferLength);
|
||||
handledFieldLength = 0;
|
||||
handledFieldSize = 0;
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::METHOD: {
|
||||
HandleMethodEncodeFlag();
|
||||
handledFieldLength = 0;
|
||||
handledFieldSize = 0;
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::NATIVE_BINDING_OBJECT: {
|
||||
@ -301,24 +359,43 @@ size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slo
|
||||
nativeBindingInfos_.push_back(new NativeBindingInfo(af, bufferPointer, hint, attachData, slot, isRoot));
|
||||
break;
|
||||
}
|
||||
case (uint8_t)EncodeFlag::JS_ERROR: {
|
||||
uint8_t type = data_->ReadUint8();
|
||||
ASSERT(type >= static_cast<uint8_t>(JSType::JS_ERROR_FIRST)
|
||||
&& type <= static_cast<uint8_t>(JSType::JS_ERROR_LAST));
|
||||
jsErrorInfos_.push_back(new JSErrorInfo(type, JSTaggedValue::Undefined(), slot, isRoot));
|
||||
uint8_t flag = data_->ReadUint8();
|
||||
if (flag == 1) { // error msg is string
|
||||
isErrorMsg_ = true;
|
||||
handledFieldSize = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ECMA(FATAL) << "this branch is unreachable";
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
return handledFieldLength;
|
||||
return handledFieldSize;
|
||||
}
|
||||
|
||||
void BaseDeserializer::UpdateIfExistOldToNew(uintptr_t addr, ObjectSlot slot)
|
||||
void BaseDeserializer::UpdateBarrier(uintptr_t addr, ObjectSlot slot)
|
||||
{
|
||||
Region *valueRegion = Region::ObjectAddressToRange(addr);
|
||||
if (valueRegion == nullptr) {
|
||||
return;
|
||||
}
|
||||
Region *rootRegion = Region::ObjectAddressToRange(slot.SlotAddress());
|
||||
// root region is impossible in young space when deserialize
|
||||
if (valueRegion != nullptr && valueRegion->InYoungSpace()) {
|
||||
if (valueRegion->InYoungSpace()) {
|
||||
// Should align with '8' in 64 and 32 bit platform
|
||||
ASSERT(slot.SlotAddress() % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT) == 0);
|
||||
Region *rootRegion = Region::ObjectAddressToRange(slot.SlotAddress());
|
||||
rootRegion->InsertOldToNewRSet(slot.SlotAddress());
|
||||
}
|
||||
|
||||
if (valueRegion->IsMarking()) {
|
||||
Barriers::Update(slot.SlotAddress(), rootRegion, reinterpret_cast<TaggedObject *>(addr), valueRegion);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t BaseDeserializer::RelocateObjectAddr(SerializedObjectSpace space, size_t objSize)
|
||||
|
@ -42,6 +42,17 @@ struct NativeBindingInfo {
|
||||
NativeBindingInfo(AttachFunc af, void *bufferPointer, void *hint, void *attachData, ObjectSlot slot, bool root)
|
||||
: af_(af), bufferPointer_(bufferPointer), hint_(hint), attachData_(attachData), slot_(slot), root_(root) {}
|
||||
};
|
||||
|
||||
struct JSErrorInfo {
|
||||
uint8_t errorType_ {0};
|
||||
JSTaggedValue errorMsg_;
|
||||
ObjectSlot slot_;
|
||||
bool root_ {false};
|
||||
|
||||
JSErrorInfo(uint8_t errorType, JSTaggedValue errorMsg, ObjectSlot slot, bool root)
|
||||
: errorType_(errorType), errorMsg_(errorMsg), slot_(slot), root_(root) {}
|
||||
};
|
||||
|
||||
class BaseDeserializer {
|
||||
public:
|
||||
explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr)
|
||||
@ -63,15 +74,16 @@ private:
|
||||
uintptr_t DeserializeTaggedObject(SerializedObjectSpace space);
|
||||
void DeserializeConstPool(NewConstPoolInfo *info);
|
||||
void DeserializeNativeBindingObject(NativeBindingInfo *info);
|
||||
void DeserializeJSError(JSErrorInfo *info);
|
||||
uintptr_t RelocateObjectAddr(SerializedObjectSpace space, size_t objSize);
|
||||
JSTaggedType RelocateObjectProtoAddr(uint8_t objectType);
|
||||
void DeserializeObjectField(ObjectSlot start, ObjectSlot end);
|
||||
size_t ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slot, bool isRoot = false);
|
||||
void DeserializeObjectField(uintptr_t start, uintptr_t end);
|
||||
size_t ReadSingleEncodeData(uint8_t encodeFlag, uintptr_t addr, bool isRoot = false);
|
||||
void HandleNewObjectEncodeFlag(SerializedObjectSpace space, ObjectSlot slot, bool isRoot);
|
||||
void HandleMethodEncodeFlag();
|
||||
|
||||
void TransferArrayBufferAttach(uintptr_t objAddr);
|
||||
void ResetArrayBufferNativePointer(uintptr_t objAddr, void *bufferPointer);
|
||||
void ResetNativePointerBuffer(uintptr_t objAddr, void *bufferPointer);
|
||||
void ResetMethodConstantPool(uintptr_t objAddr, ConstantPool *constpool);
|
||||
|
||||
void AllocateToDifferentSpaces();
|
||||
@ -79,7 +91,7 @@ private:
|
||||
void AllocateToOldSpace(size_t oldSpaceSize);
|
||||
void AllocateToNonMovableSpace(size_t nonMovableSpaceSize);
|
||||
void AllocateToMachineCodeSpace(size_t machineCodeSpaceSize);
|
||||
void UpdateIfExistOldToNew(uintptr_t addr, ObjectSlot slot);
|
||||
void UpdateBarrier(uintptr_t addr, ObjectSlot slot);
|
||||
|
||||
bool GetAndResetWeak()
|
||||
{
|
||||
@ -92,11 +104,29 @@ private:
|
||||
|
||||
bool GetAndResetTransferBuffer()
|
||||
{
|
||||
bool isTransferArrayBuffer = isTransferArrayBuffer_;
|
||||
if (isTransferArrayBuffer_) {
|
||||
isTransferArrayBuffer_ = false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return isTransferArrayBuffer;
|
||||
}
|
||||
|
||||
bool GetAndResetNeedNewConstPool()
|
||||
{
|
||||
bool needNewConstPool = needNewConstPool_;
|
||||
if (needNewConstPool_) {
|
||||
needNewConstPool_ = false;
|
||||
}
|
||||
return needNewConstPool;
|
||||
}
|
||||
|
||||
bool GetAndResetIsErrorMsg()
|
||||
{
|
||||
bool isErrorMsg = isErrorMsg_;
|
||||
if (isErrorMsg_) {
|
||||
isErrorMsg_ = false;
|
||||
}
|
||||
return isErrorMsg;
|
||||
}
|
||||
|
||||
void *GetAndResetBufferPointer()
|
||||
@ -125,7 +155,6 @@ private:
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr size_t SINGLE_FILED_LENGTH = 1;
|
||||
JSThread *thread_;
|
||||
Heap *heap_;
|
||||
std::unique_ptr<SerializeData> data_;
|
||||
@ -141,11 +170,14 @@ private:
|
||||
size_t regionRemainSizeIndex_ {0};
|
||||
bool isWeak_ {false};
|
||||
bool isTransferArrayBuffer_ {false};
|
||||
bool isErrorMsg_ {false};
|
||||
void *bufferPointer_ {nullptr};
|
||||
ConstantPool *constpool_ {nullptr};
|
||||
bool needNewConstPool_ {false};
|
||||
CVector<NewConstPoolInfo *> newConstPoolInfos_;
|
||||
CVector<NativeBindingInfo *> nativeBindingInfos_;
|
||||
CVector<JSErrorInfo *> jsErrorInfos_;
|
||||
CVector<JSFunction *> concurrentFunctions_;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,7 @@ void BaseSerializer::WriteMultiRawData(uintptr_t beginAddr, size_t fieldSize)
|
||||
{
|
||||
if (fieldSize > 0) {
|
||||
data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
|
||||
data_->WriteUint32(fieldSize / sizeof(JSTaggedType));
|
||||
data_->WriteUint32(fieldSize);
|
||||
data_->WriteRawData(reinterpret_cast<uint8_t *>(beginAddr), fieldSize);
|
||||
}
|
||||
}
|
||||
@ -158,6 +158,13 @@ void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root,
|
||||
while (slot < end) {
|
||||
size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
|
||||
switch (fieldOffset) {
|
||||
// hash filed
|
||||
case sizeof(TaggedObject): {
|
||||
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
|
||||
data_->WriteJSTaggedValue(JSTaggedValue(0)); // 0: reset hash filed
|
||||
slot++;
|
||||
break;
|
||||
}
|
||||
case JSFunction::PROTO_OR_DYNCLASS_OFFSET:
|
||||
case JSFunction::LEXICAL_ENV_OFFSET:
|
||||
case JSFunction::HOME_OBJECT_OFFSET: {
|
||||
@ -167,8 +174,9 @@ void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root,
|
||||
break;
|
||||
}
|
||||
case JSFunction::WORK_NODE_POINTER_OFFSET: {
|
||||
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
|
||||
data_->WriteJSTaggedType(0U);
|
||||
data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
|
||||
data_->WriteUint32(sizeof(uintptr_t));
|
||||
data_->WriteRawData(reinterpret_cast<uint8_t *>(slot.SlotAddress()), sizeof(uintptr_t));
|
||||
slot++;
|
||||
break;
|
||||
}
|
||||
|
@ -29,16 +29,18 @@ enum class EncodeFlag : uint8_t {
|
||||
// 0x03: huge space
|
||||
NEW_OBJECT = 0x00,
|
||||
REFERENCE = 0x04,
|
||||
WEAK = 0x05,
|
||||
PRIMITIVE = 0x06,
|
||||
MULTI_RAW_DATA = 0x07,
|
||||
ROOT_OBJECT = 0x08,
|
||||
OBJECT_PROTO = 0X09,
|
||||
ARRAY_BUFFER = 0x0a,
|
||||
TRANSFER_ARRAY_BUFFER = 0X0b,
|
||||
METHOD = 0x0c,
|
||||
NATIVE_BINDING_OBJECT = 0x0d,
|
||||
LAST = 0x0e
|
||||
WEAK,
|
||||
PRIMITIVE,
|
||||
MULTI_RAW_DATA,
|
||||
ROOT_OBJECT,
|
||||
OBJECT_PROTO,
|
||||
ARRAY_BUFFER,
|
||||
TRANSFER_ARRAY_BUFFER,
|
||||
METHOD,
|
||||
NATIVE_BINDING_OBJECT,
|
||||
JS_ERROR,
|
||||
JS_REG_EXP,
|
||||
LAST
|
||||
};
|
||||
|
||||
enum class SerializedObjectSpace : uint8_t {
|
||||
|
@ -143,6 +143,98 @@ public:
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void JSPlainObjectTest3(SerializeData* data)
|
||||
{
|
||||
Init();
|
||||
BaseDeserializer deserializer(thread, data);
|
||||
JSHandle<JSTaggedValue> objValue = deserializer.ReadValue();
|
||||
ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC);
|
||||
ecmaVm->CollectGarbage(TriggerGCType::OLD_GC);
|
||||
|
||||
JSHandle<JSObject> retObj = JSHandle<JSObject>::Cast(objValue);
|
||||
EXPECT_FALSE(retObj.IsEmpty());
|
||||
EXPECT_TRUE(retObj->GetClass()->IsDictionaryMode());
|
||||
|
||||
JSHandle<TaggedArray> array = JSObject::GetOwnPropertyKeys(thread, retObj);
|
||||
uint32_t length = array->GetLength();
|
||||
EXPECT_EQ(length, 1030U);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
JSHandle<JSTaggedValue> key(thread, array->Get(i));
|
||||
JSHandle<JSTaggedValue> value =
|
||||
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(retObj), key).GetValue();
|
||||
EXPECT_TRUE(value->IsInt());
|
||||
}
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void JSPlainObjectTest4(SerializeData* data)
|
||||
{
|
||||
Init();
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
JSHandle<JSTaggedValue> key(factory->NewFromASCII("str1"));
|
||||
|
||||
BaseDeserializer deserializer(thread, data);
|
||||
JSHandle<JSTaggedValue> objValue = deserializer.ReadValue();
|
||||
ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC);
|
||||
ecmaVm->CollectGarbage(TriggerGCType::OLD_GC);
|
||||
|
||||
JSHandle<JSObject> retObj = JSHandle<JSObject>::Cast(objValue);
|
||||
EXPECT_FALSE(retObj.IsEmpty());
|
||||
|
||||
JSHandle<JSTaggedValue> value =
|
||||
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(retObj), key).GetValue();
|
||||
EXPECT_TRUE(value->IsTaggedArray());
|
||||
TaggedArray *array = reinterpret_cast<TaggedArray *>(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<JSTaggedValue> 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<JSTaggedValue> objValue = deserializer.ReadValue();
|
||||
ecmaVm->CollectGarbage(TriggerGCType::YOUNG_GC);
|
||||
ecmaVm->CollectGarbage(TriggerGCType::OLD_GC);
|
||||
|
||||
JSHandle<JSObject> retObj = JSHandle<JSObject>::Cast(objValue);
|
||||
EXPECT_FALSE(retObj.IsEmpty());
|
||||
|
||||
JSHandle<TaggedArray> array = JSObject::GetOwnPropertyKeys(thread, retObj);
|
||||
uint32_t length = array->GetLength();
|
||||
EXPECT_EQ(length, 2U);
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
JSHandle<JSTaggedValue> key(thread, array->Get(i));
|
||||
JSHandle<JSTaggedValue> value =
|
||||
JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(retObj), key).GetValue();
|
||||
EXPECT_TRUE(value->IsJSError());
|
||||
}
|
||||
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void BigIntTest(SerializeData* data)
|
||||
{
|
||||
Init();
|
||||
@ -421,6 +513,8 @@ public:
|
||||
Init();
|
||||
JSHandle<EcmaString> pattern = thread->GetEcmaVM()->GetFactory()->NewFromASCII("key2");
|
||||
JSHandle<EcmaString> flags = thread->GetEcmaVM()->GetFactory()->NewFromASCII("i");
|
||||
char buffer[] = "1234567"; // use char buffer to simulate byteCodeBuffer
|
||||
uint32_t bufferSize = 7;
|
||||
|
||||
BaseDeserializer deserializer(thread, data);
|
||||
JSHandle<JSTaggedValue> res = deserializer.ReadValue();
|
||||
@ -428,12 +522,22 @@ public:
|
||||
EXPECT_TRUE(res->IsJSRegExp()) << "[NotJSRegexp] Deserialize JSRegExp fail";
|
||||
JSHandle<JSRegExp> resJSRegexp(res);
|
||||
|
||||
uint32_t resBufferSize = resJSRegexp->GetLength();
|
||||
EXPECT_TRUE(resBufferSize == bufferSize) << "Not Same Length";
|
||||
JSHandle<JSTaggedValue> originalSource(thread, resJSRegexp->GetOriginalSource());
|
||||
EXPECT_TRUE(originalSource->IsString());
|
||||
JSHandle<JSTaggedValue> originalFlags(thread, resJSRegexp->GetOriginalFlags());
|
||||
EXPECT_TRUE(originalFlags->IsString());
|
||||
EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle<EcmaString>(originalSource), *pattern));
|
||||
EXPECT_TRUE(EcmaStringAccessor::StringsAreEqual(*JSHandle<EcmaString>(originalFlags), *flags));
|
||||
JSHandle<JSTaggedValue> resBufferData(thread, resJSRegexp->GetByteCodeBuffer());
|
||||
JSHandle<JSNativePointer> resNp = JSHandle<JSNativePointer>::Cast(resBufferData);
|
||||
void *resBuffer = resNp->GetExternalPointer();
|
||||
ASSERT_NE(resBuffer, nullptr);
|
||||
|
||||
for (uint32_t i = 0; i < resBufferSize; i++) {
|
||||
EXPECT_TRUE(static_cast<char *>(resBuffer)[i] == buffer[i]) << "Not Same ByteCode";
|
||||
}
|
||||
|
||||
Destroy();
|
||||
}
|
||||
@ -709,7 +813,7 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject2)
|
||||
}
|
||||
key2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1));
|
||||
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(key2),
|
||||
JSHandle<JSTaggedValue>(obj1));
|
||||
JSHandle<JSTaggedValue>(obj1));
|
||||
}
|
||||
|
||||
ValueSerializer *serializer = new ValueSerializer(thread);
|
||||
@ -721,6 +825,93 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject2)
|
||||
delete serializer;
|
||||
};
|
||||
|
||||
// test dictionary mode
|
||||
HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject3)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
JSHandle<EcmaString> key1(factory->NewFromASCII("str1"));
|
||||
JSHandle<EcmaString> key2(factory->NewFromASCII("str2"));
|
||||
JSHandle<JSTaggedValue> value1(thread, JSTaggedValue(1));
|
||||
for (int i = 0; i < 1030; i++) {
|
||||
key2 = JSHandle<EcmaString>(thread, EcmaStringAccessor::Concat(ecmaVm, key2, key1));
|
||||
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(key2), value1);
|
||||
}
|
||||
|
||||
EXPECT_TRUE(obj->GetClass()->IsDictionaryMode());
|
||||
|
||||
ValueSerializer *serializer = new ValueSerializer(thread);
|
||||
serializer->WriteValue(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(obj));
|
||||
std::unique_ptr<SerializeData> data = serializer->Release();
|
||||
JSDeserializerTest jsDeserializerTest;
|
||||
std::thread t1(&JSDeserializerTest::JSPlainObjectTest3, jsDeserializerTest, data.release());
|
||||
t1.join();
|
||||
delete serializer;
|
||||
};
|
||||
|
||||
// test huge object serialize
|
||||
HWTEST_F_L0(JSSerializerTest, SerializeJSPlainObject4)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
JSHandle<EcmaString> key1(factory->NewFromASCII("str1"));
|
||||
// new huge tagged array
|
||||
JSHandle<TaggedArray> taggedArray =
|
||||
factory->NewTaggedArray(1024 * 100, JSTaggedValue::Hole(), MemSpaceType::OLD_SPACE);
|
||||
|
||||
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(key1),
|
||||
JSHandle<JSTaggedValue>(taggedArray));
|
||||
|
||||
ValueSerializer *serializer = new ValueSerializer(thread);
|
||||
serializer->WriteValue(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(obj));
|
||||
std::unique_ptr<SerializeData> data = serializer->Release();
|
||||
JSDeserializerTest jsDeserializerTest;
|
||||
std::thread t1(&JSDeserializerTest::JSPlainObjectTest4, jsDeserializerTest, data.release());
|
||||
t1.join();
|
||||
delete serializer;
|
||||
};
|
||||
|
||||
HWTEST_F_L0(JSSerializerTest, SerializeJSError1)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
JSHandle<EcmaString> msg(factory->NewFromASCII("this is error"));
|
||||
JSHandle<JSTaggedValue> errorTag =
|
||||
JSHandle<JSTaggedValue>::Cast(factory->NewJSError(base::ErrorType::ERROR, msg));
|
||||
|
||||
ValueSerializer *serializer = new ValueSerializer(thread);
|
||||
serializer->WriteValue(thread, errorTag, errorTag);
|
||||
std::unique_ptr<SerializeData> data = serializer->Release();
|
||||
JSDeserializerTest jsDeserializerTest;
|
||||
std::thread t1(&JSDeserializerTest::JSErrorTest1, jsDeserializerTest, data.release());
|
||||
t1.join();
|
||||
delete serializer;
|
||||
};
|
||||
|
||||
HWTEST_F_L0(JSSerializerTest, SerializeJSError2)
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
JSHandle<JSObject> obj = factory->NewEmptyJSObject();
|
||||
JSHandle<EcmaString> key1(factory->NewFromASCII("error1"));
|
||||
JSHandle<EcmaString> key2(factory->NewFromASCII("error2"));
|
||||
JSHandle<EcmaString> msg(factory->NewFromASCII("this is error"));
|
||||
JSHandle<JSTaggedValue> errorTag =
|
||||
JSHandle<JSTaggedValue>::Cast(factory->NewJSError(base::ErrorType::ERROR, msg));
|
||||
|
||||
|
||||
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(key1), errorTag);
|
||||
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(key2), errorTag);
|
||||
|
||||
ValueSerializer *serializer = new ValueSerializer(thread);
|
||||
serializer->WriteValue(thread, JSHandle<JSTaggedValue>(obj), JSHandle<JSTaggedValue>(obj));
|
||||
std::unique_ptr<SerializeData> data = serializer->Release();
|
||||
JSDeserializerTest jsDeserializerTest;
|
||||
std::thread t1(&JSDeserializerTest::JSErrorTest2, jsDeserializerTest, data.release());
|
||||
t1.join();
|
||||
delete serializer;
|
||||
#endif
|
||||
};
|
||||
|
||||
HWTEST_F_L0(JSSerializerTest, SerializeBigInt)
|
||||
{
|
||||
ObjectFactory *factory = ecmaVm->GetFactory();
|
||||
@ -938,7 +1129,9 @@ HWTEST_F_L0(JSSerializerTest, SerializeJSRegExp)
|
||||
JSHandle<JSRegExp>::Cast(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(target), target));
|
||||
JSHandle<EcmaString> pattern = thread->GetEcmaVM()->GetFactory()->NewFromASCII("key2");
|
||||
JSHandle<EcmaString> flags = thread->GetEcmaVM()->GetFactory()->NewFromASCII("i");
|
||||
|
||||
char buffer[] = "1234567"; // use char to simulate bytecode
|
||||
uint32_t bufferSize = 7;
|
||||
factory->NewJSRegExpByteCodeData(jsRegexp, static_cast<void *>(buffer), bufferSize);
|
||||
jsRegexp->SetOriginalSource(thread, JSHandle<JSTaggedValue>(pattern));
|
||||
jsRegexp->SetOriginalFlags(thread, JSHandle<JSTaggedValue>(flags));
|
||||
|
||||
|
@ -65,6 +65,7 @@ bool ValueSerializer::CheckObjectCanSerialize(TaggedObject *object)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
LOG_ECMA(ERROR) << "Unsupport serialize object type: " << JSHClass::DumpJSType(type);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -99,6 +100,7 @@ bool ValueSerializer::WriteValue(JSThread *thread, const JSHandle<JSTaggedValue>
|
||||
vm_->GetSnapshotEnv()->ClearEnvMap();
|
||||
}
|
||||
if (notSupport_) {
|
||||
LOG_ECMA(ERROR) << "ValueSerialize: serialize data is incomplete";
|
||||
data_->SetIncompleteData(true);
|
||||
return false;
|
||||
}
|
||||
@ -124,8 +126,14 @@ void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak)
|
||||
SerializeNativeBindingObject(object);
|
||||
return;
|
||||
}
|
||||
JSType type = object->GetClass()->GetObjectType();
|
||||
if (object->GetClass()->IsJSError()) {
|
||||
SerializeJSError(object);
|
||||
return;
|
||||
}
|
||||
bool arrayBufferDeferDetach = false;
|
||||
JSTaggedValue trackInfo;
|
||||
JSType type = object->GetClass()->GetObjectType();
|
||||
// serialize prologue
|
||||
switch (type) {
|
||||
case JSType::JS_ARRAY_BUFFER:
|
||||
arrayBufferDeferDetach = SerializeJSArrayBufferPrologue(object);
|
||||
@ -136,10 +144,31 @@ void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak)
|
||||
case JSType::METHOD:
|
||||
SerializeMethodPrologue(reinterpret_cast<Method *>(object));
|
||||
break;
|
||||
case JSType::JS_ARRAY: {
|
||||
JSArray *array = reinterpret_cast<JSArray *>(object);
|
||||
trackInfo = array->GetTrackInfo();
|
||||
array->SetTrackInfo(thread_, JSTaggedValue::Undefined());
|
||||
break;
|
||||
}
|
||||
case JSType::TREE_STRING:
|
||||
case JSType::SLICED_STRING:
|
||||
object = EcmaStringAccessor::FlattenNoGC(vm_, EcmaString::Cast(object));
|
||||
break;
|
||||
case JSType::JS_REG_EXP:
|
||||
SerializeJSRegExpPrologue(reinterpret_cast<JSRegExp *>(object));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// serialize object here
|
||||
SerializeTaggedObject<SerializeType::VALUE_SERIALIZE>(object);
|
||||
|
||||
// serialize epilogue
|
||||
if (type == JSType::JS_ARRAY) {
|
||||
JSArray *array = reinterpret_cast<JSArray *>(object);
|
||||
array->SetTrackInfo(thread_, trackInfo);
|
||||
}
|
||||
if (arrayBufferDeferDetach) {
|
||||
ASSERT(object->GetClass()->IsArrayBuffer());
|
||||
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(object);
|
||||
@ -147,6 +176,26 @@ void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak)
|
||||
}
|
||||
}
|
||||
|
||||
void ValueSerializer::SerializeJSError(TaggedObject *object)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
data_->WriteEncodeFlag(EncodeFlag::JS_ERROR);
|
||||
JSType type = object->GetClass()->GetObjectType();
|
||||
ASSERT(type >= JSType::JS_ERROR_FIRST && type <= JSType::JS_ERROR_LAST);
|
||||
data_->WriteUint8(static_cast<uint8_t>(type));
|
||||
auto globalConst = thread_->GlobalConstants();
|
||||
JSHandle<JSTaggedValue> handleMsg = globalConst->GetHandledMessageString();
|
||||
JSHandle<JSTaggedValue> msg =
|
||||
JSObject::GetProperty(thread_, JSHandle<JSTaggedValue>(thread_, object), handleMsg).GetValue();
|
||||
if (msg->IsString()) {
|
||||
EcmaString *str = EcmaStringAccessor::FlattenNoGC(vm_, EcmaString::Cast(msg->GetTaggedObject()));
|
||||
data_->WriteUint8(1); // 1: msg is string
|
||||
SerializeTaggedObject<SerializeType::VALUE_SERIALIZE>(str);
|
||||
} else {
|
||||
data_->WriteUint8(0); // 0: msg is undefined
|
||||
}
|
||||
}
|
||||
|
||||
void ValueSerializer::SerializeNativeBindingObject(TaggedObject *object)
|
||||
{
|
||||
[[maybe_unused]] EcmaHandleScope scope(thread_);
|
||||
@ -247,6 +296,22 @@ void ValueSerializer::SerializeMethodPrologue(Method *method)
|
||||
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(jsPandaFile));
|
||||
}
|
||||
|
||||
void ValueSerializer::SerializeJSRegExpPrologue(JSRegExp *jsRegExp)
|
||||
{
|
||||
uint32_t bufferSize = jsRegExp->GetLength();
|
||||
if (bufferSize == 0) {
|
||||
LOG_ECMA(ERROR) << "ValueSerialize: JSRegExp buffer size is 0";
|
||||
notSupport_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
data_->WriteEncodeFlag(EncodeFlag::JS_REG_EXP);
|
||||
data_->WriteUint32(bufferSize);
|
||||
JSNativePointer *np =
|
||||
reinterpret_cast<JSNativePointer *>(jsRegExp->GetByteCodeBuffer().GetTaggedObject());
|
||||
data_->WriteRawData(static_cast<uint8_t *>(np->GetExternalPointer()), bufferSize);
|
||||
}
|
||||
|
||||
bool ValueSerializer::PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer)
|
||||
{
|
||||
if (transfer->IsUndefined()) {
|
||||
|
@ -31,10 +31,12 @@ public:
|
||||
|
||||
private:
|
||||
void SerializeObjectImpl(TaggedObject *object, bool isWeak = false) override;
|
||||
void SerializeJSError(TaggedObject *object);
|
||||
void SerializeNativeBindingObject(TaggedObject *object);
|
||||
bool SerializeJSArrayBufferPrologue(TaggedObject *object);
|
||||
void SerializeJSSharedArrayBufferPrologue(TaggedObject *object);
|
||||
void SerializeMethodPrologue(Method *method);
|
||||
void SerializeJSRegExpPrologue(JSRegExp *jsRegExp);
|
||||
void InitTransferSet(CUnorderedSet<uintptr_t> transferDataSet);
|
||||
void ClearTransferSet();
|
||||
bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer);
|
||||
@ -42,7 +44,10 @@ private:
|
||||
|
||||
bool IsInternalJSType(JSType type)
|
||||
{
|
||||
return type >= JSType::HCLASS && type <= JSType::TYPE_LAST;
|
||||
if (type >= JSType::JS_RECORD_FIRST && type <= JSType::JS_RECORD_LAST) {
|
||||
return false;
|
||||
}
|
||||
return type >= JSType::HCLASS && type <= JSType::TYPE_LAST && type != JSType::SYMBOL;
|
||||
}
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user