mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-11-23 01:59:58 +00:00
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:
parent
9cc8a59978
commit
8f5e2fa5b4
5
BUILD.gn
5
BUILD.gn
@ -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",
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -71,6 +71,7 @@ private:
|
||||
CUnorderedMultiMap<uint32_t, EcmaString *> table_;
|
||||
const EcmaVM *vm_{nullptr};
|
||||
friend class SnapshotProcessor;
|
||||
friend class BaseDeserializer;
|
||||
};
|
||||
} // namespace panda::ecmascript
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
|
48
ecmascript/mem/layout_visitor.h
Normal file
48
ecmascript/mem/layout_visitor.h
Normal 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
|
@ -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()
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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_;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -43,6 +43,7 @@ public:
|
||||
}
|
||||
|
||||
static constexpr int HCLASS_OFFSET = 0;
|
||||
static constexpr int SIZE = sizeof(MarkWordType);
|
||||
|
||||
JSThread* GetJSThread() const;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
510
ecmascript/serializer/base_deserializer.cpp
Normal file
510
ecmascript/serializer/base_deserializer.cpp
Normal 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 ®ionIndex)
|
||||
{
|
||||
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
|
||||
|
153
ecmascript/serializer/base_deserializer.h
Normal file
153
ecmascript/serializer/base_deserializer.h
Normal 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 ®ionIndex);
|
||||
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
|
70
ecmascript/serializer/base_serializer-inl.h
Normal file
70
ecmascript/serializer/base_serializer-inl.h
Normal 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
|
236
ecmascript/serializer/base_serializer.cpp
Normal file
236
ecmascript/serializer/base_serializer.cpp
Normal 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
|
||||
|
72
ecmascript/serializer/base_serializer.h
Normal file
72
ecmascript/serializer/base_serializer.h
Normal 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
|
230
ecmascript/serializer/serialize_data.h
Normal file
230
ecmascript/serializer/serialize_data.h
Normal 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
|
49
ecmascript/serializer/tests/BUILD.gn
Normal file
49
ecmascript/serializer/tests/BUILD.gn
Normal 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" ]
|
||||
}
|
1322
ecmascript/serializer/tests/serializer_test.cpp
Normal file
1322
ecmascript/serializer/tests/serializer_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
274
ecmascript/serializer/value_serializer.cpp
Normal file
274
ecmascript/serializer/value_serializer.cpp
Normal 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
|
||||
|
55
ecmascript/serializer/value_serializer.h
Normal file
55
ecmascript/serializer/value_serializer.h
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
};
|
||||
|
@ -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"/>
|
||||
|
Loading…
Reference in New Issue
Block a user