Implement serialize base class

Description:Implement serialize base class
Issue:https://gitee.com/openharmony/arkcompiler_ets_runtime/issues/I8GZGX
Signed-off-by: dingwen <dingwen6@huawei.com>

Change-Id: Ia03fc9cac949d73cafbd6a2603da053d2f886cd1
This commit is contained in:
dingwen 2023-11-16 15:12:09 +08:00
parent 9cc8a59978
commit 8f5e2fa5b4
53 changed files with 3590 additions and 314 deletions

View File

@ -93,6 +93,7 @@ group("ark_js_unittest") {
if (host_os != "mac") {
deps += [
"ecmascript/pgo_profiler/tests:unittest",
"ecmascript/serializer/tests:unittest",
"//arkcompiler/ets_runtime/ecmascript/base/tests:unittest",
"//arkcompiler/ets_runtime/ecmascript/builtins/tests:unittest",
"//arkcompiler/ets_runtime/ecmascript/containers/tests:unittest",
@ -139,6 +140,7 @@ group("ark_unittest") {
"ecmascript/pgo_profiler/tests:host_unittest",
"ecmascript/regexp/tests:host_unittest",
"ecmascript/require/tests:host_unittest",
"ecmascript/serializer/tests:host_unittest",
"ecmascript/snapshot/tests:host_unittest",
"ecmascript/tests:host_unittest",
"ecmascript/ts_types/tests:host_unittest",
@ -788,6 +790,9 @@ ecma_source = [
"ecmascript/pgo_profiler/ap_file/pgo_method_type_set.cpp",
"ecmascript/pgo_profiler/types/pgo_profile_type.cpp",
"ecmascript/property_accessor.cpp",
"ecmascript/serializer/base_deserializer.cpp",
"ecmascript/serializer/base_serializer.cpp",
"ecmascript/serializer/value_serializer.cpp",
"ecmascript/stackmap/ark_stackmap_builder.cpp",
"ecmascript/stackmap/ark_stackmap_parser.cpp",
"ecmascript/stackmap/llvm_stackmap_parser.cpp",

View File

@ -35,6 +35,18 @@ public:
return size;
}
static inline size_t ComputeDataSize(size_t elemSize, uint32_t length)
{
ASSERT(elemSize != 0);
return elemSize * length;
}
size_t GetPointerLength()
{
size_t byteSize = ComputeDataSize(GetArrayLength(), GetByteLength());
return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType);
}
inline void *GetData(uint32_t index = 0) const
{
return reinterpret_cast<void *>(ToUintPtr(this) + DATA_OFFSET + index * GetByteLength());
@ -49,6 +61,7 @@ public:
DEFINE_ALIGN_SIZE(LAST_OFFSET);
static constexpr size_t DATA_OFFSET = SIZE; // DATA_OFFSET equal to Empty ByteArray size
DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetPointerLength());
DECL_DUMP()
private:

View File

@ -171,6 +171,8 @@ using Address = uintptr_t;
#define WIN_OR_MAC_OR_IOS_PLATFORM false
#endif
#define ECMASCRIPT_ENABLE_VALUE_SERIALIZER 0
#define STATIC_ASSERT_EQ_ARCH(expect, valueArch32, valueArch64) \
STATIC_ASSERT_EQ_ARCH32(expect, valueArch32); \
STATIC_ASSERT_EQ_ARCH64(expect, valueArch64)

View File

@ -1448,7 +1448,7 @@ void LLVMIRBuilder::VisitLoad(GateRef gate, GateRef base)
switch (order.GetOrder()) {
case MemoryOrder::MEMORY_ORDER_RELEASE: {
LLVMSetOrdering(result, LLVMAtomicOrderingRelease);
[[fallthrough]];
break;
}
case MemoryOrder::NOT_ATOMIC: {
break;
@ -1479,7 +1479,7 @@ void LLVMIRBuilder::VisitStore(GateRef gate, GateRef base, GateRef value)
switch (order.GetOrder()) {
case MemoryOrder::MEMORY_ORDER_RELEASE: {
LLVMSetOrdering(result, LLVMAtomicOrderingRelease);
[[fallthrough]];
break;
}
case MemoryOrder::NOT_ATOMIC: {
break;

View File

@ -444,10 +444,8 @@ JSTaggedValue EcmaContext::FindConstpool(const JSPandaFile *jsPandaFile, panda_f
return FindConstpool(jsPandaFile, index);
}
JSHandle<ConstantPool> EcmaContext::FindOrCreateConstPool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id)
JSTaggedValue EcmaContext::FindConstpoolWithAOT(const JSPandaFile *jsPandaFile, int32_t index)
{
panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
JSTaggedValue constpool = FindConstpool(jsPandaFile, index);
// In the taskpool thread, there is a case where the Function object is serialized before InitForCurrentThread.
// A constpool is created when a Function is serialized. Slowpath, the default deserialized constpool,
@ -458,12 +456,19 @@ JSHandle<ConstantPool> EcmaContext::FindOrCreateConstPool(const JSPandaFile *jsP
constpool = FindConstpool(jsPandaFile, index);
}
}
return constpool;
}
JSHandle<ConstantPool> EcmaContext::FindOrCreateConstPool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id)
{
panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), id);
int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
JSTaggedValue constpool = FindConstpoolWithAOT(jsPandaFile, index);
if (constpool.IsHole()) {
JSHandle<ConstantPool> newConstpool = ConstantPool::CreateConstPool(vm_, jsPandaFile, id);
AddConstpool(jsPandaFile, newConstpool.GetTaggedValue(), index);
return newConstpool;
}
return JSHandle<ConstantPool>(thread_, constpool);
}

View File

@ -252,6 +252,7 @@ public:
JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, int32_t index);
// For new version instruction.
JSTaggedValue FindConstpool(const JSPandaFile *jsPandaFile, panda_file::File::EntityId id);
JSTaggedValue FindConstpoolWithAOT(const JSPandaFile *jsPandaFile, int32_t index);
std::optional<std::reference_wrapper<CMap<int32_t, JSTaggedValue>>> FindConstpools(
const JSPandaFile *jsPandaFile);

View File

@ -472,50 +472,54 @@
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DECL_VISIT_ARRAY(BEGIN_OFFSET, LENGTH) \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
size_t endOffset = (BEGIN_OFFSET) + (LENGTH) * JSTaggedValue::TaggedTypeSize(); \
visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), \
ObjectSlot(ToUintPtr(this) + endOffset), VisitObjectArea::NORMAL); \
#define DECL_VISIT_ARRAY(BEGIN_OFFSET, REF_LENGTH, LENGTH) \
template <VisitType visitType> \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
ArrayBodyIterator<visitType, (BEGIN_OFFSET)>::IterateBody(this, visitor, (REF_LENGTH), (LENGTH)); \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET) \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), \
ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NORMAL); \
#define DECL_VISIT_OBJECT(BEGIN_OFFSET, END_OFFSET) \
template <VisitType visitType> \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateRefBody(this, visitor); \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET) \
void VisitRangeSlotForNative(const EcmaObjectRangeVisitor &visitor) \
{ \
visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), \
ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NATIVE_POINTER); \
#define DECL_VISIT_PRIMITIVE_OBJECT() \
template <VisitType visitType> \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
PrimitiveObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor); \
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET) \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
VisitObjects(visitor); \
/* visit in object fields */ \
auto objSize = this->GetClass()->GetObjectSize(); \
if (objSize > SIZE) { \
visitor(this, ObjectSlot(ToUintPtr(this) + SIZE), \
ObjectSlot(ToUintPtr(this) + objSize), VisitObjectArea::IN_OBJECT); \
} \
} \
void VisitObjects(const EcmaObjectRangeVisitor &visitor) \
{ \
PARENTCLASS::VisitObjects(visitor); \
if ((BEGIN_OFFSET) == (END_OFFSET)) { \
return; \
} \
visitor(this, ObjectSlot(ToUintPtr(this) + (BEGIN_OFFSET)), \
ObjectSlot(ToUintPtr(this) + (END_OFFSET)), VisitObjectArea::NORMAL); \
#define DECL_VISIT_NATIVE_FIELD(BEGIN_OFFSET, END_OFFSET) \
template <VisitType visitType> \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
ObjectBodyIterator<visitType, (BEGIN_OFFSET), (END_OFFSET), SIZE>::IterateNativeBody(this, visitor); \
} \
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, END_OFFSET) \
template <VisitType visitType> \
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \
{ \
VisitObjects<visitType>(visitor); \
JSObjectBodyIterator<visitType, SIZE>::IterateBody(this, visitor); \
} \
template <VisitType visitType> \
void VisitObjects(const EcmaObjectRangeVisitor &visitor) \
{ \
PARENTCLASS::VisitObjects<visitType>(visitor); \
if ((BEGIN_OFFSET) == (END_OFFSET)) { \
return; \
} \
ObjectBodyIterator<visitType, (BEGIN_OFFSET), \
(END_OFFSET), SIZE>::IterateRefBody(this, visitor, PARENTCLASS::SIZE); \
}
#if ECMASCRIPT_ENABLE_CAST_CHECK

View File

@ -726,6 +726,8 @@ public:
CAST_CHECK(LineEcmaString, IsLineString);
DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetPointerLength());
static LineEcmaString *Cast(EcmaString *str)
{
return static_cast<LineEcmaString *>(str);
@ -752,6 +754,18 @@ public:
return str->IsUtf16() ? ComputeSizeUtf16(length) : ComputeSizeUtf8(length);
}
static size_t DataSize(EcmaString *str)
{
uint32_t length = str->GetLength();
return str->IsUtf16() ? length * sizeof(uint16_t) : length;
}
size_t GetPointerLength()
{
size_t byteSize = DataSize(this);
return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType);
}
uint16_t *GetData() const
{
return reinterpret_cast<uint16_t *>(ToUintPtr(this) + DATA_OFFSET);
@ -802,6 +816,7 @@ public:
ACCESSORS_NATIVE_FIELD(ConstantData, uint8_t, CONSTANT_DATA_OFFSET, SIZE);
CAST_CHECK(ConstantString, IsConstantString);
DECL_VISIT_OBJECT(RELOCTAED_DATA_OFFSET, ENTITY_ID_OFFSET);
static ConstantString *Cast(EcmaString *str)
{

View File

@ -71,6 +71,7 @@ private:
CUnorderedMultiMap<uint32_t, EcmaString *> table_;
const EcmaVM *vm_{nullptr};
friend class SnapshotProcessor;
friend class BaseDeserializer;
};
} // namespace panda::ecmascript

View File

@ -225,9 +225,6 @@ bool EcmaVM::Initialize()
GenerateInternalNativeMethods();
quickFixManager_ = new QuickFixManager();
snapshotEnv_ = new SnapshotEnv(this);
if (!WIN_OR_MAC_OR_IOS_PLATFORM) {
snapshotEnv_->Initialize();
}
if (options_.GetEnableAsmInterpreter()) {
thread_->GetCurrentEcmaContext()->LoadStubFile();
}

View File

@ -56,6 +56,17 @@ public:
return result;
}
JSHandle<JSTaggedValue> GetNoLazyEnvObjectByIndex(size_t index) const
{
JSHandle<JSTaggedValue> result = GetGlobalEnvObjectByIndex(index);
if (result->IsInternalAccessor()) {
JSThread *thread = GetJSThread();
AccessorData *accessor = AccessorData::Cast(result->GetTaggedObject());
accessor->CallInternalGet(thread, JSHandle<JSObject>::Cast(GetJSGlobalObject()));
}
return result;
}
size_t GetGlobalEnvFieldSize() const
{
return FINAL_INDEX;

View File

@ -525,6 +525,7 @@ enum class ConstantIndex : size_t {
READ_ONLY_CONSTANT_END = CONSTANT_END,
JSAPI_CONTAINERS_BEGIN = ARRAYLIST_FUNCTION_INDEX,
JSAPI_CONTAINERS_END = LINKED_LIST_ITERATOR_PROTOTYPE_INDEX,
// ...
};
// clang-format on
@ -600,6 +601,11 @@ public:
return static_cast<size_t>(ConstantIndex::CONSTANT_COUNT);
}
size_t GetEmptyArrayIndex() const
{
return static_cast<size_t>(ConstantIndex::EMPTY_ARRAY_OBJECT_INDEX);
}
size_t GetJSAPIContainersBegin() const
{
return static_cast<size_t>(ConstantIndex::JSAPI_CONTAINERS_BEGIN);

View File

@ -141,7 +141,7 @@ public:
return GetPeroidIndex() == PRE_DUMP_PEROID_INDEX;
}
DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength());
DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength(), GetLength());
DECL_DUMP()

View File

@ -34,6 +34,7 @@ public:
static constexpr size_t BIT_FIELD_OFFSET = TaggedObjectSize();
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_PRIMITIVE_OBJECT()
// define BitField
static constexpr size_t HAS_CHANGED_BITS = 1;

View File

@ -157,8 +157,11 @@ public:
ACCESSORS_PRIMITIVE_FIELD(Length, uint32_t, LENGTH_OFFSET, BIT_FIELD_OFFSET)
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
static constexpr size_t DATA_OFFSET = SIZE;
DECL_VISIT_ARRAY(DATA_OFFSET, 0, GetPointerLength());
// define BitField
static constexpr size_t SIGN_BITS = 1;
FIRST_BIT_FIELD(BitField, Sign, bool, SIGN_BITS)
@ -174,6 +177,18 @@ private:
{
return GetLength() == 1;
}
inline size_t GetPointerLength()
{
size_t byteSize = DataSize(this);
return AlignUp(byteSize, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)) / sizeof(JSTaggedType);
}
static inline size_t DataSize(BigInt *bigInt)
{
uint32_t length = bigInt->GetLength();
return length * sizeof(uint32_t);
}
};
class BigIntHelper {

View File

@ -424,7 +424,7 @@ void JSHClass::ShouldUpdateProtoClass(const JSThread *thread, const JSHandle<JST
if (!hclass->IsPrototype()) {
// There is no sharing in AOT hclass. Therefore, it is not necessary or possible to clone here.
if (!hclass->IsTS()) {
// If the objcet should be changed to the proto of an object,
// If the object should be changed to the proto of an object,
// the original hclass cannot be shared.
JSHandle<JSHClass> newProtoClass = JSHClass::Clone(thread, hclass);
JSTaggedValue layout = newProtoClass->GetLayout();

View File

@ -345,8 +345,8 @@ public:
using IsStableElementsBit = IsDictionaryBit::NextFlag; // 20
using HasConstructorBits = IsStableElementsBit::NextFlag; // 21
using IsClassConstructorOrPrototypeBit = HasConstructorBits::NextFlag; // 22
using GlobalConstOrBuiltinsObjectBit = IsClassConstructorOrPrototypeBit::NextFlag; // 23
using IsTSBit = GlobalConstOrBuiltinsObjectBit::NextFlag; // 24
using IsNativeBindingObjectBit = IsClassConstructorOrPrototypeBit::NextFlag; // 23
using IsTSBit = IsNativeBindingObjectBit::NextFlag; // 24
using LevelBit = IsTSBit::NextField<uint32_t, LEVEL_BTTFIELD_NUM>; // 25-29
using IsJSFunctionBit = LevelBit::NextFlag; // 30
using IsOptimizedBit = IsJSFunctionBit::NextFlag; // 31
@ -503,9 +503,9 @@ public:
SetIsPrototype(flag);
}
inline void SetGlobalConstOrBuiltinsObject(bool flag) const
inline void SetIsNativeBindingObject(bool flag) const
{
GlobalConstOrBuiltinsObjectBit::Set<uint32_t>(flag, GetBitFieldAddr());
IsNativeBindingObjectBit::Set<uint32_t>(flag, GetBitFieldAddr());
}
inline void SetIsDictionaryMode(bool flag) const
@ -1259,10 +1259,10 @@ public:
return IsClassConstructorOrPrototypeBit::Decode(bits) && IsPrototype();
}
inline bool IsGlobalConstOrBuiltinsObject() const
inline bool IsNativeBindingObject() const
{
uint32_t bits = GetBitField();
return GlobalConstOrBuiltinsObjectBit::Decode(bits);
return IsNativeBindingObjectBit::Decode(bits);
}
inline bool IsDictionaryMode() const

View File

@ -24,6 +24,7 @@
#include "ecmascript/js_hclass.h"
#include "ecmascript/js_native_pointer.h"
#include "ecmascript/js_tagged_value.h"
#include "ecmascript/mem/layout_visitor.h"
#include "ecmascript/mem/slots.h"
#include "ecmascript/mem/visitor.h"
#include "ecmascript/method.h"
@ -356,10 +357,11 @@ public:
DECL_VISIT_OBJECT(HASH_OFFSET, SIZE);
template <VisitType visitType>
void VisitObjects(const EcmaObjectRangeVisitor &visitor)
{
// no field in this object
VisitRangeSlot(visitor);
VisitRangeSlot<visitType>(visitor);
}
};

View File

@ -399,8 +399,7 @@ public:
return val;
}
DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength());
DECL_VISIT_NATIVE_FIELD(GetLastOffset() - JSTaggedValue::TaggedTypeSize() * RESERVED_POOL_LENGTH, GetLastOffset());
DECL_VISIT_ARRAY(DATA_OFFSET, GetCacheLength(), GetLength());
DECL_DUMP()

View File

@ -33,6 +33,7 @@ public:
static constexpr size_t BIT_FIELD_OFFSET = TaggedObjectSize();
ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_PRIMITIVE_OBJECT()
// define BitField
static constexpr size_t IS_DETECTOR_INVALID_BITS = 1;

View File

@ -48,6 +48,11 @@ void BumpPointerAllocator::Reset(uintptr_t begin, uintptr_t end, uintptr_t top)
ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(top_), (end_ - top_));
}
void BumpPointerAllocator::ResetTopPointer(uintptr_t top)
{
top_ = top;
}
uintptr_t BumpPointerAllocator::Allocate(size_t size)
{
ASSERT(size != 0);
@ -141,6 +146,11 @@ void FreeListAllocator::ResetBumpPointer(uintptr_t begin, uintptr_t end, uintptr
bpAllocator_.Reset(begin, end, top);
}
void FreeListAllocator::ResetTopPointer(uintptr_t top)
{
bpAllocator_.ResetTopPointer(top);
}
// The object will be marked with poison after being put into the freelist when is_asan is true.
void FreeListAllocator::Free(uintptr_t begin, size_t size, bool isAdd)
{

View File

@ -45,6 +45,7 @@ public:
inline void Reset();
inline void Reset(uintptr_t begin, uintptr_t end);
inline void Reset(uintptr_t begin, uintptr_t end, uintptr_t top);
inline void ResetTopPointer(uintptr_t top);
inline uintptr_t Allocate(size_t size);
uintptr_t GetTop() const
@ -106,6 +107,7 @@ public:
inline void FillBumpPointer();
inline void ResetBumpPointer(uintptr_t begin, uintptr_t end, uintptr_t top);
inline void ResetTopPointer(uintptr_t top);
inline void Free(uintptr_t begin, size_t size, bool isAdd = true);

View File

@ -85,6 +85,12 @@ public:
return error_;
}
inline uint64_t GetU64(size_t offset) const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
return *reinterpret_cast<uint64_t *>(buf_ + offset);
}
inline uint32_t GetU32(size_t offset) const
{
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_MEM_LAYOUT_VISITOR_H
#define ECMASCRIPT_MEM_LAYOUT_VISITOR_H
#include <functional>
#include "ecmascript/js_hclass.h"
#include "ecmascript/mem/slots.h"
namespace panda::ecmascript {
template <VisitType visitType, size_t size>
class JSObjectBodyIterator {
public:
static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
auto hclass = root->SynchronizedGetClass();
auto objSize = hclass->GetObjectSize();
if (objSize > size) {
if (hclass->IsAllTaggedProp()) {
IteratorRange(root, visitor, size, objSize, VisitObjectArea::NORMAL);
} else {
IteratorRange(root, visitor, size, objSize, VisitObjectArea::IN_OBJECT);
}
}
}
static inline void IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor,
size_t start, size_t end, VisitObjectArea area)
{
visitor(root, ObjectSlot(ToUintPtr(root) + start), ObjectSlot(ToUintPtr(root) + end), area);
}
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_MEM_LAYOUT_VISITOR_H

View File

@ -59,14 +59,13 @@ public:
}
}
void VisitRangeSlot([[maybe_unused]] const EcmaObjectRangeVisitor &v)
template <VisitType visitType>
void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor)
{
// left blank deliberately,only need to visit TaggedObject type object.
}
void VisitObjects([[maybe_unused]] const EcmaObjectRangeVisitor &visitor) const
{
// left blank deliberately,only need to visit TaggedObject type object.
if (visitType == VisitType::ALL_VISIT) {
visitor(this, ObjectSlot(ToUintPtr(this)),
ObjectSlot(ToUintPtr(this) + GetMachineCodeObjectSize()), VisitObjectArea::RAW_DATA);
}
}
size_t GetMachineCodeObjectSize()

View File

@ -18,6 +18,7 @@
#include <cstdint>
#include "ecmascript/byte_array.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/js_async_from_sync_iterator.h"
#include "ecmascript/global_env.h"
@ -91,11 +92,11 @@
#include "ecmascript/js_set_iterator.h"
#include "ecmascript/js_string_iterator.h"
#include "ecmascript/js_typed_array.h"
#include "ecmascript/byte_array.h"
#include "ecmascript/js_weak_container.h"
#include "ecmascript/jspandafile/class_info_extractor.h"
#include "ecmascript/jspandafile/program_object.h"
#include "ecmascript/js_weak_ref.h"
#include "ecmascript/marker_cell.h"
#include "ecmascript/mem/machine_code.h"
#include "ecmascript/mem/mem.h"
#include "ecmascript/mem/slots.h"
@ -139,170 +140,170 @@ public:
case JSType::JS_TERMINATION_ERROR:
case JSType::JS_ASYNCITERATOR:
case JSType::JS_ITERATOR:
JSObject::Cast(object)->VisitRangeSlot(visitor);
JSObject::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ASYNC_FROM_SYNC_ITERATOR:
JSAsyncFromSyncIterator::Cast(object)->VisitRangeSlot(visitor);
JSAsyncFromSyncIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_GLOBAL_OBJECT:
JSGlobalObject::Cast(object)->VisitRangeSlot(visitor);
JSGlobalObject::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_FUNCTION_BASE: {
auto jsFunctionBase = JSFunctionBase::Cast(object);
jsFunctionBase->VisitRangeSlot(visitor);
jsFunctionBase->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_FUNCTION: {
auto jsFunction = JSFunction::Cast(object);
jsFunction->VisitRangeSlot(visitor);
jsFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_GENERATOR_FUNCTION: {
auto jsGeneratorFunction = JSGeneratorFunction::Cast(object);
jsGeneratorFunction->VisitRangeSlot(visitor);
jsGeneratorFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ASYNC_GENERATOR_FUNCTION: {
auto jsGeneratorFunction = JSAsyncGeneratorFunction::Cast(object);
jsGeneratorFunction->VisitRangeSlot(visitor);
jsGeneratorFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROXY_REVOC_FUNCTION: {
auto jsProxyRevocFunction = JSProxyRevocFunction::Cast(object);
jsProxyRevocFunction->VisitRangeSlot(visitor);
jsProxyRevocFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_REACTIONS_FUNCTION: {
auto jsPromiseReactionsFunction = JSPromiseReactionsFunction::Cast(object);
jsPromiseReactionsFunction->VisitRangeSlot(visitor);
jsPromiseReactionsFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_EXECUTOR_FUNCTION: {
auto jsPromiseExecutorFunction = JSPromiseExecutorFunction::Cast(object);
jsPromiseExecutorFunction->VisitRangeSlot(visitor);
jsPromiseExecutorFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ASYNC_FROM_SYNC_ITER_UNWARP_FUNCTION: {
auto jsAsyncFromSyncIterUnwarpFunction = JSAsyncFromSyncIterUnwarpFunction::Cast(object);
jsAsyncFromSyncIterUnwarpFunction->VisitRangeSlot(visitor);
jsAsyncFromSyncIterUnwarpFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: {
auto jsPromiseAllResolveElementFunction = JSPromiseAllResolveElementFunction::Cast(object);
jsPromiseAllResolveElementFunction->VisitRangeSlot(visitor);
jsPromiseAllResolveElementFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ASYNC_GENERATOR_RESUME_NEXT_RETURN_PROCESSOR_RST_FTN: {
auto jsAsyGeneratorRseNextRtnProRstFtn = JSAsyncGeneratorResNextRetProRstFtn::Cast(object);
jsAsyGeneratorRseNextRtnProRstFtn->VisitRangeSlot(visitor);
jsAsyGeneratorRseNextRtnProRstFtn->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_ANY_REJECT_ELEMENT_FUNCTION: {
auto jsPromiseAnyRejectElementFunction = JSPromiseAnyRejectElementFunction::Cast(object);
jsPromiseAnyRejectElementFunction->VisitRangeSlot(visitor);
jsPromiseAnyRejectElementFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_ALL_SETTLED_ELEMENT_FUNCTION: {
auto jsPromiseAllSettledElementFunction = JSPromiseAllSettledElementFunction::Cast(object);
jsPromiseAllSettledElementFunction->VisitRangeSlot(visitor);
jsPromiseAllSettledElementFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_FINALLY_FUNCTION: {
auto jsPromiseFinallyFunction = JSPromiseFinallyFunction::Cast(object);
jsPromiseFinallyFunction->VisitRangeSlot(visitor);
jsPromiseFinallyFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_PROMISE_VALUE_THUNK_OR_THROWER_FUNCTION: {
auto jsPromiseValueThunkOrThrowerFunction = JSPromiseValueThunkOrThrowerFunction::Cast(object);
jsPromiseValueThunkOrThrowerFunction->VisitRangeSlot(visitor);
jsPromiseValueThunkOrThrowerFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ASYNC_FUNCTION: {
auto jsAsyncFunction = JSAsyncFunction::Cast(object);
jsAsyncFunction->VisitRangeSlot(visitor);
jsAsyncFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION: {
auto jsAsyncAwaitStatusFunction = JSAsyncAwaitStatusFunction::Cast(object);
jsAsyncAwaitStatusFunction->VisitRangeSlot(visitor);
jsAsyncAwaitStatusFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_REG_EXP:
JSRegExp::Cast(object)->VisitRangeSlot(visitor);
JSRegExp::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_SET:
JSSet::Cast(object)->VisitRangeSlot(visitor);
JSSet::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_MAP:
JSMap::Cast(object)->VisitRangeSlot(visitor);
JSMap::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_WEAK_MAP:
JSWeakMap::Cast(object)->VisitRangeSlot(visitor);
JSWeakMap::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_WEAK_SET:
JSWeakSet::Cast(object)->VisitRangeSlot(visitor);
JSWeakSet::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_WEAK_REF:
JSWeakRef::Cast(object)->VisitRangeSlot(visitor);
JSWeakRef::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_FINALIZATION_REGISTRY:
JSFinalizationRegistry::Cast(object)->VisitRangeSlot(visitor);
JSFinalizationRegistry::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::CELL_RECORD:
CellRecord::Cast(object)->VisitRangeSlot(visitor);
CellRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_DATE:
JSDate::Cast(object)->VisitRangeSlot(visitor);
JSDate::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_FORIN_ITERATOR:
JSForInIterator::Cast(object)->VisitRangeSlot(visitor);
JSForInIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_MAP_ITERATOR:
JSMapIterator::Cast(object)->VisitRangeSlot(visitor);
JSMapIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_SET_ITERATOR:
JSSetIterator::Cast(object)->VisitRangeSlot(visitor);
JSSetIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_REG_EXP_ITERATOR:
JSRegExpIterator::Cast(object)->VisitRangeSlot(visitor);
JSRegExpIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ARRAY_ITERATOR:
JSArrayIterator::Cast(object)->VisitRangeSlot(visitor);
JSArrayIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_STRING_ITERATOR:
JSStringIterator::Cast(object)->VisitRangeSlot(visitor);
JSStringIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ARRAY_BUFFER:
JSArrayBuffer::Cast(object)->VisitRangeSlot(visitor);
JSArrayBuffer::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_SHARED_ARRAY_BUFFER:
JSArrayBuffer::Cast(object)->VisitRangeSlot(visitor);
JSArrayBuffer::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_PROMISE:
JSPromise::Cast(object)->VisitRangeSlot(visitor);
JSPromise::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_DATA_VIEW:
JSDataView::Cast(object)->VisitRangeSlot(visitor);
JSDataView::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_BOUND_FUNCTION: {
auto jsBoundFunction = JSBoundFunction::Cast(object);
jsBoundFunction->VisitRangeSlot(visitor);
jsBoundFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_ARGUMENTS:
JSArguments::Cast(object)->VisitRangeSlot(visitor);
JSArguments::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_GENERATOR_OBJECT:
JSGeneratorObject::Cast(object)->VisitRangeSlot(visitor);
JSGeneratorObject::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ASYNC_GENERATOR_OBJECT:
JSAsyncGeneratorObject::Cast(object)->VisitRangeSlot(visitor);
JSAsyncGeneratorObject::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ASYNC_FUNC_OBJECT:
JSAsyncFuncObject::Cast(object)->VisitRangeSlot(visitor);
JSAsyncFuncObject::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_ARRAY:
JSArray::Cast(object)->VisitRangeSlot(visitor);
JSArray::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_TYPED_ARRAY:
case JSType::JS_INT8_ARRAY:
@ -316,36 +317,46 @@ public:
case JSType::JS_FLOAT64_ARRAY:
case JSType::JS_BIGINT64_ARRAY:
case JSType::JS_BIGUINT64_ARRAY:
JSTypedArray::Cast(object)->VisitRangeSlot(visitor);
JSTypedArray::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::BYTE_ARRAY:
if (visitType == VisitType::ALL_VISIT) {
ByteArray::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::JS_PRIMITIVE_REF:
JSPrimitiveRef::Cast(object)->VisitRangeSlot(visitor);
JSPrimitiveRef::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_PROXY: {
auto jsProxy = JSProxy::Cast(object);
jsProxy->VisitRangeSlot(visitor);
jsProxy->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::HCLASS:
// semi gc is not needed to visit hclass
if (visitType != VisitType::SEMI_GC_VISIT) {
JSHClass::Cast(object)->VisitRangeSlot(visitor);
JSHClass::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::LINE_STRING:
if (visitType == VisitType::ALL_VISIT) {
LineEcmaString::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::CONSTANT_STRING:
if (visitType == VisitType::ALL_VISIT) {
ConstantString::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::TREE_STRING:
TreeEcmaString::Cast(object)->VisitRangeSlot(visitor);
TreeEcmaString::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::SLICED_STRING:
SlicedString::Cast(object)->VisitRangeSlot(visitor);
SlicedString::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_NATIVE_POINTER:
if (visitType == VisitType::SNAPSHOT_VISIT) {
JSNativePointer::Cast(object)->VisitRangeSlotForNative(visitor);
if ((visitType == VisitType::SNAPSHOT_VISIT) || (visitType == VisitType::ALL_VISIT)) {
JSNativePointer::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::TAGGED_ARRAY:
@ -355,282 +366,297 @@ public:
case JSType::AOT_LITERAL_INFO:
case JSType::VTABLE:
case JSType::COW_TAGGED_ARRAY:
TaggedArray::Cast(object)->VisitRangeSlot(visitor);
TaggedArray::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::CONSTANT_POOL:
ConstantPool::Cast(object)->VisitRangeSlot(visitor);
ConstantPool::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROFILE_TYPE_INFO:
ProfileTypeInfo::Cast(object)->VisitRangeSlot(visitor);
ProfileTypeInfo::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::GLOBAL_ENV:
GlobalEnv::Cast(object)->VisitRangeSlot(visitor);
GlobalEnv::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::ACCESSOR_DATA:
case JSType::INTERNAL_ACCESSOR:
AccessorData::Cast(object)->VisitRangeSlot(visitor);
AccessorData::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::SYMBOL:
JSSymbol::Cast(object)->VisitRangeSlot(visitor);
JSSymbol::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_GENERATOR_CONTEXT:
GeneratorContext::Cast(object)->VisitRangeSlot(visitor);
GeneratorContext::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROTOTYPE_HANDLER:
PrototypeHandler::Cast(object)->VisitRangeSlot(visitor);
PrototypeHandler::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TRANSITION_HANDLER:
TransitionHandler::Cast(object)->VisitRangeSlot(visitor);
TransitionHandler::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TRANS_WITH_PROTO_HANDLER:
TransWithProtoHandler::Cast(object)->VisitRangeSlot(visitor);
TransWithProtoHandler::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::STORE_TS_HANDLER:
StoreTSHandler::Cast(object)->VisitRangeSlot(visitor);
StoreTSHandler::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROPERTY_BOX:
PropertyBox::Cast(object)->VisitRangeSlot(visitor);
PropertyBox::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROTO_CHANGE_MARKER:
if (visitType == VisitType::ALL_VISIT) {
ProtoChangeMarker::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::MARKER_CELL:
if (visitType == VisitType::ALL_VISIT) {
MarkerCell::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::TRACK_INFO:
TrackInfo::Cast(object)->VisitRangeSlot(visitor);
TrackInfo::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROTOTYPE_INFO:
ProtoChangeDetails::Cast(object)->VisitRangeSlot(visitor);
ProtoChangeDetails::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROMISE_CAPABILITY:
PromiseCapability::Cast(object)->VisitRangeSlot(visitor);
PromiseCapability::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::ASYNC_GENERATOR_REQUEST:
AsyncGeneratorRequest::Cast(object)->VisitRangeSlot(visitor);
AsyncGeneratorRequest::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::ASYNC_ITERATOR_RECORD:
AsyncIteratorRecord::Cast(object)->VisitRangeSlot(visitor);
AsyncIteratorRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROMISE_RECORD:
PromiseRecord::Cast(object)->VisitRangeSlot(visitor);
PromiseRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::RESOLVING_FUNCTIONS_RECORD:
ResolvingFunctionsRecord::Cast(object)->VisitRangeSlot(visitor);
ResolvingFunctionsRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROMISE_REACTIONS:
PromiseReaction::Cast(object)->VisitRangeSlot(visitor);
PromiseReaction::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROMISE_ITERATOR_RECORD:
PromiseIteratorRecord::Cast(object)->VisitRangeSlot(visitor);
PromiseIteratorRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::MICRO_JOB_QUEUE:
job::MicroJobQueue::Cast(object)->VisitRangeSlot(visitor);
job::MicroJobQueue::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PENDING_JOB:
job::PendingJob::Cast(object)->VisitRangeSlot(visitor);
job::PendingJob::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::COMPLETION_RECORD:
CompletionRecord::Cast(object)->VisitRangeSlot(visitor);
CompletionRecord::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::PROGRAM:
Program::Cast(object)->VisitRangeSlot(visitor);
Program::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_INTL:
JSIntl::Cast(object)->VisitRangeSlot(visitor);
JSIntl::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_NUMBER_FORMAT:
JSNumberFormat::Cast(object)->VisitRangeSlot(visitor);
JSNumberFormat::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_LOCALE:
JSLocale::Cast(object)->VisitRangeSlot(visitor);
JSLocale::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_DATE_TIME_FORMAT:
JSDateTimeFormat::Cast(object)->VisitRangeSlot(visitor);
JSDateTimeFormat::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_RELATIVE_TIME_FORMAT:
JSRelativeTimeFormat::Cast(object)->VisitRangeSlot(visitor);
JSRelativeTimeFormat::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_INTL_BOUND_FUNCTION: {
auto jsIntlBoundFunction = JSIntlBoundFunction::Cast(object);
jsIntlBoundFunction->VisitRangeSlot(visitor);
jsIntlBoundFunction->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_REALM:
JSRealm::Cast(object)->VisitRangeSlot(visitor);
JSRealm::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_COLLATOR:
JSCollator::Cast(object)->VisitRangeSlot(visitor);
JSCollator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_PLURAL_RULES:
JSPluralRules::Cast(object)->VisitRangeSlot(visitor);
JSPluralRules::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_DISPLAYNAMES:
JSDisplayNames::Cast(object)->VisitRangeSlot(visitor);
JSDisplayNames::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_LIST_FORMAT:
JSListFormat::Cast(object)->VisitRangeSlot(visitor);
JSListFormat::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::MACHINE_CODE_OBJECT:
MachineCode::Cast(object)->VisitRangeSlot(visitor);
MachineCode::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::CLASS_INFO_EXTRACTOR: {
auto classInfoExtractor = ClassInfoExtractor::Cast(object);
classInfoExtractor->VisitRangeSlot(visitor);
classInfoExtractor->VisitRangeSlot<visitType>(visitor);
break;
}
case JSType::JS_API_QUEUE:
JSAPIQueue::Cast(object)->VisitRangeSlot(visitor);
JSAPIQueue::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_QUEUE_ITERATOR:
JSAPIQueueIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIQueueIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_ARRAY_LIST:
JSAPIArrayList::Cast(object)->VisitRangeSlot(visitor);
JSAPIArrayList::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_ARRAYLIST_ITERATOR:
JSAPIArrayListIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIArrayListIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIGHT_WEIGHT_MAP:
JSAPILightWeightMap::Cast(object)->VisitRangeSlot(visitor);
JSAPILightWeightMap::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIGHT_WEIGHT_MAP_ITERATOR:
JSAPILightWeightMapIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPILightWeightMapIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIGHT_WEIGHT_SET:
JSAPILightWeightSet::Cast(object)->VisitRangeSlot(visitor);
JSAPILightWeightSet::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIGHT_WEIGHT_SET_ITERATOR:
JSAPILightWeightSetIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPILightWeightSetIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_OBJECT_TYPE:
TSObjectType::Cast(object)->VisitRangeSlot(visitor);
TSObjectType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_CLASS_TYPE:
TSClassType::Cast(object)->VisitRangeSlot(visitor);
TSClassType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_UNION_TYPE:
TSUnionType::Cast(object)->VisitRangeSlot(visitor);
TSUnionType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_INTERFACE_TYPE:
TSInterfaceType::Cast(object)->VisitRangeSlot(visitor);
TSInterfaceType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_CLASS_INSTANCE_TYPE:
break;
case JSType::TS_FUNCTION_TYPE:
TSFunctionType::Cast(object)->VisitRangeSlot(visitor);
TSFunctionType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::TS_ARRAY_TYPE:
if (visitType == VisitType::ALL_VISIT) {
TSArrayType::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::TS_ITERATOR_INSTANCE_TYPE:
if (visitType == VisitType::ALL_VISIT) {
TSIteratorInstanceType::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::TS_NAMESPACE_TYPE:
TSNamespaceType::Cast(object)->VisitRangeSlot(visitor);
TSNamespaceType::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::RB_TREENODE:
RBTreeNode::Cast(object)->VisitRangeSlot(visitor);
RBTreeNode::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::LINKED_NODE:
LinkedNode::Cast(object)->VisitRangeSlot(visitor);
LinkedNode::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_HASH_MAP:
JSAPIHashMap::Cast(object)->VisitRangeSlot(visitor);
JSAPIHashMap::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_HASH_SET:
JSAPIHashSet::Cast(object)->VisitRangeSlot(visitor);
JSAPIHashSet::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_HASHMAP_ITERATOR:
JSAPIHashMapIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIHashMapIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_HASHSET_ITERATOR:
JSAPIHashSetIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIHashSetIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_TREE_MAP:
JSAPITreeMap::Cast(object)->VisitRangeSlot(visitor);
JSAPITreeMap::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_TREE_SET:
JSAPITreeSet::Cast(object)->VisitRangeSlot(visitor);
JSAPITreeSet::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_TREEMAP_ITERATOR:
JSAPITreeMapIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPITreeMapIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_TREESET_ITERATOR:
JSAPITreeSetIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPITreeSetIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_PLAIN_ARRAY:
JSAPIPlainArray::Cast(object)->VisitRangeSlot(visitor);
JSAPIPlainArray::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_PLAIN_ARRAY_ITERATOR:
JSAPIPlainArrayIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIPlainArrayIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_DEQUE:
JSAPIDeque::Cast(object)->VisitRangeSlot(visitor);
JSAPIDeque::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_DEQUE_ITERATOR:
JSAPIDequeIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIDequeIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_STACK:
JSAPIStack::Cast(object)->VisitRangeSlot(visitor);
JSAPIStack::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_STACK_ITERATOR:
JSAPIStackIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIStackIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_VECTOR:
JSAPIVector::Cast(object)->VisitRangeSlot(visitor);
JSAPIVector::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_VECTOR_ITERATOR:
JSAPIVectorIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIVectorIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIST:
JSAPIList::Cast(object)->VisitRangeSlot(visitor);
JSAPIList::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LINKED_LIST:
JSAPILinkedList::Cast(object)->VisitRangeSlot(visitor);
JSAPILinkedList::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LIST_ITERATOR:
JSAPIListIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPIListIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_API_LINKED_LIST_ITERATOR:
JSAPILinkedListIterator::Cast(object)->VisitRangeSlot(visitor);
JSAPILinkedListIterator::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::BIGINT:
if (visitType == VisitType::ALL_VISIT) {
BigInt::Cast(object)->VisitRangeSlot<visitType>(visitor);
}
break;
case JSType::SOURCE_TEXT_MODULE_RECORD:
SourceTextModule::Cast(object)->VisitRangeSlot(visitor);
SourceTextModule::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::IMPORTENTRY_RECORD:
ImportEntry::Cast(object)->VisitRangeSlot(visitor);
ImportEntry::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::LOCAL_EXPORTENTRY_RECORD:
LocalExportEntry::Cast(object)->VisitRangeSlot(visitor);
LocalExportEntry::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::INDIRECT_EXPORTENTRY_RECORD:
IndirectExportEntry::Cast(object)->VisitRangeSlot(visitor);
IndirectExportEntry::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::STAR_EXPORTENTRY_RECORD:
StarExportEntry::Cast(object)->VisitRangeSlot(visitor);
StarExportEntry::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::RESOLVEDBINDING_RECORD:
ResolvedBinding::Cast(object)->VisitRangeSlot(visitor);
ResolvedBinding::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::RESOLVEDINDEXBINDING_RECORD:
ResolvedIndexBinding::Cast(object)->VisitRangeSlot(visitor);
ResolvedIndexBinding::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_MODULE_NAMESPACE:
ModuleNamespace::Cast(object)->VisitRangeSlot(visitor);
ModuleNamespace::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_CJS_EXPORTS:
CjsExports::Cast(object)->VisitRangeSlot(visitor);
CjsExports::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_CJS_MODULE:
CjsModule::Cast(object)->VisitRangeSlot(visitor);
CjsModule::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::JS_CJS_REQUIRE:
CjsRequire::Cast(object)->VisitRangeSlot(visitor);
CjsRequire::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::METHOD:
Method::Cast(object)->VisitRangeSlot(visitor);
Method::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
case JSType::CLASS_LITERAL:
ClassLiteral::Cast(object)->VisitRangeSlot(visitor);
ClassLiteral::Cast(object)->VisitRangeSlot<visitType>(visitor);
break;
default:
LOG_ECMA(FATAL) << "this branch is unreachable, type: " << static_cast<size_t>(type);

View File

@ -36,9 +36,7 @@ bool ParallelEvacuator::VisitBodyInObj(
TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback callback)
{
auto hclass = root->GetClass();
if (hclass->IsAllTaggedProp()) {
return false;
}
ASSERT(!hclass->IsAllTaggedProp());
int index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
TaggedObject *dst = hclass->GetLayout().GetTaggedObject();

View File

@ -74,8 +74,7 @@ void NonMovableMarker::ProcessMarkStack(uint32_t threadId)
Region *rootRegion = Region::ObjectAddressToRange(root);
bool needBarrier = isFullMark && !rootRegion->InYoungSpaceOrCSet();
if (area == VisitObjectArea::IN_OBJECT) {
auto hclass = root->SynchronizedGetClass();
if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, needBarrier, cb)) {
if (VisitBodyInObj(root, start, end, needBarrier, cb)) {
return;
}
}
@ -110,8 +109,7 @@ void NonMovableMarker::ProcessIncrementalMarkStack(uint32_t threadId, uint32_t m
visitAddrNum += end.SlotAddress() - start.SlotAddress();
bool needBarrier = isFullMark && !rootRegion->InYoungSpaceOrCSet();
if (area == VisitObjectArea::IN_OBJECT) {
auto hclass = root->SynchronizedGetClass();
if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, needBarrier, cb)) {
if (VisitBodyInObj(root, start, end, needBarrier, cb)) {
return;
}
}
@ -156,8 +154,7 @@ void SemiGCMarker::ProcessMarkStack(uint32_t threadId)
auto visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
VisitObjectArea area) {
if (area == VisitObjectArea::IN_OBJECT) {
auto hclass = root->SynchronizedGetClass();
if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, cb)) {
if (VisitBodyInObj(root, start, end, cb)) {
return;
}
}
@ -184,8 +181,7 @@ void CompressGCMarker::ProcessMarkStack(uint32_t threadId)
auto visitor = [this, threadId, cb](TaggedObject *root, ObjectSlot start, ObjectSlot end,
VisitObjectArea area) {
if (area == VisitObjectArea::IN_OBJECT) {
auto hclass = root->SynchronizedGetClass();
if (!hclass->IsAllTaggedProp() && VisitBodyInObj(root, start, end, cb)) {
if (VisitBodyInObj(root, start, end, cb)) {
return;
}
}

View File

@ -232,6 +232,13 @@ public:
return reinterpret_cast<Region *>(objAddress & ~DEFAULT_REGION_MASK);
}
static size_t GetRegionAvailableSize()
{
size_t regionHeaderSize = AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
size_t bitsetSize = GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE - regionHeaderSize);
return DEFAULT_REGION_SIZE - regionHeaderSize - bitsetSize;
}
void ClearMembers()
{
if (lock_ != nullptr) {

View File

@ -44,6 +44,12 @@ public:
*reinterpret_cast<JSTaggedType *>(slotAddress_) = value;
}
void UpdateWeak(uintptr_t value)
{
// NOLINTNEXTLINE(clang-analyzer-core.NullDereference)
*reinterpret_cast<JSTaggedType *>(slotAddress_) = value | JSTaggedValue::TAG_WEAK;
}
void Clear()
{
*reinterpret_cast<JSTaggedType *>(slotAddress_) = JSTaggedValue::VALUE_UNDEFINED;
@ -74,6 +80,13 @@ public:
return ret;
}
ObjectSlot operator+=(size_t length)
{
ObjectSlot ret = *this;
slotAddress_ += sizeof(JSTaggedType) * length;
return ret;
}
uintptr_t SlotAddress() const
{
return slotAddress_;

View File

@ -50,6 +50,11 @@ void SparseSpace::Reset()
liveObjectSize_ = 0;
}
void SparseSpace::ResetTopPointer(uintptr_t top)
{
allocator_->ResetTopPointer(top);
}
uintptr_t SparseSpace::Allocate(size_t size, bool allowGC)
{
auto object = allocator_->Allocate(size);

View File

@ -61,6 +61,7 @@ public:
void Initialize() override;
void Reset();
void ResetTopPointer(uintptr_t top);
uintptr_t Allocate(size_t size, bool allowGC = true);
bool Expand();

View File

@ -43,6 +43,7 @@ public:
}
static constexpr int HCLASS_OFFSET = 0;
static constexpr int SIZE = sizeof(MarkWordType);
JSThread* GetJSThread() const;

View File

@ -29,17 +29,16 @@ void VerifyObjectVisitor::VisitAllObjects(TaggedObject *obj)
VisitObjectArea area) {
if (area == VisitObjectArea::IN_OBJECT) {
auto hclass = root->GetClass();
if (!hclass->IsAllTaggedProp()) {
int index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
auto attr = layout->GetAttr(index++);
if (attr.IsTaggedRep()) {
VisitObject(slot);
}
ASSERT(!hclass->IsAllTaggedProp());
int index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
auto attr = layout->GetAttr(index++);
if (attr.IsTaggedRep()) {
VisitObject(slot);
}
return;
}
return;
}
for (ObjectSlot slot = start; slot < end; slot++) {
VisitObject(slot);

View File

@ -33,10 +33,11 @@ enum class Root {
enum class VisitObjectArea {
NORMAL,
NATIVE_POINTER,
IN_OBJECT
IN_OBJECT,
RAW_DATA
};
enum class VisitType : size_t { SEMI_GC_VISIT, OLD_GC_VISIT, SNAPSHOT_VISIT };
enum class VisitType : size_t { SEMI_GC_VISIT, OLD_GC_VISIT, SNAPSHOT_VISIT, ALL_VISIT };
using RootVisitor = std::function<void(Root type, ObjectSlot p)>;
using RootRangeVisitor = std::function<void(Root type, ObjectSlot start, ObjectSlot end)>;
@ -45,5 +46,130 @@ using RootBaseAndDerivedVisitor =
using EcmaObjectRangeVisitor = std::function<void(TaggedObject *root, ObjectSlot start, ObjectSlot end,
VisitObjectArea area)>;
using WeakRootVisitor = std::function<TaggedObject *(TaggedObject *p)>;
template <VisitType visitType, size_t size>
class PrimitiveObjectBodyIterator {
public:
static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
if (visitType == VisitType::ALL_VISIT) {
size_t hclassEnd = sizeof(JSTaggedType);
visitor(root, ObjectSlot(ToUintPtr(root)),
ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL);
if (size > hclassEnd) {
visitor(root, ObjectSlot(ToUintPtr(root) + hclassEnd),
ObjectSlot(ToUintPtr(root) + size), VisitObjectArea::RAW_DATA);
}
}
}
};
template <VisitType visitType, size_t startOffset, size_t endOffset, size_t size>
class ObjectBodyIterator {
public:
template <VisitObjectArea area, bool visitHClass>
static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t startSize)
{
if (visitType == VisitType::ALL_VISIT) {
if (visitHClass) {
IterateHClass(root, visitor);
}
IterateBefore(root, visitor, startSize);
}
visitor(root, ObjectSlot(ToUintPtr(root) + startOffset),
ObjectSlot(ToUintPtr(root) + endOffset), area);
if (visitType == VisitType::ALL_VISIT) {
IterateAfter(root, visitor);
}
}
static inline void IterateRefBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
IterateBody<VisitObjectArea::NORMAL, true>(root, visitor, sizeof(JSTaggedType));
}
static inline void IterateNativeBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
IterateBody<VisitObjectArea::NATIVE_POINTER, true>(root, visitor, sizeof(JSTaggedType));
}
static inline void IterateRefBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t parentSize)
{
IterateBody<VisitObjectArea::NORMAL, false>(root, visitor, parentSize);
}
static inline void IterateHClass(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
size_t hclassEnd = sizeof(JSTaggedType);
visitor(root, ObjectSlot(ToUintPtr(root)),
ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL);
}
static inline void IterateBefore(TaggedObject *root, const EcmaObjectRangeVisitor& visitor, size_t startSize)
{
if (startOffset > startSize) {
IteratorRange(root, visitor, startSize, startOffset);
}
}
static inline void IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
if (size > endOffset) {
IteratorRange(root, visitor, endOffset, size);
}
}
static inline void IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor,
size_t start, size_t end)
{
visitor(root, ObjectSlot(ToUintPtr(root) + start),
ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA);
}
};
template <VisitType visitType, size_t startOffset>
class ArrayBodyIterator {
public:
static inline void IterateBody(TaggedObject *root, const EcmaObjectRangeVisitor& visitor,
size_t refLength, size_t length)
{
if (visitType == VisitType::ALL_VISIT) {
IterateBefore(root, visitor);
}
if (LIKELY(refLength != 0)) {
size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize();
visitor(root, ObjectSlot(ToUintPtr(root) + startOffset),
ObjectSlot(ToUintPtr(root) + endOffset), VisitObjectArea::NORMAL);
}
if (visitType == VisitType::ALL_VISIT) {
IterateAfter(root, visitor, refLength, length);
}
}
static inline void IterateBefore(TaggedObject *root, const EcmaObjectRangeVisitor& visitor)
{
size_t hclassEnd = sizeof(JSTaggedType);
ASSERT(startOffset > hclassEnd);
visitor(root, ObjectSlot(ToUintPtr(root)), ObjectSlot(ToUintPtr(root) + hclassEnd), VisitObjectArea::NORMAL);
IteratorRange(root, visitor, hclassEnd, startOffset);
}
static inline void IterateAfter(TaggedObject *root, const EcmaObjectRangeVisitor& visitor,
size_t refLength, size_t length)
{
if (length > refLength) {
size_t endOffset = startOffset + refLength * JSTaggedValue::TaggedTypeSize();
size_t size = startOffset + length * JSTaggedValue::TaggedTypeSize();
IteratorRange(root, visitor, endOffset, size);
}
}
static inline void IteratorRange(TaggedObject *root, const EcmaObjectRangeVisitor& visitor,
size_t start, size_t end)
{
visitor(root, ObjectSlot(ToUintPtr(root) + start),
ObjectSlot(ToUintPtr(root) + end), VisitObjectArea::RAW_DATA);
}
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_MEM_VISITOR_H

View File

@ -81,6 +81,8 @@
#include "ecmascript/pgo_profiler/pgo_profiler_manager.h"
#include "ecmascript/platform/file.h"
#include "ecmascript/regexp/regexp_parser.h"
#include "ecmascript/serializer/base_deserializer.h"
#include "ecmascript/serializer/value_serializer.h"
#include "ecmascript/tagged_array.h"
#include "ecmascript/js_weak_container.h"
#ifdef ARK_SUPPORT_INTL
@ -820,9 +822,21 @@ void *JSNApi::SerializeValue(const EcmaVM *vm, Local<JSValueRef> value, Local<JS
{
CHECK_HAS_PENDING_EXCEPTION(vm, nullptr);
ecmascript::JSThread *thread = vm->GetJSThread();
ecmascript::Serializer serializer(thread);
JSHandle<JSTaggedValue> arkValue = JSNApiHelper::ToJSHandle(value);
JSHandle<JSTaggedValue> arkTransfer = JSNApiHelper::ToJSHandle(transfer);
#if ECMASCRIPT_ENABLE_VALUE_SERIALIZER
ecmascript::ValueSerializer serializer(thread);
std::unique_ptr<ecmascript::SerializeData> data;
if (serializer.WriteValue(thread, arkValue, arkTransfer)) {
data = serializer.Release();
}
if (data == nullptr) {
return nullptr;
} else {
return reinterpret_cast<void *>(data.release());
}
#else
ecmascript::Serializer serializer(thread);
std::unique_ptr<ecmascript::SerializationData> data;
if (serializer.WriteValue(thread, arkValue, arkTransfer)) {
data = serializer.Release();
@ -832,23 +846,37 @@ void *JSNApi::SerializeValue(const EcmaVM *vm, Local<JSValueRef> value, Local<JS
} else {
return reinterpret_cast<void *>(data.release());
}
#endif
}
Local<JSValueRef> JSNApi::DeserializeValue(const EcmaVM *vm, void *recoder, void *hint)
{
CHECK_HAS_PENDING_EXCEPTION_RETURN_UNDEFINED(vm);
ecmascript::JSThread *thread = vm->GetJSThread();
#if ECMASCRIPT_ENABLE_VALUE_SERIALIZER
std::unique_ptr<ecmascript::SerializeData> data(reinterpret_cast<ecmascript::SerializeData *>(recoder));
ecmascript::BaseDeserializer deserializer(thread, data.release(), hint);
JSHandle<JSTaggedValue> result = deserializer.ReadValue();
return JSNApiHelper::ToLocal<ObjectRef>(result);
#else
std::unique_ptr<ecmascript::SerializationData> data(reinterpret_cast<ecmascript::SerializationData *>(recoder));
ecmascript::Deserializer deserializer(thread, data.release(), hint);
JSHandle<JSTaggedValue> result = deserializer.ReadValue();
return JSNApiHelper::ToLocal<ObjectRef>(result);
#endif
}
void JSNApi::DeleteSerializationData(void *data)
{
#if ECMASCRIPT_ENABLE_VALUE_SERIALIZER
ecmascript::SerializeData *value = reinterpret_cast<ecmascript::SerializeData *>(data);
delete value;
value = nullptr;
#else
ecmascript::SerializationData *value = reinterpret_cast<ecmascript::SerializationData *>(data);
delete value;
value = nullptr;
#endif
}
void HostPromiseRejectionTracker(const EcmaVM *vm,
@ -1403,6 +1431,7 @@ bool ObjectRef::ConvertToNativeBindingObject(const EcmaVM *vm, Local<NativePoint
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> keyValue = env->GetNativeBindingSymbol();
JSHandle<JSTaggedValue> valueValue = JSNApiHelper::ToJSHandle(value);
object->GetTaggedObject()->GetClass()->SetIsNativeBindingObject(true);
return JSTaggedValue::SetProperty(vm->GetJSThread(), object, keyValue, valueValue);
}

View File

@ -0,0 +1,510 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/serializer/base_deserializer.h"
#include "ecmascript/ecma_string_table.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/global_env.h"
#include "ecmascript/js_thread.h"
#include "ecmascript/mem/mem.h"
#include "ecmascript/mem/sparse_space.h"
namespace panda::ecmascript {
#define NEW_OBJECT_ALL_SPACES() \
(uint8_t)SerializedObjectSpace::OLD_SPACE: \
case (uint8_t)SerializedObjectSpace::NON_MOVABLE_SPACE: \
case (uint8_t)SerializedObjectSpace::MACHINE_CODE_SPACE: \
case (uint8_t)SerializedObjectSpace::HUGE_SPACE
JSHandle<JSTaggedValue> BaseDeserializer::ReadValue()
{
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "Deserialize dataSize: " + std::to_string(data_->Size()));
size_t maxSerializerSize = thread_->GetEcmaVM()->GetEcmaParamConfiguration().GetMaxJSSerializerSize();
if (data_->Size() > maxSerializerSize) {
LOG_ECMA(ERROR) << "The serialization data size has exceed limit Size, current size is: " << data_->Size()
<< " max size is: " << maxSerializerSize;
return JSHandle<JSTaggedValue>();
}
AllocateToDifferentSpaces();
JSHandle<JSTaggedValue> res = DeserializeJSTaggedValue();
return res;
}
JSHandle<JSTaggedValue> BaseDeserializer::DeserializeJSTaggedValue()
{
if (data_->IsIncompleteData()) {
LOG_ECMA(ERROR) << "The serialization data is incomplete";
return JSHandle<JSTaggedValue>();
}
uint8_t encodeFlag = data_->ReadUint8();
uintptr_t result = 0U;
while (ReadSingleEncodeData(encodeFlag, ObjectSlot(ToUintPtr(&result)), true) == 0) {
encodeFlag = data_->ReadUint8();
}
// now new constpool here if newConstPoolInfos_ is not empty
for(auto newConstpoolInfo : newConstPoolInfos_) {
DeserializeConstPool(newConstpoolInfo);
delete newConstpoolInfo;
}
newConstPoolInfos_.clear();
// new native binding object here
for(auto nativeBindingInfo : nativeBindingInfos_) {
DeserializeNativeBindingObject(nativeBindingInfo);
delete nativeBindingInfo;
}
nativeBindingInfos_.clear();
return JSHandle<JSTaggedValue>(thread_, JSTaggedValue(result));
}
uintptr_t BaseDeserializer::DeserializeTaggedObject(SerializedObjectSpace space)
{
size_t objSize = data_->ReadUint32();
uintptr_t res = RelocateObjectAddr(space, objSize);
objectVector_.push_back(res);
size_t resIndex = objectVector_.size() - 1;
DeserializeObjectField(ObjectSlot(res), ObjectSlot(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) {
EcmaStringTable *stringTable = thread_->GetEcmaVM()->GetEcmaStringTable();
EcmaString *str = stringTable->GetString(reinterpret_cast<EcmaString *>(res));
if (str) {
res = ToUintPtr(str);
objectVector_[resIndex] = res;
} else {
EcmaStringAccessor(reinterpret_cast<EcmaString *>(res)).ClearInternString();
stringTable->InternString(reinterpret_cast<EcmaString *>(res));
}
}
return res;
}
void BaseDeserializer::DeserializeObjectField(ObjectSlot start, ObjectSlot end)
{
while (start < end) {
uint8_t encodeFlag = data_->ReadUint8();
start += ReadSingleEncodeData(encodeFlag, start);
}
}
void BaseDeserializer::DeserializeConstPool(NewConstPoolInfo *info)
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSPandaFile *jsPandaFile = info->jsPandaFile_;
panda_file::File::EntityId methodId = info->methodId_;
ObjectSlot slot = ObjectSlot(info->slotAddr_);
JSHandle<ConstantPool> constpool = ConstantPool::CreateConstPool(thread_->GetEcmaVM(), jsPandaFile, methodId);
panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), methodId);
int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
thread_->GetCurrentEcmaContext()->AddConstpool(jsPandaFile, constpool.GetTaggedValue(), index);
slot.Update(constpool.GetTaggedType());
UpdateIfExistOldToNew(constpool.GetTaggedType(), slot);
}
void BaseDeserializer::DeserializeNativeBindingObject(NativeBindingInfo *info)
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
AttachFunc af = info->af_;
void *bufferPointer = info->bufferPointer_;
void *hint = info->hint_;
void *attachData = info->attachData_;
ObjectSlot slot = info->slot_;
bool root = info->root_;
Local<JSValueRef> attachVal = af(engine_, bufferPointer, hint, attachData);
if (attachVal.IsEmpty()) {
LOG_ECMA(ERROR) << "NativeBindingObject is empty";
attachVal = JSValueRef::Undefined(thread_->GetEcmaVM());
}
JSTaggedType res = JSNApiHelper::ToJSHandle(attachVal).GetTaggedType();
slot.Update(res);
if (!root) {
UpdateIfExistOldToNew(res, slot);
}
}
void BaseDeserializer::HandleNewObjectEncodeFlag(SerializedObjectSpace space, ObjectSlot slot, bool isRoot)
{
// deserialize object prologue
bool isWeak = GetAndResetWeak();
bool isTransferBuffer = GetAndResetTransferBuffer();
void *bufferPointer = GetAndResetBufferPointer();
ConstantPool *constpool = GetAndResetConstantPool();
if (needNewConstPool_) {
needNewConstPool_ = false;
newConstPoolInfos_.back()->slotAddr_ = slot.SlotAddress();
}
// deserialize object here
uintptr_t addr = DeserializeTaggedObject(space);
// deserialize object epilogue
if (isTransferBuffer) {
TransferArrayBufferAttach(addr);
} else if (bufferPointer != nullptr) {
ResetArrayBufferNativePointer(addr, bufferPointer);
} else if (constpool != nullptr) {
ResetMethodConstantPool(addr, constpool);
}
TaggedObject *object = reinterpret_cast<TaggedObject *>(addr);
if (object->GetClass()->IsJSNativePointer()) {
JSNativePointer *nativePointer = reinterpret_cast<JSNativePointer *>(object);
if (nativePointer->GetDeleter() != nullptr) {
thread_->GetEcmaVM()->PushToNativePointerList(nativePointer);
}
}
UpdateMaybeWeak(slot, addr, isWeak);
if (!isRoot) {
UpdateIfExistOldToNew(addr, slot);
}
}
void BaseDeserializer::HandleMethodEncodeFlag()
{
panda_file::File::EntityId methodId = MethodLiteral::GetMethodId(data_->ReadJSTaggedType());
JSPandaFile *jsPandaFile = reinterpret_cast<JSPandaFile *>(data_->ReadJSTaggedType());
panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), methodId);
int32_t index = static_cast<int32_t>(indexAccessor.GetHeaderIndex());
JSTaggedValue constpool = thread_->GetCurrentEcmaContext()->FindConstpoolWithAOT(jsPandaFile, index);
if (constpool.IsHole()) {
LOG_ECMA(ERROR) << "ValueDeserialize: function deserialize can't find constpool from panda file: "
<< jsPandaFile;
// defer new constpool until deserialize finish
needNewConstPool_ = true;
newConstPoolInfos_.push_back(new NewConstPoolInfo(jsPandaFile, methodId));
} else {
constpool_ = reinterpret_cast<ConstantPool *>(constpool.GetTaggedObject());
}
}
void BaseDeserializer::TransferArrayBufferAttach(uintptr_t objAddr)
{
ASSERT(JSTaggedValue(objAddr).IsArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
bool withNativeAreaAllocator = arrayBuffer->GetWithNativeAreaAllocator();
JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
arrayBuffer->Attach(thread_, arrayLength, JSTaggedValue(np), withNativeAreaAllocator);
}
void BaseDeserializer::ResetArrayBufferNativePointer(uintptr_t objAddr, void *bufferPointer)
{
ASSERT(JSTaggedValue(objAddr).IsArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(objAddr);
arrayBuffer->SetWithNativeAreaAllocator(true);
JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
np->SetExternalPointer(bufferPointer);
np->SetDeleter(&NativeAreaAllocator::FreeBufferFunc);
np->SetData(thread_->GetEcmaVM()->GetNativeAreaAllocator());
}
void BaseDeserializer::ResetMethodConstantPool(uintptr_t objAddr, ConstantPool *constpool)
{
ASSERT(JSTaggedValue(objAddr).IsMethod());
Method *method = reinterpret_cast<Method *>(objAddr);
method->SetConstantPool(thread_, JSTaggedValue(constpool), BarrierMode::SKIP_BARRIER);
}
size_t BaseDeserializer::ReadSingleEncodeData(uint8_t encodeFlag, ObjectSlot slot, bool isRoot)
{
size_t handledFieldLength = SINGLE_FILED_LENGTH;
switch (encodeFlag) {
case NEW_OBJECT_ALL_SPACES(): {
SerializedObjectSpace space = SerializeData::DecodeSpace(encodeFlag);
HandleNewObjectEncodeFlag(space, slot, isRoot);
break;
}
case (uint8_t)EncodeFlag::REFERENCE: {
uint32_t objIndex = data_->ReadUint32();
uintptr_t addr = objectVector_[objIndex];
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
UpdateIfExistOldToNew(addr, slot);
break;
}
case (uint8_t)EncodeFlag::WEAK: {
ASSERT(!isWeak_);
isWeak_ = true;
handledFieldLength = 0;
break;
}
case (uint8_t)EncodeFlag::PRIMITIVE: {
JSTaggedType value = data_->ReadJSTaggedType();
slot.Update(value);
break;
}
case (uint8_t)EncodeFlag::MULTI_RAW_DATA: {
uint32_t length = data_->ReadUint32();
data_->ReadRawData(slot.SlotAddress(), sizeof(JSTaggedType) * length);
handledFieldLength = length;
break;
}
case (uint8_t)EncodeFlag::ROOT_OBJECT: {
uint32_t index = data_->ReadUint32();
uintptr_t addr = thread_->GetEcmaVM()->GetSnapshotEnv()->RelocateRootObjectAddr(index);
if (!isRoot) {
UpdateIfExistOldToNew(addr, slot);
}
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
break;
}
case (uint8_t)EncodeFlag::OBJECT_PROTO: {
uint8_t type = data_->ReadUint8();
uintptr_t addr = RelocateObjectProtoAddr(type);
if (!isRoot) {
UpdateIfExistOldToNew(addr, slot);
}
UpdateMaybeWeak(slot, addr, GetAndResetWeak());
break;
}
case (uint8_t)EncodeFlag::TRANSFER_ARRAY_BUFFER: {
isTransferArrayBuffer_ = true;
handledFieldLength = 0;
break;
}
case (uint8_t)EncodeFlag::ARRAY_BUFFER: {
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;
break;
}
case (uint8_t)EncodeFlag::METHOD: {
HandleMethodEncodeFlag();
handledFieldLength = 0;
break;
}
case (uint8_t)EncodeFlag::NATIVE_BINDING_OBJECT: {
slot.Update(JSTaggedValue::Undefined().GetRawData());
AttachFunc af = reinterpret_cast<AttachFunc>(data_->ReadJSTaggedType());
void *bufferPointer = reinterpret_cast<void *>(data_->ReadJSTaggedType());
void *hint = reinterpret_cast<void *>(data_->ReadJSTaggedType());
void *attachData = reinterpret_cast<void *>(data_->ReadJSTaggedType());
// defer new native binding object until deserialize finish
nativeBindingInfos_.push_back(new NativeBindingInfo(af, bufferPointer, hint, attachData, slot, isRoot));
break;
}
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
break;
}
return handledFieldLength;
}
void BaseDeserializer::UpdateIfExistOldToNew(uintptr_t addr, ObjectSlot slot)
{
Region *valueRegion = Region::ObjectAddressToRange(addr);
// root region is impossible in young space when deserialize
if (valueRegion != nullptr && 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());
}
}
uintptr_t BaseDeserializer::RelocateObjectAddr(SerializedObjectSpace space, size_t objSize)
{
uintptr_t res = 0U;
switch (space) {
case SerializedObjectSpace::OLD_SPACE: {
if (oldSpaceBeginAddr_ + objSize > AlignUp(oldSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(oldRegionIndex_ < regionVector_.size());
oldSpaceBeginAddr_ = regionVector_[oldRegionIndex_++]->GetBegin();
}
res = oldSpaceBeginAddr_;
oldSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::NON_MOVABLE_SPACE: {
if (nonMovableSpaceBeginAddr_ + objSize > AlignUp(nonMovableSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(nonMovableRegionIndex_ < regionVector_.size());
nonMovableSpaceBeginAddr_ = regionVector_[nonMovableRegionIndex_++]->GetBegin();
}
res = nonMovableSpaceBeginAddr_;
nonMovableSpaceBeginAddr_ += objSize;
break;
}
case SerializedObjectSpace::MACHINE_CODE_SPACE: {
if (machineCodeSpaceBeginAddr_ + objSize > AlignUp(machineCodeSpaceBeginAddr_, DEFAULT_REGION_SIZE)) {
ASSERT(machineCodeRegionIndex_ < regionVector_.size());
machineCodeSpaceBeginAddr_ = regionVector_[machineCodeRegionIndex_++]->GetBegin();
}
res = nonMovableSpaceBeginAddr_;
nonMovableSpaceBeginAddr_ += objSize;
break;
}
default:
// no gc for this allocate
res = heap_->GetHugeObjectSpace()->Allocate(objSize, thread_);
break;
}
return res;
}
JSTaggedType BaseDeserializer::RelocateObjectProtoAddr(uint8_t objectType)
{
auto env = thread_->GetEcmaVM()->GetGlobalEnv();
switch (objectType) {
case (uint8_t)JSType::JS_OBJECT:
return env->GetObjectFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_ERROR:
return JSHandle<JSFunction>(env->GetErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_EVAL_ERROR:
return JSHandle<JSFunction>(env->GetEvalErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_RANGE_ERROR:
return JSHandle<JSFunction>(env->GetRangeErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_REFERENCE_ERROR:
return JSHandle<JSFunction>(env->GetReferenceErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_TYPE_ERROR:
return JSHandle<JSFunction>(env->GetTypeErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_AGGREGATE_ERROR:
return JSHandle<JSFunction>(env->GetAggregateErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_URI_ERROR:
return JSHandle<JSFunction>(env->GetURIErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_SYNTAX_ERROR:
return JSHandle<JSFunction>(env->GetSyntaxErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_OOM_ERROR:
return JSHandle<JSFunction>(env->GetOOMErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_TERMINATION_ERROR:
return JSHandle<JSFunction>(env->GetTerminationErrorFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_DATE:
return env->GetDatePrototype().GetTaggedType();
case (uint8_t)JSType::JS_ARRAY:
return env->GetArrayPrototype().GetTaggedType();
case (uint8_t)JSType::JS_MAP:
return env->GetMapPrototype().GetTaggedType();
case (uint8_t)JSType::JS_SET:
return env->GetSetPrototype().GetTaggedType();
case (uint8_t)JSType::JS_REG_EXP:
return env->GetRegExpPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT8_ARRAY:
return env->GetInt8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT8_ARRAY:
return env->GetUint8ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT8_CLAMPED_ARRAY:
return env->GetUint8ClampedArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT16_ARRAY:
return env->GetInt16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT16_ARRAY:
return env->GetUint16ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_INT32_ARRAY:
return env->GetInt32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_UINT32_ARRAY:
return env->GetUint32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_FLOAT32_ARRAY:
return env->GetFloat32ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_FLOAT64_ARRAY:
return env->GetFloat64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_BIGINT64_ARRAY:
return env->GetBigInt64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_BIGUINT64_ARRAY:
return env->GetBigUint64ArrayFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::JS_ARRAY_BUFFER:
return JSHandle<JSFunction>(env->GetArrayBufferFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_SHARED_ARRAY_BUFFER:
return JSHandle<JSFunction>(env->GetSharedArrayBufferFunction())->GetFunctionPrototype().GetRawData();
case (uint8_t)JSType::JS_ASYNC_FUNCTION:
return env->GetAsyncFunctionPrototype().GetTaggedType();
case (uint8_t)JSType::BIGINT:
return JSHandle<JSFunction>(env->GetBigIntFunction())->GetFunctionPrototype().GetRawData();
default:
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
break;
}
}
void BaseDeserializer::AllocateToDifferentSpaces()
{
size_t oldSpaceSize = data_->GetOldSpaceSize();
if (oldSpaceSize > 0) {
heap_->GetOldSpace()->IncreaseLiveObjectSize(oldSpaceSize);
AllocateToOldSpace(oldSpaceSize);
}
size_t nonMovableSpaceSize = data_->GetNonMovableSpaceSize();
if (nonMovableSpaceSize > 0) {
heap_->GetNonMovableSpace()->IncreaseLiveObjectSize(nonMovableSpaceSize);
AllocateToNonMovableSpace(nonMovableSpaceSize);
}
size_t machineCodeSpaceSize = data_->GetMachineCodeSpaceSize();
if (machineCodeSpaceSize > 0) {
heap_->GetMachineCodeSpace()->IncreaseLiveObjectSize(machineCodeSpaceSize);
AllocateToMachineCodeSpace(machineCodeSpaceSize);
}
}
void BaseDeserializer::AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t &regionIndex)
{
regionIndex = regionVector_.size();
size_t regionAlignedSize = SerializeData::AlignUpRegionAvailableSize(spaceObjSize);
size_t regionNum = regionAlignedSize / Region::GetRegionAvailableSize();
while (regionNum > 1) { // 1: one region have allocated before
std::vector<size_t> regionRemainSizeVector = data_->GetRegionRemainSizeVector();
space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - regionRemainSizeVector[regionRemainSizeIndex_++]);
if (!space->Expand()) {
LOG_ECMA(FATAL) << "BaseDeserializer::OutOfMemory when deserialize";
}
regionVector_.push_back(space->GetCurrentRegion());
regionNum--;
}
size_t lastRegionRemainSize = regionAlignedSize - spaceObjSize;
space->ResetTopPointer(space->GetCurrentRegion()->GetEnd() - lastRegionRemainSize);
}
void BaseDeserializer::AllocateToOldSpace(size_t oldSpaceSize)
{
SparseSpace *space = heap_->GetOldSpace();
uintptr_t object = space->Allocate(oldSpaceSize, false);
if (UNLIKELY(object == 0U)) {
oldSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
AllocateMultiRegion(space, oldSpaceSize, oldRegionIndex_);
} else {
oldSpaceBeginAddr_ = object;
}
}
void BaseDeserializer::AllocateToNonMovableSpace(size_t nonMovableSpaceSize)
{
SparseSpace *space = heap_->GetNonMovableSpace();
uintptr_t object = space->Allocate(nonMovableSpaceSize, false);
if (UNLIKELY(object == 0U)) {
nonMovableSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
AllocateMultiRegion(space, nonMovableSpaceSize, nonMovableRegionIndex_);
} else {
nonMovableSpaceBeginAddr_ = object;
}
}
void BaseDeserializer::AllocateToMachineCodeSpace(size_t machineCodeSpaceSize)
{
SparseSpace *space = heap_->GetMachineCodeSpace();
uintptr_t object = space->Allocate(machineCodeSpaceSize, false);
if (UNLIKELY(object == 0U)) {
machineCodeSpaceBeginAddr_ = space->GetCurrentRegion()->GetBegin();
AllocateMultiRegion(space, machineCodeSpaceSize, machineCodeRegionIndex_);
} else {
machineCodeSpaceBeginAddr_ = object;
}
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,153 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H
#define ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H
#include "ecmascript/js_serializer.h"
#include "ecmascript/serializer/serialize_data.h"
namespace panda::ecmascript {
class JSThread;
class Heap;
struct NewConstPoolInfo {
JSPandaFile *jsPandaFile_ {nullptr};
panda_file::File::EntityId methodId_;
uintptr_t slotAddr_ {0U};
NewConstPoolInfo(JSPandaFile *jsPandaFile, panda_file::File::EntityId methodId)
: jsPandaFile_(jsPandaFile), methodId_(methodId) {}
};
struct NativeBindingInfo {
AttachFunc af_ {nullptr};
void *bufferPointer_ {nullptr};
void *hint_ = {nullptr};
void *attachData_ = {nullptr};
ObjectSlot slot_;
bool root_ {false};
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) {}
};
class BaseDeserializer {
public:
explicit BaseDeserializer(JSThread *thread, SerializeData *data, void *hint = nullptr)
: thread_(thread), heap_(const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())), data_(data), engine_(hint) {}
~BaseDeserializer()
{
data_.reset(nullptr);
objectVector_.clear();
regionVector_.clear();
}
NO_COPY_SEMANTIC(BaseDeserializer);
NO_MOVE_SEMANTIC(BaseDeserializer);
JSHandle<JSTaggedValue> ReadValue();
private:
JSHandle<JSTaggedValue> DeserializeJSTaggedValue();
uintptr_t DeserializeTaggedObject(SerializedObjectSpace space);
void DeserializeConstPool(NewConstPoolInfo *info);
void DeserializeNativeBindingObject(NativeBindingInfo *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 HandleNewObjectEncodeFlag(SerializedObjectSpace space, ObjectSlot slot, bool isRoot);
void HandleMethodEncodeFlag();
void TransferArrayBufferAttach(uintptr_t objAddr);
void ResetArrayBufferNativePointer(uintptr_t objAddr, void *bufferPointer);
void ResetMethodConstantPool(uintptr_t objAddr, ConstantPool *constpool);
void AllocateToDifferentSpaces();
void AllocateMultiRegion(SparseSpace *space, size_t spaceObjSize, size_t &regionIndex);
void AllocateToOldSpace(size_t oldSpaceSize);
void AllocateToNonMovableSpace(size_t nonMovableSpaceSize);
void AllocateToMachineCodeSpace(size_t machineCodeSpaceSize);
void UpdateIfExistOldToNew(uintptr_t addr, ObjectSlot slot);
bool GetAndResetWeak()
{
bool isWeak = isWeak_;
if (isWeak_) {
isWeak_ = false;
}
return isWeak;
}
bool GetAndResetTransferBuffer()
{
if (isTransferArrayBuffer_) {
isTransferArrayBuffer_ = false;
return true;
}
return false;
}
void *GetAndResetBufferPointer()
{
if (bufferPointer_) {
void *buffer = bufferPointer_;
bufferPointer_ = nullptr;
return buffer;
}
return nullptr;
}
ConstantPool *GetAndResetConstantPool()
{
if (constpool_) {
ConstantPool *constpool = constpool_;
constpool_ = nullptr;
return constpool;
}
return nullptr;
}
void UpdateMaybeWeak(ObjectSlot slot, uintptr_t addr, bool isWeak)
{
isWeak ? slot.UpdateWeak(addr) : slot.Update(addr);
}
private:
static constexpr size_t SINGLE_FILED_LENGTH = 1;
JSThread *thread_;
Heap *heap_;
std::unique_ptr<SerializeData> data_;
void *engine_;
uintptr_t oldSpaceBeginAddr_ {0};
uintptr_t nonMovableSpaceBeginAddr_ {0};
uintptr_t machineCodeSpaceBeginAddr_ {0};
CVector<uintptr_t> objectVector_;
CVector<Region *> regionVector_;
size_t oldRegionIndex_ {0};
size_t nonMovableRegionIndex_ {0};
size_t machineCodeRegionIndex_ {0};
size_t regionRemainSizeIndex_ {0};
bool isWeak_ {false};
bool isTransferArrayBuffer_ {false};
void *bufferPointer_ {nullptr};
ConstantPool *constpool_ {nullptr};
bool needNewConstPool_ {false};
CVector<NewConstPoolInfo *> newConstPoolInfos_;
CVector<NativeBindingInfo *> nativeBindingInfos_;
};
}
#endif // ECMASCRIPT_SERIALIZER_BASE_DESERIALIZER_H

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_INL_H
#define ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_INL_H
#include "ecmascript/serializer/base_serializer.h"
namespace panda::ecmascript {
template<SerializeType serializeType>
void BaseSerializer::SerializeObjectField(TaggedObject *object, JSType objectType)
{
auto visitor = [this, objectType](TaggedObject *root, ObjectSlot start, ObjectSlot end, VisitObjectArea area) {
switch (area) {
case VisitObjectArea::RAW_DATA:
WriteMultiRawData(start.SlotAddress(), end.SlotAddress() - start.SlotAddress());
break;
case VisitObjectArea::NATIVE_POINTER:
if (serializeType == SerializeType::VALUE_SERIALIZE) {
WriteMultiRawData(start.SlotAddress(), end.SlotAddress() - start.SlotAddress());
}
break;
case VisitObjectArea::IN_OBJECT: {
SerializeInObjField(root, start, end);
break;
}
default:
if (serializeType != SerializeType::VALUE_SERIALIZE
|| !SerializeSpecialObjIndividually(objectType, root, start, end)) {
for (ObjectSlot slot = start; slot < end; slot++) {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
}
}
break;
}
};
objXRay_.VisitObjectBody<VisitType::ALL_VISIT>(object, object->GetClass(), visitor);
}
template<SerializeType serializeType>
void BaseSerializer::SerializeTaggedObject(TaggedObject *object)
{
JSHClass *hclass = object->GetClass();
size_t objectSize = hclass->SizeFromJSHClass(object);
JSType objectType = hclass->GetObjectType();
SerializedObjectSpace space = GetSerializedObjectSpace(object);
data_->WriteUint8(SerializeData::EncodeNewObject(space));
data_->WriteUint32(objectSize);
data_->CalculateSerializedObjectSize(space, objectSize);
referenceMap_.emplace(object, objectIndex_++);
SerializeObjectField<serializeType>(object, objectType);
}
}
#endif // ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_INL_H

View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/serializer/base_serializer-inl.h"
#include "ecmascript/ecma_vm.h"
#include "ecmascript/mem/mem.h"
#include "ecmascript/mem/region.h"
namespace panda::ecmascript {
SerializedObjectSpace BaseSerializer::GetSerializedObjectSpace(TaggedObject *object) const
{
auto region = Region::ObjectAddressToRange(object);
if (region->InYoungOrOldSpace() || region->InAppSpawnSpace()) {
return SerializedObjectSpace::OLD_SPACE;
}
if (region->InNonMovableSpace() || region->InReadOnlySpace()) {
return SerializedObjectSpace::NON_MOVABLE_SPACE;
}
if (region->InMachineCodeSpace()) {
return SerializedObjectSpace::MACHINE_CODE_SPACE;
}
if (region->InHugeObjectSpace()) {
return SerializedObjectSpace::HUGE_SPACE;
}
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
void BaseSerializer::WriteMultiRawData(uintptr_t beginAddr, size_t fieldSize)
{
if (fieldSize > 0) {
data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
data_->WriteUint32(fieldSize / sizeof(JSTaggedType));
data_->WriteRawData(reinterpret_cast<uint8_t *>(beginAddr), fieldSize);
}
}
// Write JSTaggedValue could be either a pointer to a HeapObject or a value
void BaseSerializer::SerializeJSTaggedValue(JSTaggedValue value)
{
DISALLOW_GARBAGE_COLLECTION;
if (!value.IsHeapObject()) {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(value);
} else {
TaggedObject *object = nullptr;
bool isWeak = value.IsWeak();
object = isWeak ? value.GetWeakReferent() : value.GetTaggedObject();
SerializeObjectImpl(object, isWeak);
}
}
bool BaseSerializer::SerializeReference(TaggedObject *object)
{
if (referenceMap_.find(object) != referenceMap_.end()) {
uint32_t objectIndex = referenceMap_.find(object)->second;
data_->WriteEncodeFlag(EncodeFlag::REFERENCE);
data_->WriteUint32(objectIndex);
return true;
}
return false;
}
bool BaseSerializer::SerializeRootObject(TaggedObject *object)
{
size_t index = vm_->GetSnapshotEnv()->FindEnvObjectIndex(ToUintPtr(object));
if (index != SnapshotEnv::MAX_UINT_32) {
data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
data_->WriteUint32(index);
return true;
}
return false;
}
bool BaseSerializer::SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root,
ObjectSlot start, ObjectSlot end)
{
switch (objectType) {
case JSType::HCLASS:
SerializeHClassFieldIndividually(root, start, end);
return true;
case JSType::JS_ASYNC_FUNCTION:
SerializeAsyncFunctionFieldIndividually(root, start, end);
return true;
case JSType::METHOD:
SerializeMethodFieldIndividually(root, start, end);
return true;
default:
return false;
}
}
void BaseSerializer::SerializeHClassFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
{
ASSERT(root->GetClass()->IsHClass());
ObjectSlot slot = start;
while(slot < end) {
size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
switch (fieldOffset) {
case JSHClass::PROTOTYPE_OFFSET: {
JSHClass *kclass = reinterpret_cast<JSHClass *>(root);
JSTaggedValue proto = kclass->GetPrototype();
SerializeObjectProto(kclass, proto);
slot++;
break;
}
case JSHClass::TRANSTIONS_OFFSET:
case JSHClass::PARENT_OFFSET:
case JSHClass::VTABLE_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
slot++;
break;
}
case JSHClass::PROTO_CHANGE_MARKER_OFFSET:
case JSHClass::PROTO_CHANGE_DETAILS_OFFSET:
case JSHClass::ENUM_CACHE_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(JSTaggedValue::Null());
slot++;
break;
}
case JSHClass::SUPERS_OFFSET: {
auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
data_->WriteUint32(globalConst->GetEmptyArrayIndex());
slot++;
break;
}
default: {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
slot++;
break;
}
}
}
}
void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
{
ASSERT(root->GetClass()->GetObjectType() == JSType::JS_ASYNC_FUNCTION);
ObjectSlot slot = start;
while(slot < end) {
size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
switch (fieldOffset) {
case JSFunction::PROTO_OR_DYNCLASS_OFFSET:
case JSFunction::LEXICAL_ENV_OFFSET:
case JSFunction::HOME_OBJECT_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
slot++;
break;
}
case JSFunction::WORK_NODE_POINTER_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedType(0U);
slot++;
break;
}
default: {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
slot++;
break;
}
}
}
}
void BaseSerializer::SerializeMethodFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
{
ASSERT(root->GetClass()->IsMethod());
ObjectSlot slot = start;
while(slot < end) {
size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
switch (fieldOffset) {
case Method::CONSTANT_POOL_OFFSET:
case Method::PROFILE_TYPE_INFO_OFFSET:
case Method::ECMA_MODULE_OFFSET: {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
slot++;
break;
}
default: {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
slot++;
break;
}
}
}
}
void BaseSerializer::SerializeObjectProto(JSHClass *kclass, JSTaggedValue proto)
{
if (!proto.IsHeapObject()) {
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteJSTaggedValue(proto);
} else if (!SerializeReference(proto.GetTaggedObject()) && !SerializeRootObject(proto.GetTaggedObject())) {
data_->WriteEncodeFlag(EncodeFlag::OBJECT_PROTO);
data_->WriteUint8(static_cast<uint8_t>(kclass->GetObjectType()));
}
}
void BaseSerializer::SerializeInObjField(TaggedObject *object, ObjectSlot start, ObjectSlot end)
{
auto hclass = object->GetClass();
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
size_t index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
auto attr = layout->GetAttr(index++);
if (attr.GetRepresentation() == Representation::DOUBLE || attr.GetRepresentation() == Representation::INT) {
auto fieldAddr = slot.SlotAddress();
data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
data_->WriteRawData(reinterpret_cast<uint8_t *>(fieldAddr), sizeof(JSTaggedType));
} else {
SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
}
}
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_H
#define ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_H
#include "ecmascript/mem/object_xray.h"
#include "ecmascript/serializer/serialize_data.h"
namespace panda::ecmascript {
class Ecmavm;
class JSThread;
class BaseSerializer {
public:
explicit BaseSerializer(JSThread *thread) : thread_(thread), vm_(thread->GetEcmaVM()), objXRay_(vm_) {
data_.reset(new SerializeData(thread));
}
virtual ~BaseSerializer()
{
referenceMap_.clear();
}
NO_COPY_SEMANTIC(BaseSerializer);
NO_MOVE_SEMANTIC(BaseSerializer);
void SerializeJSTaggedValue(JSTaggedValue value);
std::unique_ptr<SerializeData> Release()
{
return std::move(data_);
}
protected:
// Different serialize mode can implement this interface to custom processing
virtual void SerializeObjectImpl(TaggedObject *object, bool isWeak = false) = 0;
void WriteMultiRawData(uintptr_t beginAddr, size_t fieldSize);
template<SerializeType serializeType>
void SerializeTaggedObject(TaggedObject *object);
bool SerializeReference(TaggedObject *object);
bool SerializeRootObject(TaggedObject *object);
template<SerializeType serializeType>
void SerializeObjectField(TaggedObject *object, JSType objectType);
bool SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root, ObjectSlot start, ObjectSlot end);
void SerializeHClassFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end);
void SerializeAsyncFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end);
void SerializeMethodFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end);
void SerializeObjectProto(JSHClass *kclass, JSTaggedValue proto);
void SerializeInObjField(TaggedObject *object, ObjectSlot start, ObjectSlot end);
SerializedObjectSpace GetSerializedObjectSpace(TaggedObject *object) const;
protected:
JSThread *thread_;
EcmaVM *vm_;
ObjectXRay objXRay_;
std::unique_ptr<SerializeData> data_;
CUnorderedMap<TaggedObject *, uint32_t> referenceMap_;
size_t objectIndex_ {0};
};
}
#endif // ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_H

View File

@ -0,0 +1,230 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
#define ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H
#include "ecmascript/js_tagged_value-inl.h"
#include "ecmascript/mem/dyn_chunk.h"
#include "ecmascript/snapshot/mem/snapshot_env.h"
namespace panda::ecmascript {
enum class EncodeFlag : uint8_t {
// 0x00~0x03 represent new object to different space:
// 0x00: old space
// 0x01: non movable space
// 0x02: machine code space
// 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
};
enum class SerializedObjectSpace : uint8_t {
OLD_SPACE = 0,
NON_MOVABLE_SPACE,
MACHINE_CODE_SPACE,
HUGE_SPACE
};
enum class SerializeType : uint8_t {
VALUE_SERIALIZE,
PGO_SERIALIZE
};
class SerializeData {
public:
explicit SerializeData(JSThread *thread) : chunk_(thread->GetNativeAreaAllocator()), data_(&chunk_) {}
~SerializeData()
{
regionRemainSizeVector_.clear();
}
NO_COPY_SEMANTIC(SerializeData);
NO_MOVE_SEMANTIC(SerializeData);
static uint8_t EncodeNewObject(SerializedObjectSpace space)
{
return static_cast<uint8_t>(space) | static_cast<uint8_t>(EncodeFlag::NEW_OBJECT);
}
static SerializedObjectSpace DecodeSpace(uint8_t type)
{
ASSERT(type < static_cast<uint8_t>(EncodeFlag::REFERENCE));
return static_cast<SerializedObjectSpace>(type);
}
static size_t AlignUpRegionAvailableSize(size_t size)
{
if (size == 0) {
return Region::GetRegionAvailableSize();
}
size_t regionAvailableSize = Region::GetRegionAvailableSize();
return ((size - 1) / regionAvailableSize + 1) * regionAvailableSize; // 1: align up
}
void WriteUint8(uint8_t data) {
data_.EmitChar(data);
}
uint8_t ReadUint8() {
ASSERT(position_ < Size());
return data_.GetU8(position_++);
}
void WriteEncodeFlag(EncodeFlag flag) {
data_.EmitChar(static_cast<uint8_t>(flag));
}
void WriteUint32(uint32_t data)
{
data_.EmitU32(data);
}
uint32_t ReadUint32()
{
ASSERT(position_ < Size());
uint32_t value = data_.GetU32(position_);
position_ += sizeof(uint32_t);
return value;
}
void WriteRawData(uint8_t *data, size_t length)
{
data_.Emit(data, length);
}
void WriteJSTaggedValue(JSTaggedValue value)
{
data_.EmitU64(value.GetRawData());
}
void WriteJSTaggedType(JSTaggedType value)
{
data_.EmitU64(value);
}
JSTaggedType ReadJSTaggedType()
{
ASSERT(position_ < Size());
JSTaggedType value = data_.GetU64(position_);
position_ += sizeof(JSTaggedType);
return value;
}
void ReadRawData(uintptr_t addr, size_t len)
{
ASSERT(position_ + len <= Size());
if (memcpy_s(reinterpret_cast<void *>(addr), len, data_.GetBegin() + position_, len) != EOK) {
LOG_ECMA(FATAL) << "this branch is unreachable";
UNREACHABLE();
}
position_ += len;
}
uint8_t* Data() const
{
return data_.GetBegin();
}
size_t Size() const
{
return data_.GetSize();
}
size_t GetPosition() const
{
return position_;
}
void SetIncompleteData(bool incomplete)
{
incompleteData_ = incomplete;
}
bool IsIncompleteData() const
{
return incompleteData_;
}
const std::vector<size_t>& GetRegionRemainSizeVector() const
{
return regionRemainSizeVector_;
}
size_t GetOldSpaceSize() const
{
return oldSpaceSize_;
}
size_t GetNonMovableSpaceSize() const
{
return nonMovableSpaceSize_;
}
size_t GetMachineCodeSpaceSize() const
{
return machineCodeSpaceSize_;
}
void CalculateSerializedObjectSize(SerializedObjectSpace space, size_t objectSize)
{
switch (space) {
case SerializedObjectSpace::OLD_SPACE:
AlignSpaceObjectSize(oldSpaceSize_, objectSize);
break;
case SerializedObjectSpace::NON_MOVABLE_SPACE:
AlignSpaceObjectSize(nonMovableSpaceSize_, objectSize);
break;
case SerializedObjectSpace::MACHINE_CODE_SPACE:
AlignSpaceObjectSize(machineCodeSpaceSize_, objectSize);
break;
default:
break;
}
}
void AlignSpaceObjectSize(size_t &spaceSize, size_t objectSize)
{
size_t alignRegionSize = AlignUpRegionAvailableSize(spaceSize);
if(UNLIKELY(spaceSize + objectSize > alignRegionSize)) {
regionRemainSizeVector_.push_back(alignRegionSize - spaceSize);
spaceSize = alignRegionSize;
}
spaceSize += objectSize;
ASSERT(spaceSize <= SnapshotEnv::MAX_UINT_32);
}
private:
Chunk chunk_;
DynChunk data_;
size_t oldSpaceSize_ {0};
size_t nonMovableSpaceSize_ {0};
size_t machineCodeSpaceSize_ {0};
size_t position_ {0};
bool incompleteData_ {false};
std::vector<size_t> regionRemainSizeVector_;
};
}
#endif // ECMASCRIPT_SERIALIZER_SERIALIZE_DATA_H

View File

@ -0,0 +1,49 @@
# Copyright (c) 2021 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//arkcompiler/ets_runtime/js_runtime_config.gni")
import("//arkcompiler/ets_runtime/test/test_helper.gni")
module_output_path = "arkcompiler/ets_runtime"
host_unittest_action("SerializerTest") {
module_out_path = module_output_path
sources = [
# test file
"serializer_test.cpp",
]
configs = [ "$js_root:ecma_test_config" ]
deps = [
"$ark_third_party_root/icu/icu4c:shared_icui18n",
"$ark_third_party_root/icu/icu4c:shared_icuuc",
"$js_root:libark_jsruntime_test",
sdk_libc_secshared_dep,
]
# hiviewdfx libraries
external_deps = hiviewdfx_ext_deps
deps += hiviewdfx_deps
}
group("unittest") {
testonly = true
deps = [ ":SerializerTest" ]
}
group("host_unittest") {
testonly = true
deps = [ ":SerializerTestAction" ]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/serializer/value_serializer.h"
#include "ecmascript/base/array_helper.h"
#include "ecmascript/js_serializer.h"
#include "ecmascript/shared_mm/shared_mm.h"
namespace panda::ecmascript {
bool ValueSerializer::CheckObjectCanSerialize(TaggedObject *object)
{
JSType type = object->GetClass()->GetObjectType();
if (IsInternalJSType(type)) {
return true;
}
switch (type) {
case JSType::JS_ERROR:
case JSType::JS_EVAL_ERROR:
case JSType::JS_RANGE_ERROR:
case JSType::JS_REFERENCE_ERROR:
case JSType::JS_TYPE_ERROR:
case JSType::JS_AGGREGATE_ERROR:
case JSType::JS_URI_ERROR:
case JSType::JS_SYNTAX_ERROR:
case JSType::JS_OOM_ERROR:
case JSType::JS_DATE:
case JSType::JS_ARRAY:
case JSType::JS_MAP:
case JSType::JS_SET:
case JSType::JS_REG_EXP:
case JSType::JS_INT8_ARRAY:
case JSType::JS_UINT8_ARRAY:
case JSType::JS_UINT8_CLAMPED_ARRAY:
case JSType::JS_INT16_ARRAY:
case JSType::JS_UINT16_ARRAY:
case JSType::JS_INT32_ARRAY:
case JSType::JS_UINT32_ARRAY:
case JSType::JS_FLOAT32_ARRAY:
case JSType::JS_FLOAT64_ARRAY:
case JSType::JS_BIGINT64_ARRAY:
case JSType::JS_BIGUINT64_ARRAY:
case JSType::JS_ARRAY_BUFFER:
case JSType::JS_SHARED_ARRAY_BUFFER:
case JSType::LINE_STRING:
case JSType::CONSTANT_STRING:
case JSType::TREE_STRING:
case JSType::SLICED_STRING:
case JSType::JS_OBJECT:
case JSType::JS_ASYNC_FUNCTION: // means CONCURRENT_FUNCTION
return true;
default:
break;
}
return false;
}
void ValueSerializer::InitTransferSet(CUnorderedSet<uintptr_t> transferDataSet)
{
transferDataSet_ = std::move(transferDataSet);
}
void ValueSerializer::ClearTransferSet()
{
transferDataSet_.clear();
}
bool ValueSerializer::WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value,
const JSHandle<JSTaggedValue> &transfer)
{
ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ValueSerializer::WriteValue");
ASSERT(!value->IsWeak());
if (value.GetTaggedValue() == transfer.GetTaggedValue()) {
defaultTransfer_ = true;
} else if (!PrepareTransfer(thread, transfer)) {
data_->SetIncompleteData(true);
return false;
}
if (value->IsHeapObject()) {
vm_->GetSnapshotEnv()->Initialize();
}
SerializeJSTaggedValue(value.GetTaggedValue());
// clear transfer obj set after serialization
transferDataSet_.clear();
if (value->IsHeapObject()) {
vm_->GetSnapshotEnv()->ClearEnvMap();
}
if (notSupport_) {
data_->SetIncompleteData(true);
return false;
}
return true;
}
void ValueSerializer::SerializeObjectImpl(TaggedObject *object, bool isWeak)
{
if (notSupport_) {
return;
}
if (!CheckObjectCanSerialize(object)) {
notSupport_ = true;
return;
}
if (isWeak) {
data_->WriteEncodeFlag(EncodeFlag::WEAK);
}
if (SerializeReference(object) || SerializeRootObject(object)) {
return;
}
if (object->GetClass()->IsNativeBindingObject()) {
SerializeNativeBindingObject(object);
return;
}
JSType type = object->GetClass()->GetObjectType();
bool arrayBufferDeferDetach = false;
switch (type) {
case JSType::JS_ARRAY_BUFFER:
arrayBufferDeferDetach = SerializeJSArrayBufferPrologue(object);
break;
case JSType::JS_SHARED_ARRAY_BUFFER:
SerializeJSSharedArrayBufferPrologue(object);
break;
case JSType::METHOD:
SerializeMethodPrologue(reinterpret_cast<Method *>(object));
break;
default:
break;
}
SerializeTaggedObject<SerializeType::VALUE_SERIALIZE>(object);
if (arrayBufferDeferDetach) {
ASSERT(object->GetClass()->IsArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(object);
arrayBuffer->Detach(thread_, arrayBuffer->GetWithNativeAreaAllocator());
}
}
void ValueSerializer::SerializeNativeBindingObject(TaggedObject *object)
{
[[maybe_unused]] EcmaHandleScope scope(thread_);
JSHandle<GlobalEnv> env = vm_->GetGlobalEnv();
JSHandle<JSTaggedValue> nativeBindingSymbol = env->GetNativeBindingSymbol();
JSHandle<JSTaggedValue> nativeBindingValue =
JSObject::GetProperty(thread_, JSHandle<JSObject>(thread_, object), nativeBindingSymbol).GetRawValue();
if (!nativeBindingValue->IsJSNativePointer()) {
LOG_ECMA(ERROR) << "ValueSerialize: SerializeNativeBindingObject nativeBindingValue is not JSNativePointer";
notSupport_ = true;
return;
}
auto info = reinterpret_cast<panda::JSNApi::NativeBindingInfo *>(
JSNativePointer::Cast(nativeBindingValue->GetTaggedObject())->GetExternalPointer());
if (info == nullptr) {
LOG_ECMA(ERROR) << "ValueSerialize: SerializeNativeBindingObject NativeBindingInfo is nullptr";
notSupport_ = true;
return;
}
void *enginePointer = info->env;
void *objPointer = info->nativeValue;
void *hint = info->hint;
void *detachData = info->detachData;
void *attachData = info->attachData;
DetachFunc detachNative = reinterpret_cast<DetachFunc>(info->detachFunc);
if (detachNative == nullptr) {
LOG_ECMA(ERROR) << "ValueSerialize: SerializeNativeBindingObject detachNative == nullptr";
notSupport_ = true;
return;
}
void *buffer = detachNative(enginePointer, objPointer, hint, detachData);
AttachFunc attachNative = reinterpret_cast<AttachFunc>(info->attachFunc);
data_->WriteEncodeFlag(EncodeFlag::NATIVE_BINDING_OBJECT);
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(attachNative));
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(buffer));
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(hint));
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(attachData));
}
bool ValueSerializer::SerializeJSArrayBufferPrologue(TaggedObject *object)
{
ASSERT(object->GetClass()->IsArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(object);
if (arrayBuffer->IsDetach()) {
LOG_ECMA(ERROR) << "ValueSerialize: don't support serialize detached array buffer";
notSupport_ = true;
return false;
}
bool transfer = transferDataSet_.find(ToUintPtr(object)) != transferDataSet_.end();
size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
if (arrayLength > 0) {
if (defaultTransfer_ || transfer) {
data_->WriteEncodeFlag(EncodeFlag::TRANSFER_ARRAY_BUFFER);
return true;
} else {
data_->WriteEncodeFlag(EncodeFlag::ARRAY_BUFFER);
data_->WriteUint32(arrayLength);
JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
data_->WriteRawData(static_cast<uint8_t *>(np->GetExternalPointer()), arrayLength);
}
}
return false;
}
void ValueSerializer::SerializeJSSharedArrayBufferPrologue(TaggedObject *object)
{
ASSERT(object->GetClass()->IsSharedArrayBuffer());
JSArrayBuffer *arrayBuffer = reinterpret_cast<JSArrayBuffer *>(object);
bool transfer = transferDataSet_.find(ToUintPtr(object)) != transferDataSet_.end();
if (arrayBuffer->IsDetach() || transfer) {
LOG_ECMA(ERROR) << "ValueSerialize: don't support serialize detached or transfer shared array buffer";
notSupport_ = true;
return;
}
size_t arrayLength = arrayBuffer->GetArrayBufferByteLength();
if (arrayLength > 0) {
JSNativePointer *np = reinterpret_cast<JSNativePointer *>(arrayBuffer->GetArrayBufferData().GetTaggedObject());
void *buffer = np->GetExternalPointer();
if(JSSharedMemoryManager::GetInstance()->CreateOrLoad(&buffer, arrayLength)) {
LOG_ECMA(ERROR) << "ValueSerialize: can't find buffer form shared memory pool";
notSupport_ = true;
return;
}
}
}
void ValueSerializer::SerializeMethodPrologue(Method *method)
{
JSTaggedValue constPoolVal = method->GetConstantPool();
if (!constPoolVal.IsHeapObject()) {
return;
}
ConstantPool *constPool = reinterpret_cast<ConstantPool *>(constPoolVal.GetTaggedObject());
const JSPandaFile *jsPandaFile = constPool->GetJSPandaFile();
data_->WriteEncodeFlag(EncodeFlag::METHOD);
data_->WriteJSTaggedType(method->GetLiteralInfo());
data_->WriteJSTaggedType(reinterpret_cast<JSTaggedType>(jsPandaFile));
}
bool ValueSerializer::PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer)
{
if (transfer->IsUndefined()) {
return true;
}
if (!transfer->IsJSArray()) {
return false;
}
int len = base::ArrayHelper::GetArrayLength(thread, transfer);
int k = 0;
while (k < len) {
bool exists = JSTaggedValue::HasProperty(thread, transfer, k);
if (exists) {
JSHandle<JSTaggedValue> element = JSArray::FastGetPropertyByValue(thread, transfer, k);
if (!element->IsArrayBuffer()) {
return false;
}
transferDataSet_.insert(static_cast<uintptr_t>(element.GetTaggedType()));
}
k++;
}
return true;
}
} // namespace panda::ecmascript

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_SERIALIZER_VALUE_SERIALIZER_H
#define ECMASCRIPT_SERIALIZER_VALUE_SERIALIZER_H
#include "ecmascript/serializer/base_serializer-inl.h"
namespace panda::ecmascript {
class ValueSerializer : public BaseSerializer {
public:
explicit ValueSerializer(JSThread *thread) : BaseSerializer(thread) {}
~ValueSerializer() override = default;
NO_COPY_SEMANTIC(ValueSerializer);
NO_MOVE_SEMANTIC(ValueSerializer);
bool WriteValue(JSThread *thread, const JSHandle<JSTaggedValue> &value, const JSHandle<JSTaggedValue> &transfer);
private:
void SerializeObjectImpl(TaggedObject *object, bool isWeak = false) override;
void SerializeNativeBindingObject(TaggedObject *object);
bool SerializeJSArrayBufferPrologue(TaggedObject *object);
void SerializeJSSharedArrayBufferPrologue(TaggedObject *object);
void SerializeMethodPrologue(Method *method);
void InitTransferSet(CUnorderedSet<uintptr_t> transferDataSet);
void ClearTransferSet();
bool PrepareTransfer(JSThread *thread, const JSHandle<JSTaggedValue> &transfer);
bool CheckObjectCanSerialize(TaggedObject *object);
bool IsInternalJSType(JSType type)
{
return type >= JSType::HCLASS && type <= JSType::TYPE_LAST;
}
private:
bool defaultTransfer_ {false};
bool notSupport_ {false};
CUnorderedSet<uintptr_t> transferDataSet_;
};
}
#endif // ECMASCRIPT_SERIALIZER_BASE_SERIALIZER_H

View File

@ -21,22 +21,17 @@
namespace panda::ecmascript {
void SnapshotEnv::Initialize()
{
#if ECMASCRIPT_ENABLE_SNAPSHOT
InitGlobalConst();
InitGlobalEnv();
#endif
}
void SnapshotEnv::InitGlobalConst()
{
auto globalConst = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
size_t constantCount = globalConst->GetConstantCount();
for (size_t index = 0; index < constantCount; index++) {
for (size_t index = 0; index < globalConst->GetConstantCount(); index++) {
JSTaggedValue objectValue = globalConst->GetGlobalConstantObject(index);
if (objectValue.IsHeapObject() && !objectValue.IsString()) {
TaggedObject *object = objectValue.GetTaggedObject();
object->GetClass()->SetGlobalConstOrBuiltinsObject(true);
objectVector_.emplace_back(ToUintPtr(object));
if (objectValue.IsHeapObject()) {
rootObjectMap_.emplace(ToUintPtr(objectValue.GetTaggedObject()), index);
}
}
}
@ -44,55 +39,20 @@ void SnapshotEnv::InitGlobalConst()
void SnapshotEnv::InitGlobalEnv()
{
auto globalEnv = vm_->GetGlobalEnv();
CQueue<TaggedObject *> objectQueue;
std::set<TaggedObject *> objectSet;
objectQueue.emplace(*globalEnv);
objectSet.emplace(*globalEnv);
while (!objectQueue.empty()) {
auto taggedObject = objectQueue.front();
if (taggedObject == nullptr) {
break;
auto globalConst = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
size_t globalEnvIndexStart = globalConst->GetConstantCount();
for (size_t index = 0; index < globalEnv->GetGlobalEnvFieldSize(); index++) {
JSHandle<JSTaggedValue> objectValue = globalEnv->GetGlobalEnvObjectByIndex(index);
if (objectValue->IsHeapObject() && !objectValue->IsInternalAccessor()) {
rootObjectMap_.emplace(ToUintPtr(objectValue->GetTaggedObject()), index + globalEnvIndexStart);
}
taggedObject->GetClass()->SetGlobalConstOrBuiltinsObject(true);
objectVector_.emplace_back(ToUintPtr(taggedObject));
objectQueue.pop();
HandleObjectField(taggedObject, &objectQueue, &objectSet);
}
}
void SnapshotEnv::HandleObjectField(TaggedObject *objectHeader, CQueue<TaggedObject *> *objectQueue,
std::set<TaggedObject *> *objectSet)
{
auto visitor = [objectQueue, objectSet](TaggedObject *root, ObjectSlot start, ObjectSlot end,
VisitObjectArea area) {
auto hclass = root->GetClass();
int index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
if (area == VisitObjectArea::IN_OBJECT && !hclass->IsAllTaggedProp()) {
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
auto attr = layout->GetAttr(index++);
if (!attr.IsTaggedRep()) {
continue;
}
}
auto fieldAddr = reinterpret_cast<JSTaggedType *>(slot.SlotAddress());
JSTaggedValue fieldValue(*fieldAddr);
if (fieldValue.IsHeapObject() && !fieldValue.IsWeak() && !fieldValue.IsString()
&& objectSet->find(fieldValue.GetTaggedObject()) == objectSet->end()) {
auto object = fieldValue.GetTaggedObject();
objectQueue->emplace(object);
objectSet->emplace(object);
}
}
};
objXRay_.VisitObjectBody<VisitType::OLD_GC_VISIT>(objectHeader, objectHeader->GetClass(), visitor);
}
void SnapshotEnv::Iterate(const RootVisitor &v)
{
uint64_t length = objectVector_.size();
for (uint64_t i = 0; i < length; i++) {
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(objectVector_.data()[i]))));
for (auto &it : rootObjectMap_) {
v(Root::ROOT_VM, ObjectSlot(reinterpret_cast<uintptr_t>(&(it.first))));
}
}
} // namespace panda::ecmascript

View File

@ -32,27 +32,31 @@ public:
void Initialize();
void Iterate(const RootVisitor &v);
void ClearEnvMap()
{
objectVector_.clear();
rootObjectMap_.clear();
}
size_t GetEnvObjectIndex(uintptr_t objectAddr) const
void Iterate(const RootVisitor &v);
uint32_t FindEnvObjectIndex(uintptr_t objectAddr) const
{
auto it = std::find(objectVector_.begin(), objectVector_.end(), objectAddr);
if (it == objectVector_.end()) {
return MAX_UINT_32;
} else {
return std::distance(objectVector_.begin(), it);
if (rootObjectMap_.find(objectAddr) != rootObjectMap_.end()) {
return rootObjectMap_.find(objectAddr)->second;
}
return MAX_UINT_32;
}
uintptr_t FindEnvObjectByIndex(size_t index)
JSTaggedType RelocateRootObjectAddr(uint32_t index)
{
ASSERT(index < objectVector_.size());
return objectVector_.at(index);
auto globalConst = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
size_t globalConstCount = globalConst->GetConstantCount();
if (index < globalConstCount) {
JSTaggedValue obj = globalConst->GetGlobalConstantObject(index);
return obj.GetRawData();
}
JSHandle<JSTaggedValue> value = vm_->GetGlobalEnv()->GetNoLazyEnvObjectByIndex(index - globalConstCount);
return value->GetRawData();
}
static constexpr size_t MAX_UINT_32 = 0xFFFFFFFF;
@ -61,14 +65,12 @@ private:
NO_MOVE_SEMANTIC(SnapshotEnv);
NO_COPY_SEMANTIC(SnapshotEnv);
void HandleObjectField(TaggedObject *objectHeader, CQueue<TaggedObject *> *objectQueue,
std::set<TaggedObject *> *objectSet);
void InitGlobalConst();
void InitGlobalEnv();
EcmaVM *vm_;
ObjectXRay objXRay_;
CVector<uintptr_t> objectVector_;
CUnorderedMap<uintptr_t, uint32_t> rootObjectMap_;
};
} // namespace panda::ecmascript
#endif // ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_ENV_H

View File

@ -1492,9 +1492,7 @@ bool SnapshotProcessor::VisitObjectBodyWithRep(TaggedObject *root, ObjectSlot sl
return false;
}
auto hclass = root->GetClass();
if (hclass->IsAllTaggedProp()) {
return false;
}
ASSERT(!hclass->IsAllTaggedProp());
auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
auto attr = layout->GetAttr(index++);
if (attr.GetRepresentation() == Representation::DOUBLE) {
@ -1644,7 +1642,7 @@ void SnapshotProcessor::DeserializeTaggedField(uint64_t *value, TaggedObject *ro
EncodeBit encodeBit(*value);
if (!builtinsDeserialize_ && encodeBit.IsReference() && encodeBit.IsGlobalConstOrBuiltins()) {
size_t index = encodeBit.GetNativePointerOrObjectIndex();
*value = vm_->GetSnapshotEnv()->FindEnvObjectByIndex(index);
*value = vm_->GetSnapshotEnv()->RelocateRootObjectAddr(index);
return;
}
@ -1842,14 +1840,12 @@ EncodeBit SnapshotProcessor::EncodeTaggedObject(TaggedObject *objectHeader, CQue
}
// builtins object reuse
if (objectHeader->GetClass()->IsGlobalConstOrBuiltinsObject()) {
size_t index = vm_->GetSnapshotEnv()->GetEnvObjectIndex(ToUintPtr(objectHeader));
if (index != SnapshotEnv::MAX_UINT_32) {
EncodeBit encodeBit(index);
encodeBit.SetGlobalConstOrBuiltins();
data->emplace(ToUintPtr(objectHeader), std::make_pair(0U, encodeBit));
return encodeBit;
}
size_t index = vm_->GetSnapshotEnv()->FindEnvObjectIndex(ToUintPtr(objectHeader));
if (index != SnapshotEnv::MAX_UINT_32) {
EncodeBit encodeBit(index);
encodeBit.SetGlobalConstOrBuiltins();
data->emplace(ToUintPtr(objectHeader), std::make_pair(0U, encodeBit));
return encodeBit;
}
}
auto oldObjHeader = objectHeader;

View File

@ -90,7 +90,7 @@ public:
DEFINE_ALIGN_SIZE(LAST_OFFSET);
static constexpr size_t DATA_OFFSET = SIZE; // DATA_OFFSET equal to Empty Array size
DECL_VISIT_ARRAY(DATA_OFFSET, GetLength());
DECL_VISIT_ARRAY(DATA_OFFSET, GetLength(), GetLength());
DECL_DUMP()
private:

View File

@ -43,12 +43,6 @@ public:
static constexpr size_t SIZE = DATA_OFFSET;
DECL_VISIT_OBJECT(HASH_OFFSET, SIZE);
void VisitObjects(const EcmaObjectRangeVisitor &visitor)
{
// no field in this object
VisitRangeSlot(visitor);
}
static int Hash(JSTaggedValue key)
{
if (key.IsDouble() && key.GetDouble() == 0.0) {
@ -99,11 +93,13 @@ public:
}
static constexpr size_t NEXT_OFFSET = TaggedNode::SIZE;
ACCESSORS(Next, NEXT_OFFSET, DATA_OFFSET);
static constexpr size_t SIZE = DATA_OFFSET;
DECL_VISIT_OBJECT_FOR_JS_OBJECT(TaggedNode, NEXT_OFFSET, SIZE)
ACCESSORS(Next, NEXT_OFFSET, LAST_OFFSET);
static constexpr size_t SIZE = LAST_OFFSET;
DECL_VISIT_OBJECT(TaggedObject::SIZE, SIZE)
DECL_DUMP()
static JSHandle<RBTreeNode> Treeing(JSThread *thread, const JSHandle<LinkedNode> &head);
};
@ -128,7 +124,7 @@ public:
ACCESSORS_PRIMITIVE_FIELD(Count, uint32_t, COUNT_OFFSET, LAST_OFFSET)
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_OBJECT_FOR_JS_OBJECT(TaggedNode, LEFT_OFFSET, COUNT_OFFSET)
DECL_VISIT_OBJECT(TaggedObject::SIZE, COUNT_OFFSET)
void InitRBTreeNode(JSThread *thread, int hash, JSHandle<JSTaggedValue> key,
JSHandle<JSTaggedValue> value, int count);

View File

@ -220,6 +220,7 @@ public:
ACCESSORS_ATTACHED_TYPEREF(ElementGT, ELEMENT_GT_OFFSET, LAST_OFFSET);
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_PRIMITIVE_OBJECT()
DECL_DUMP()
};
@ -235,6 +236,7 @@ public:
ACCESSORS_ATTACHED_TYPEREF(KindGT, KIND_GT_OFFSET, ELEMENT_GT_OFFSET);
ACCESSORS_ATTACHED_TYPEREF(ElementGT, ELEMENT_GT_OFFSET, LAST_OFFSET);
DEFINE_ALIGN_SIZE(LAST_OFFSET);
DECL_VISIT_PRIMITIVE_OBJECT()
DECL_DUMP()
};

View File

@ -317,6 +317,11 @@
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>
</preparer>
</target>
<target name="SerializerTest">
<preparer>
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>
</preparer>
</target>
<target name="EcmaVm_001_Test">
<preparer>
<option name="push" value="test/test/libark_jsruntime_test.so -> /data/test" src="out"/>