modify transitions to weak reference

1.modify transitions to weak reference and delete parent field in JSHClass.
2.add targeted test case to intercept the issue.
3.fix weak ref in parallel gc
4.fix TaggedCastToWeakReferentUnChecked() in stub

Change-Id: I118d293a04390fba6c21179a0a8ac7993dae5e96
Signed-off-by: ding <dingding5@huawei.com>
This commit is contained in:
ding 2022-03-11 17:30:43 +08:00
parent 1e538180ef
commit 197e0a317c
25 changed files with 249 additions and 153 deletions

View File

@ -1492,7 +1492,7 @@ GateRef Stub::SetPrototypeToHClass(VariableType type, GateRef glue, GateRef hCla
GateRef Stub::SetProtoChangeDetailsToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef protoChange)
{
GateRef offset = GetIntPtrConstant(JSHClass::PROTOTYPE_INFO_OFFSET);
GateRef offset = GetIntPtrConstant(JSHClass::PROTO_CHANGE_DETAILS_OFFSET);
return Store(type, glue, hClass, offset, protoChange);
}
@ -1502,12 +1502,6 @@ GateRef Stub::SetLayoutToHClass(VariableType type, GateRef glue, GateRef hClass,
return Store(type, glue, hClass, offset, attr);
}
GateRef Stub::SetParentToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef parent)
{
GateRef offset = GetIntPtrConstant(JSHClass::PARENT_OFFSET);
return Store(type, glue, hClass, offset, parent);
}
GateRef Stub::SetEnumCacheToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef key)
{
GateRef offset = GetIntPtrConstant(JSHClass::ENUM_CACHE_OFFSET);
@ -1770,6 +1764,7 @@ GateRef Stub::TaggedCastToDouble(GateRef x)
GateRef Stub::TaggedCastToWeakReferentUnChecked(GateRef x)
{
x = ChangeTaggedPointerToInt64(x);
return Int64And(x, GetInt64Constant(~JSTaggedValue::TAG_WEAK_MASK));
}

View File

@ -2245,8 +2245,7 @@ void Stub::CopyAllHClass(GateRef glue, GateRef dstHClass, GateRef srcHClass)
SetPrototypeToHClass(VariableType::JS_POINTER(), glue, dstHClass, proto);
SetBitFieldToHClass(glue, dstHClass, GetBitFieldFromHClass(srcHClass));
SetNumberOfPropsToHClass(glue, dstHClass, GetNumberOfPropsFromHClass(srcHClass));
SetParentToHClass(VariableType::INT64(), glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL));
SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL));
SetTransitionsToHClass(VariableType::INT64(), glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_UNDEFINED));
SetProtoChangeDetailsToHClass(VariableType::INT64(), glue, dstHClass,
GetInt64Constant(JSTaggedValue::VALUE_NULL));
SetEnumCacheToHClass(VariableType::INT64(), glue, dstHClass, GetInt64Constant(JSTaggedValue::VALUE_NULL));
@ -2265,18 +2264,19 @@ GateRef Stub::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, Ga
GateRef transition = Load(VariableType::JS_POINTER(), hclass, transitionOffset);
DEFVARIABLE(result, VariableType::JS_ANY(), transition);
Label notNull(env);
Branch(Int64Equal(transition, GetInt64Constant(JSTaggedValue::VALUE_NULL)), &exit, &notNull);
Bind(&notNull);
Label notUndefined(env);
Branch(Int64Equal(transition, GetUndefinedConstant()), &exit, &notUndefined);
Bind(&notUndefined);
{
Label isJSHClass(env);
Label notJSHClass(env);
Branch(IsJSHClass(transition), &isJSHClass, &notJSHClass);
Bind(&isJSHClass);
Label isWeak(env);
Label notWeak(env);
Branch(TaggedIsWeak(transition), &isWeak, &notWeak);
Bind(&isWeak);
{
GateRef propNums = GetNumberOfPropsFromHClass(transition);
GateRef transitionHClass = TaggedCastToWeakReferentUnChecked(transition);
GateRef propNums = GetNumberOfPropsFromHClass(transitionHClass);
GateRef last = Int32Sub(propNums, GetInt32Constant(1));
GateRef layoutInfo = GetLayoutFromHClass(transition);
GateRef layoutInfo = GetLayoutFromHClass(transitionHClass);
GateRef cachedKey = GetKeyFromLayoutInfo(layoutInfo, last);
GateRef cachedAttr = TaggedCastToInt32(GetPropAttrFromLayoutInfo(layoutInfo, last));
GateRef cachedMetaData = GetPropertyMetaDataFromAttr(cachedAttr);
@ -2290,9 +2290,9 @@ GateRef Stub::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, Ga
Bind(&isMatch);
{
#if ECMASCRIPT_ENABLE_IC
NotifyHClassChanged(glue, hclass, transition);
NotifyHClassChanged(glue, hclass, transitionHClass);
#endif
StoreHClass(glue, receiver, transition);
StoreHClass(glue, receiver, transitionHClass);
Jump(&exit);
}
}
@ -2302,7 +2302,7 @@ GateRef Stub::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, Ga
Jump(&exit);
}
}
Bind(&notJSHClass);
Bind(&notWeak);
{
// need to find from dictionary
GateRef entry = FindEntryFromTransitionDictionary(glue, transition, key, metaData);
@ -2310,17 +2310,30 @@ GateRef Stub::FindTransitions(GateRef glue, GateRef receiver, GateRef hclass, Ga
Label notFound(env);
Branch(Int32NotEqual(entry, GetInt32Constant(-1)), &isFound, &notFound);
Bind(&isFound);
auto newHClass = GetValueFromDictionary<TransitionsDictionary>(
auto value = GetValueFromDictionary<TransitionsDictionary>(
VariableType::JS_POINTER(), transition, entry);
result = newHClass;
Label valueUndefined(env);
Label valueNotUndefined(env);
Branch(Int64NotEqual(value, GetUndefinedConstant()), &valueNotUndefined,
&valueUndefined);
Bind(&valueNotUndefined);
{
GateRef newHClass = TaggedCastToWeakReferentUnChecked(value);
result = ChangeInt64ToTagged(newHClass);
#if ECMASCRIPT_ENABLE_IC
NotifyHClassChanged(glue, hclass, newHClass);
NotifyHClassChanged(glue, hclass, newHClass);
#endif
StoreHClass(glue, receiver, newHClass);
Jump(&exit);
Bind(&notFound);
result = GetNullConstant();
Jump(&exit);
StoreHClass(glue, receiver, newHClass);
Jump(&exit);
Bind(&notFound);
result = GetNullConstant();
Jump(&exit);
}
Bind(&valueUndefined);
{
result = GetNullConstant();
Jump(&exit);
}
}
}
Bind(&exit);

View File

@ -676,7 +676,6 @@ public:
inline GateRef SetProtoChangeDetailsToHClass(VariableType type, GateRef glue, GateRef hClass,
GateRef protoChange);
inline GateRef SetLayoutToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef attr);
inline GateRef SetParentToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef parent);
inline GateRef SetEnumCacheToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef key);
inline GateRef SetTransitionsToHClass(VariableType type, GateRef glue, GateRef hClass, GateRef transition);
inline void SetIsProtoTypeToHClass(GateRef glue, GateRef hClass, GateRef value);

View File

@ -522,6 +522,9 @@ void HeapSnapShot::FillEdges(JSThread *thread)
for (auto const &it : nameResources) {
JSTaggedValue toValue = it.second;
Node *entryTo = nullptr;
if (toValue.IsWeak()) {
toValue.RemoveWeakTag();
}
if (toValue.IsHeapObject()) {
auto *to = reinterpret_cast<TaggedObject *>(toValue.GetHeapObject());
entryTo = entryMap_.FindEntry(Node::NewAddress(to));

View File

@ -357,9 +357,6 @@ static void DumpHClass(JSThread *thread, const JSHClass *jshclass, std::ostream
if (withDetail && !transtions.IsNull()) {
transtions.Dump(thread, os);
}
os << " - Parent :" << std::setw(DUMP_TYPE_OFFSET);
jshclass->GetParent().DumpTaggedValue(thread, os);
os << "\n";
os << " - Flags : " << std::setw(DUMP_TYPE_OFFSET);
os << "Ctor :" << jshclass->IsConstructor();
@ -724,7 +721,7 @@ void JSTaggedValue::DumpHeapObjectType([[maybe_unused]] JSThread *thread, std::o
<< "\n";
}
JSType type = GetTaggedObject()->GetClass()->GetObjectType();
JSType type = obj->GetClass()->GetObjectType();
if (type == JSType::STRING) {
CString string = ConvertToString(EcmaString::Cast(obj));
os << std::left << std::setw(DUMP_TYPE_OFFSET) << "[" + string + "]";

View File

@ -33,14 +33,14 @@ void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &
const JSHandle<JSTaggedValue> &key, PropertyAttributes attributes)
{
JSTaggedValue transitions = parent->GetTransitions();
if (transitions.IsNull()) {
parent->SetTransitions(thread, child.GetTaggedValue());
child->SetParent(thread, parent.GetTaggedValue());
if (transitions.IsUndefined()) {
JSTaggedValue weakChild = JSTaggedValue(child.GetTaggedValue().CreateAndGetWeakRef());
parent->SetTransitions(thread, weakChild);
return;
}
JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
if (transitions.IsJSHClass()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedObject());
if (transitions.IsWeak()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
int last = cachedHClass->NumberOfProps() - 1;
LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
@ -54,7 +54,6 @@ void JSHClass::AddTransitions(const JSThread *thread, const JSHandle<JSHClass> &
transitions =
TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), attr).GetTaggedValue();
parent->SetTransitions(thread, transitions);
child->SetParent(thread, parent.GetTaggedValue());
}
void JSHClass::AddExtensionTransitions(const JSThread *thread, const JSHandle<JSHClass> &parent,
@ -70,10 +69,10 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHCla
{
JSTaggedValue transitions = parent->GetTransitions();
JSMutableHandle<TransitionsDictionary> dict(thread, JSTaggedValue::Undefined());
if (transitions.IsNull()) {
if (transitions.IsUndefined()) {
transitions = TransitionsDictionary::Create(thread).GetTaggedValue();
} else if (transitions.IsJSHClass()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedObject());
} else if (transitions.IsWeak()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
int last = cachedHClass->NumberOfProps() - 1;
LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
auto attr = JSHandle<JSTaggedValue>(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData()));
@ -87,18 +86,17 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle<JSHCla
transitions =
TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle<JSTaggedValue>(child), proto).GetTaggedValue();
parent->SetTransitions(thread, transitions);
child->SetParent(thread, parent.GetTaggedValue());
}
inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTaggedValue &attributes)
{
DISALLOW_GARBAGE_COLLECTION;
JSTaggedValue transitions = GetTransitions();
if (transitions.IsNull()) {
if (transitions.IsUndefined()) {
return nullptr;
}
if (transitions.IsJSHClass()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedObject());
if (transitions.IsWeak()) {
auto cachedHClass = JSHClass::Cast(transitions.GetTaggedWeakRef());
int last = cachedHClass->NumberOfProps() - 1;
LayoutInfo *layoutInfo = LayoutInfo::Cast(cachedHClass->GetLayout().GetTaggedObject());
auto attr = layoutInfo->GetAttr(last).GetPropertyMetaData();
@ -115,15 +113,21 @@ inline JSHClass *JSHClass::FindTransitions(const JSTaggedValue &key, const JSTag
if (entry == -1) {
return nullptr;
}
return JSHClass::Cast(dict->GetValue(entry).GetTaggedObject());
JSTaggedValue ret = dict->GetValue(entry);
if (ret.IsUndefined()) {
return nullptr;
}
return JSHClass::Cast(ret.GetTaggedWeakRef());
}
inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const JSTaggedValue &proto)
{
DISALLOW_GARBAGE_COLLECTION;
JSTaggedValue transitions = GetTransitions();
if (!transitions.IsTaggedArray()) {
ASSERT(transitions.IsNull() || transitions.IsJSHClass());
if (transitions.IsWeak() || !transitions.IsTaggedArray()) {
ASSERT(transitions.IsUndefined() || transitions.IsWeak());
return nullptr;
}
ASSERT(transitions.IsTaggedArray());
@ -132,7 +136,13 @@ inline JSHClass *JSHClass::FindProtoTransitions(const JSTaggedValue &key, const
if (entry == -1) {
return nullptr;
}
return JSHClass::Cast(dict->GetValue(entry).GetTaggedObject());
JSTaggedValue ret = dict->GetValue(entry);
if (ret.IsUndefined()) {
return nullptr;
}
return JSHClass::Cast(ret.GetTaggedWeakRef());
}
inline void JSHClass::UpdatePropertyMetaData(const JSThread *thread, [[maybe_unused]] const JSTaggedValue &key,

View File

@ -27,7 +27,6 @@
#include "ecmascript/weak_vector-inl.h"
namespace panda::ecmascript {
// class TransitionsDictionary
JSHandle<TransitionsDictionary> TransitionsDictionary::PutIfAbsent(const JSThread *thread,
const JSHandle<TransitionsDictionary> &dictionary,
const JSHandle<JSTaggedValue> &key,
@ -46,7 +45,8 @@ JSHandle<TransitionsDictionary> TransitionsDictionary::PutIfAbsent(const JSThrea
JSHandle<TransitionsDictionary> newDictionary(HashTableT::GrowHashTable(thread, dictionary));
// Compute the key object.
entry = newDictionary->FindInsertIndex(hash);
newDictionary->SetEntry(thread, entry, key.GetTaggedValue(), value.GetTaggedValue(), metaData.GetTaggedValue());
JSTaggedValue val = value.GetTaggedValue();
newDictionary->SetEntry(thread, entry, key.GetTaggedValue(), val, metaData.GetTaggedValue());
newDictionary->IncreaseEntries(thread);
return newDictionary;
@ -135,8 +135,7 @@ void JSHClass::Initialize(const JSThread *thread, uint32_t size, JSType type, ui
SetExtensible(true);
SetIsPrototype(false);
SetElementRepresentation(Representation::NONE);
SetTransitions(thread, JSTaggedValue::Null());
SetParent(thread, JSTaggedValue::Null());
SetTransitions(thread, JSTaggedValue::Undefined());
SetProtoChangeMarker(thread, JSTaggedValue::Null());
SetProtoChangeDetails(thread, JSTaggedValue::Null());
SetEnumCache(thread, JSTaggedValue::Null());
@ -151,8 +150,7 @@ JSHandle<JSHClass> JSHClass::Clone(const JSThread *thread, const JSHandle<JSHCla
JSHandle<JSHClass> newJshclass = thread->GetEcmaVM()->GetFactory()->NewEcmaDynClass(size, type, numInlinedProps);
// Copy all
newJshclass->Copy(thread, *jshclass);
newJshclass->SetParent(thread, JSTaggedValue::Null());
newJshclass->SetTransitions(thread, JSTaggedValue::Null());
newJshclass->SetTransitions(thread, JSTaggedValue::Undefined());
newJshclass->SetProtoChangeDetails(thread, JSTaggedValue::Null());
newJshclass->SetEnumCache(thread, JSTaggedValue::Null());
// reuse Attributes first.
@ -266,9 +264,9 @@ JSHandle<JSHClass> JSHClass::TransitionProto(const JSThread *thread, const JSHan
JSHandle<JSHClass> newJshclass = JSHClass::Clone(thread, jshclass);
newJshclass->SetPrototype(thread, proto.GetTaggedValue());
JSTaggedValue attrs = newJshclass->GetLayout();
JSTaggedValue layout = newJshclass->GetLayout();
{
JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, attrs);
JSMutableHandle<LayoutInfo> layoutInfoHandle(thread, layout);
layoutInfoHandle.Update(factory->CopyLayoutInfo(layoutInfoHandle).GetTaggedValue());
newJshclass->SetLayout(thread, layoutInfoHandle);
}

View File

@ -1105,10 +1105,9 @@ public:
static constexpr size_t PROTOTYPE_OFFSET = TaggedObjectSize();
ACCESSORS(Proto, PROTOTYPE_OFFSET, LAYOUT_OFFSET);
ACCESSORS(Layout, LAYOUT_OFFSET, TRANSTIONS_OFFSET);
ACCESSORS(Transitions, TRANSTIONS_OFFSET, PARENT_OFFSET);
ACCESSORS(Parent, PARENT_OFFSET, VALIDITY_CELL_OFFSET);
ACCESSORS(ProtoChangeMarker, VALIDITY_CELL_OFFSET, PROTOTYPE_INFO_OFFSET);
ACCESSORS(ProtoChangeDetails, PROTOTYPE_INFO_OFFSET, ENUM_CACHE_OFFSET);
ACCESSORS(Transitions, TRANSTIONS_OFFSET, PROTO_CHANGE_MARKER_OFFSET);
ACCESSORS(ProtoChangeMarker, PROTO_CHANGE_MARKER_OFFSET, PROTO_CHANGE_DETAILS_OFFSET);
ACCESSORS(ProtoChangeDetails, PROTO_CHANGE_DETAILS_OFFSET, ENUM_CACHE_OFFSET);
ACCESSORS(EnumCache, ENUM_CACHE_OFFSET, BIT_FIELD_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(BitField, uint32_t, BIT_FIELD_OFFSET, BIT_FIELD1_OFFSET);
ACCESSORS_PRIMITIVE_FIELD(BitField1, uint32_t, BIT_FIELD1_OFFSET, LAST_OFFSET)

View File

@ -48,6 +48,7 @@ public:
parser->Add(&enableCpuprofiler_);
parser->Add(&arkProperties_);
parser->Add(&enableTsAot_);
parser->Add(&maxNonmovableSpaceCapacity_);
}
bool IsEnableArkTools() const

View File

@ -227,9 +227,31 @@ void ParallelEvacuation::UpdateRoot()
objXRay_.VisitVMRoots(gcUpdateYoung, gcUpdateRangeYoung);
}
void ParallelEvacuation::UpdateRecordWeakReference()
{
auto totalThreadCount = Platform::GetCurrentPlatform()->GetTotalThreadNum() + 1;
for (uint32_t i = 0; i < totalThreadCount; i++) {
ProcessQueue *queue = heap_->GetWorkList()->GetWeakReferenceQueue(i);
while (true) {
auto obj = queue->PopBack();
if (UNLIKELY(obj == nullptr)) {
break;
}
ObjectSlot slot(ToUintPtr(obj));
JSTaggedValue value(slot.GetTaggedType());
ASSERT(value.IsWeak() || value.IsUndefined());
if (!value.IsUndefined()) {
UpdateWeakObjectSlot(value.GetTaggedWeakRef(), slot);
}
}
}
}
void ParallelEvacuation::UpdateWeakReference()
{
MEM_ALLOCATE_AND_GC_TRACE(heap_->GetEcmaVM(), UpdateWeakReference);
UpdateRecordWeakReference();
auto stringTable = heap_->GetEcmaVM()->GetEcmaStringTable();
bool isFullMark = heap_->IsFullMark();
WeakRootVisitor gcUpdateWeak = [isFullMark](TaggedObject *header) {

View File

@ -130,6 +130,7 @@ private:
void UpdateReference();
void UpdateRoot();
void UpdateWeakReference();
void UpdateRecordWeakReference();
void UpdateRSet(Region *region);
void UpdateNewRegionReference(Region *region);
void UpdateAndSweepNewRegionReference(Region *region);

View File

@ -59,6 +59,10 @@ inline void NonMovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused
for (ObjectSlot slot = start; slot < end; slot++) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
if (value.IsWeakForHeapObject()) {
RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
continue;
}
MarkObject(threadId, value.GetTaggedObject());
}
}
@ -71,8 +75,12 @@ inline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *regi
oldRSet->IterateOverMarkedChunks([this, threadId](void *mem) -> bool {
ObjectSlot slot(ToUintPtr(mem));
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject() && !value.IsWeakForHeapObject()) {
MarkObject(threadId, value.GetTaggedObject());
if (value.IsHeapObject()) {
if (value.IsWeakForHeapObject()) {
RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(mem));
} else {
MarkObject(threadId, value.GetTaggedObject());
}
}
return true;
});
@ -81,8 +89,9 @@ inline void NonMovableMarker::HandleOldToNewRSet(uint32_t threadId, Region *regi
inline void NonMovableMarker::RecordWeakReference(uint32_t threadId, JSTaggedType *ref)
{
Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(ref));
if (!objectRegion->InYoungGeneration()) {
auto value = JSTaggedValue(*ref);
Region *objectRegion = Region::ObjectAddressToRange(value.GetTaggedWeakRef());
if (!objectRegion->InYoungOrCSetGeneration()) {
heap_->GetWorkList()->PushWeakReference(threadId, ref);
}
}
@ -101,7 +110,11 @@ inline void MovableMarker::HandleRangeRoots(uint32_t threadId, [[maybe_unused]]
for (ObjectSlot slot = start; slot < end; slot++) {
JSTaggedValue value(slot.GetTaggedType());
if (value.IsHeapObject()) {
MarkObject(threadId, value.GetTaggedObject(), slot);
if (value.IsWeakForHeapObject()) {
RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
} else {
MarkObject(threadId, value.GetTaggedObject(), slot);
}
}
}
}

View File

@ -62,6 +62,7 @@ void NonMovableMarker::ProcessMarkStack(uint32_t threadId)
obj = value.GetTaggedObject();
MarkObject(threadId, obj);
} else {
RecordWeakReference(threadId, reinterpret_cast<JSTaggedType *>(slot.SlotAddress()));
obj = value.GetWeakReferentUnChecked();
}
if (needBarrier) {

View File

@ -1042,12 +1042,12 @@ host_unittest_action("MemControllerTest") {
}
}
host_unittest_action("WeakRefGenGcTest") {
host_unittest_action("WeakRefOldGcTest") {
module_out_path = module_output_path
sources = [
# test file
"weak_ref_gen_gc_test.cpp",
"weak_ref_old_gc_test.cpp",
]
configs = [
@ -1069,12 +1069,12 @@ host_unittest_action("WeakRefGenGcTest") {
}
}
host_unittest_action("WeakRefStwGcTest") {
host_unittest_action("WeakRefSemiGcTest") {
module_out_path = module_output_path
sources = [
# test file
"weak_ref_stw_gc_test.cpp",
"weak_ref_semi_gc_test.cpp",
]
configs = [
@ -1223,8 +1223,8 @@ group("unittest") {
":SymbolTableTest",
":TaggedTreeTest",
":TaggedValueTest",
":WeakRefGenGcTest",
":WeakRefStwGcTest",
":WeakRefOldGcTest",
":WeakRefSemiGcTest",
]
}
@ -1273,7 +1273,7 @@ group("host_unittest") {
":SymbolTableTestAction",
":TaggedTreeTestAction",
":TaggedValueTestAction",
":WeakRefGenGcTestAction",
":WeakRefStwGcTestAction",
":WeakRefOldGcTestAction",
":WeakRefSemiGcTestAction",
]
}

View File

@ -500,7 +500,7 @@ HWTEST_F_L0(EcmaDumpTest, HeapProfileDump)
break;
}
case JSType::HCLASS: {
CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 8)
CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 7)
JSHandle<JSHClass> hclass = factory->NewEcmaDynClass(JSHClass::SIZE, JSType::HCLASS, proto);
DUMP_FOR_HANDLE(hclass)
break;

View File

@ -814,50 +814,38 @@ HWTEST_F_L0(JSObjectTest, SetterIsUndefined)
JSTaggedValue(10));
}
HWTEST_F_L0(JSObjectTest, HClass)
HWTEST_F_L0(JSObjectTest, Transitions)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<JSTaggedValue> objFunc(thread, JSObjectTestCreate(thread));
JSHandle<JSObject> obj1 = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
JSHandle<JSHClass> hc0(thread, obj1->GetJSHClass());
JSHandle<JSObject> obj2 = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
JSHandle<JSHClass> hc1(thread, obj1->GetJSHClass());
JSHandle<JSHClass> hc2(thread, obj2->GetJSHClass());
EXPECT_EQ(hc1.GetTaggedValue(), hc2.GetTaggedValue());
JSHandle<JSTaggedValue> key1(factory->NewFromCanBeCompressString("x"));
JSHandle<JSTaggedValue> key2(factory->NewFromCanBeCompressString("y"));
JSHandle<JSTaggedValue> key3(factory->NewFromCanBeCompressString("z"));
JSHandle<JSTaggedValue> value(thread, JSTaggedValue(1));
// key1
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj1), key1, value);
JSHandle<JSHClass> hc1(thread, obj1->GetJSHClass());
EXPECT_NE(hc0.GetTaggedValue(), hc1.GetTaggedValue());
EXPECT_EQ(hc0.GetTaggedValue(), hc1->GetParent());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj1), key2, value);
JSHandle<JSHClass> hc2(thread, obj1->GetJSHClass());
EXPECT_NE(hc1.GetTaggedValue(), hc2.GetTaggedValue());
EXPECT_EQ(hc1.GetTaggedValue(), hc2->GetParent());
JSHandle<JSObject> obj2 = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
EXPECT_EQ(hc0.GetTaggedValue().GetTaggedObject(), obj2->GetJSHClass());
JSHandle<JSHClass> hc3(thread, obj1->GetJSHClass());
EXPECT_NE(hc1.GetTaggedValue(), hc3.GetTaggedValue());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj2), key1, value);
EXPECT_EQ(hc1.GetTaggedValue().GetTaggedObject(), obj2->GetJSHClass());
JSHandle<JSHClass> hc4(thread, obj2->GetJSHClass());
EXPECT_EQ(hc3.GetTaggedValue(), hc4.GetTaggedValue());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj2), key3, value);
JSHandle<JSHClass> hc3(thread, obj2->GetJSHClass());
EXPECT_NE(hc1.GetTaggedValue().GetTaggedObject(), obj2->GetJSHClass());
EXPECT_EQ(hc1.GetTaggedValue(), obj2->GetJSHClass()->GetParent());
// key2
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj1), key2, value);
JSHandle<JSHClass> hc5(thread, obj1->GetJSHClass());
EXPECT_NE(hc3.GetTaggedValue(), hc5.GetTaggedValue());
JSHandle<JSObject> obj3 = factory->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
EXPECT_EQ(hc0.GetTaggedValue().GetTaggedObject(), obj3->GetJSHClass());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj3), key1, value);
EXPECT_EQ(hc1.GetTaggedValue().GetTaggedObject(), obj3->GetJSHClass());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj3), key2, value);
EXPECT_EQ(hc2.GetTaggedValue().GetTaggedObject(), obj3->GetJSHClass());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj3), key3, value);
EXPECT_NE(hc3.GetTaggedValue().GetTaggedObject(), obj3->GetJSHClass());
EXPECT_EQ(hc2.GetTaggedValue(), obj3->GetJSHClass()->GetParent());
JSObject::SetProperty(thread, JSHandle<JSTaggedValue>(obj2), key2, value);
JSHandle<JSHClass> hc6(thread, obj2->GetJSHClass());
EXPECT_EQ(hc5.GetTaggedValue(), hc6.GetTaggedValue());
}
HWTEST_F_L0(JSObjectTest, FastToSlow)

View File

@ -23,7 +23,7 @@
using namespace panda::ecmascript;
namespace panda::test {
class WeakRefGenGCTest : public testing::Test {
class WeakRefOldGCTest : public testing::Test {
public:
static void SetUpTestCase()
{
@ -50,7 +50,6 @@ public:
JSThread *thread {nullptr};
};
#if !defined(NDEBUG)
static JSObject *JSObjectTestCreate(JSThread *thread)
{
[[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
@ -62,9 +61,7 @@ static JSObject *JSObjectTestCreate(JSThread *thread)
ecmaVM->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc1), jsFunc1);
return *newObj;
}
#endif
#if !defined(NDEBUG)
static TaggedArray *ArrayTestCreate(JSThread *thread)
{
[[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
@ -72,11 +69,9 @@ static TaggedArray *ArrayTestCreate(JSThread *thread)
JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2);
return *array;
}
#endif
HWTEST_F_L0(WeakRefGenGCTest, ArrayNonMovable)
HWTEST_F_L0(WeakRefOldGCTest, ArrayNonMovable)
{
#if !defined(NDEBUG)
auto vm = thread->GetEcmaVM();
auto array = vm->GetFactory()->NewTaggedArray(2, JSTaggedValue::Undefined(), true);
JSHandle<JSObject> newObj1(thread, JSObjectTestCreate(thread));
@ -88,15 +83,13 @@ HWTEST_F_L0(WeakRefGenGCTest, ArrayNonMovable)
array->Set(thread, 1, value);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(value, array->Get(1));
vm->CollectGarbage(TriggerGCType::SEMI_GC);
vm->CollectGarbage(TriggerGCType::OLD_GC);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(JSTaggedValue::Undefined(), array->Get(1));
#endif
}
HWTEST_F_L0(WeakRefGenGCTest, ArrayUndefined)
HWTEST_F_L0(WeakRefOldGCTest, ArrayUndefined)
{
#if !defined(NDEBUG)
EcmaVM *ecmaVM = thread->GetEcmaVM();
JSHandle<TaggedArray> array = ecmaVM->GetFactory()->NewTaggedArray(2);
EXPECT_TRUE(*array != nullptr);
@ -109,15 +102,13 @@ HWTEST_F_L0(WeakRefGenGCTest, ArrayUndefined)
array->Set(thread, 1, value);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(value, array->Get(1));
ecmaVM->CollectGarbage(TriggerGCType::SEMI_GC);
ecmaVM->CollectGarbage(TriggerGCType::OLD_GC);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(JSTaggedValue::Undefined(), array->Get(1));
#endif
}
HWTEST_F_L0(WeakRefGenGCTest, ArrayKeep)
HWTEST_F_L0(WeakRefOldGCTest, ArrayKeep)
{
#if !defined(NDEBUG)
EcmaVM *ecmaVM = thread->GetEcmaVM();
JSHandle<TaggedArray> array = ecmaVM->GetFactory()->NewTaggedArray(2);
EXPECT_TRUE(*array != nullptr);
@ -130,41 +121,36 @@ HWTEST_F_L0(WeakRefGenGCTest, ArrayKeep)
array->Set(thread, 1, value);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(value, array->Get(1));
ecmaVM->CollectGarbage(TriggerGCType::SEMI_GC);
ecmaVM->CollectGarbage(TriggerGCType::OLD_GC);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(true, array->Get(1).IsWeak());
value = newObj2.GetTaggedValue();
value.CreateWeakRef();
EXPECT_EQ(value, array->Get(1));
#endif
}
HWTEST_F_L0(WeakRefGenGCTest, DynObjectUndefined)
HWTEST_F_L0(WeakRefOldGCTest, DynObjectUndefined)
{
#if !defined(NDEBUG)
JSHandle<JSObject> newObj1(thread, JSObjectTestCreate(thread));
JSTaggedValue array(ArrayTestCreate(thread));
array.CreateWeakRef();
newObj1->SetElements(thread, array);
EXPECT_EQ(newObj1->GetElements(), array);
thread->GetEcmaVM()->CollectGarbage(TriggerGCType::SEMI_GC);
thread->GetEcmaVM()->CollectGarbage(TriggerGCType::OLD_GC);
EXPECT_EQ(newObj1->GetElements(), JSTaggedValue::Undefined());
#endif
}
HWTEST_F_L0(WeakRefGenGCTest, DynObjectKeep)
HWTEST_F_L0(WeakRefOldGCTest, DynObjectKeep)
{
#if !defined(NDEBUG)
JSHandle<JSObject> newObj1(thread, JSObjectTestCreate(thread));
JSHandle<TaggedArray> array(thread, ArrayTestCreate(thread));
JSTaggedValue value = array.GetTaggedValue();
value.CreateWeakRef();
newObj1->SetElements(thread, value);
EXPECT_EQ(newObj1->GetElements(), value);
thread->GetEcmaVM()->CollectGarbage(TriggerGCType::SEMI_GC);
thread->GetEcmaVM()->CollectGarbage(TriggerGCType::OLD_GC);
value = array.GetTaggedValue();
value.CreateWeakRef();
EXPECT_EQ(newObj1->GetElements(), value);
#endif
}
} // namespace panda::test

View File

@ -23,7 +23,7 @@
using namespace panda::ecmascript;
namespace panda::test {
class WeakRefStwGCTest : public testing::Test {
class WeakRefSemiGCTest : public testing::Test {
public:
static void SetUpTestCase()
{
@ -50,7 +50,6 @@ public:
JSThread *thread {nullptr};
};
#if !defined(NDEBUG)
static JSObject *JSObjectTestCreate(JSThread *thread)
{
[[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
@ -61,9 +60,7 @@ static JSObject *JSObjectTestCreate(JSThread *thread)
ecmaVM->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(jsFunc), jsFunc);
return *newObj;
}
#endif
#if !defined(NDEBUG)
static TaggedArray *ArrayTestCreate(JSThread *thread)
{
[[maybe_unused]] ecmascript::EcmaHandleScope scope(thread);
@ -71,11 +68,9 @@ static TaggedArray *ArrayTestCreate(JSThread *thread)
JSHandle<TaggedArray> array = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(2);
return *array;
}
#endif
HWTEST_F_L0(WeakRefStwGCTest, ArrayUndefined)
HWTEST_F_L0(WeakRefSemiGCTest, ArrayUndefined)
{
#if !defined(NDEBUG)
EcmaVM *ecmaVM = thread->GetEcmaVM();
JSHandle<TaggedArray> array = ecmaVM->GetFactory()->NewTaggedArray(2);
EXPECT_TRUE(*array != nullptr);
@ -91,12 +86,10 @@ HWTEST_F_L0(WeakRefStwGCTest, ArrayUndefined)
ecmaVM->CollectGarbage(TriggerGCType::SEMI_GC);
EXPECT_EQ(newObj1.GetTaggedValue(), array->Get(0));
EXPECT_EQ(JSTaggedValue::Undefined(), array->Get(1));
#endif
}
HWTEST_F_L0(WeakRefStwGCTest, ArrayKeep)
HWTEST_F_L0(WeakRefSemiGCTest, ArrayKeep)
{
#if !defined(NDEBUG)
EcmaVM *ecmaVM = thread->GetEcmaVM();
JSHandle<TaggedArray> array = ecmaVM->GetFactory()->NewTaggedArray(2);
EXPECT_TRUE(*array != nullptr);
@ -115,12 +108,10 @@ HWTEST_F_L0(WeakRefStwGCTest, ArrayKeep)
value = newObj2.GetTaggedValue();
value.CreateWeakRef();
EXPECT_EQ(value, array->Get(1));
#endif
}
HWTEST_F_L0(WeakRefStwGCTest, DynObjectUndefined)
HWTEST_F_L0(WeakRefSemiGCTest, DynObjectUndefined)
{
#if !defined(NDEBUG)
JSHandle<JSObject> newObj1(thread, JSObjectTestCreate(thread));
JSTaggedValue array(ArrayTestCreate(thread));
array.CreateWeakRef();
@ -128,12 +119,10 @@ HWTEST_F_L0(WeakRefStwGCTest, DynObjectUndefined)
EXPECT_EQ(newObj1->GetElements(), array);
thread->GetEcmaVM()->CollectGarbage(TriggerGCType::SEMI_GC);
EXPECT_EQ(newObj1->GetElements(), JSTaggedValue::Undefined());
#endif
}
HWTEST_F_L0(WeakRefStwGCTest, DynObjectKeep)
HWTEST_F_L0(WeakRefSemiGCTest, DynObjectKeep)
{
#if !defined(NDEBUG)
JSHandle<JSObject> newObj1(thread, JSObjectTestCreate(thread));
JSHandle<TaggedArray> array(thread, ArrayTestCreate(thread));
JSTaggedValue value = array.GetTaggedValue();
@ -144,6 +133,5 @@ HWTEST_F_L0(WeakRefStwGCTest, DynObjectKeep)
value = array.GetTaggedValue();
value.CreateWeakRef();
EXPECT_EQ(newObj1->GetElements(), value);
#endif
}
} // namespace panda::test
} // namespace panda::test

View File

@ -96,17 +96,19 @@ public:
int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
return HashTableT::Get(index);
}
inline void SetAttributes(const JSThread *thread, int entry, JSTaggedValue metaData)
{
int index = GetEntryIndex(entry) + ENTRY_DETAILS_INDEX;
HashTableT::Set(thread, index, metaData);
}
inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, const JSTaggedValue &value,
inline void SetEntry(const JSThread *thread, int entry, const JSTaggedValue &key, JSTaggedValue &value,
const JSTaggedValue &metaData)
{
SetKey(thread, entry, key);
SetValue(thread, entry, value);
JSTaggedValue weakValue = JSTaggedValue(value.CreateAndGetWeakRef());
SetValue(thread, entry, weakValue);
SetAttributes(thread, entry, metaData);
}
@ -135,4 +137,4 @@ public:
DECL_DUMP()
};
} // namespace panda::ecmascript
#endif
#endif

View File

@ -35,4 +35,7 @@ group("ark_js_moduletest") {
"throwdyn:throwdynAction",
"yieldstar:yieldstarAction",
]
if (!is_debug) {
deps += [ "weaktransitions:weaktransitionsAction" ]
}
}

View File

@ -0,0 +1,19 @@
# Copyright (c) 2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//ark/js_runtime/test/test_helper.gni")
host_moduletest_action("weaktransitions") {
deps = []
is_set_maxNonmovableSpaceCapacity = true
}

View File

@ -0,0 +1,14 @@
# Copyright (c) 2022 Huawei Device Co., Ltd.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
success

View File

@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var count = 0;
function addProperty(obj, index) {
let key = count.toString() + "-" +index.toString() + "key";
let val = {value: index.toString() + "value"};
Object.defineProperty(obj, key, val);
}
for (let idx = 0; idx < 1000; ++idx) {
let o = {a:1};
for (let i = 0; i < 1000; ++i) {
addProperty(o, i);
}
count++;
}
print("success");

View File

@ -30,6 +30,7 @@ def parse_args():
"""parse arguments."""
parser = argparse.ArgumentParser()
parser.add_argument('--script-file', help='execute script file')
parser.add_argument('--script-options', help='execute script options')
parser.add_argument('--script-args', help='args of script')
parser.add_argument('--expect-output', help='expect output')
parser.add_argument('--expect-file', help='expect file')
@ -42,6 +43,8 @@ def judge_output(args):
"""run testcase and judge is success or not."""
start_time = time.time()
cmd = input_args.script_file
if input_args.script_options:
cmd += input_args.script_options
if input_args.script_args:
cmd += " " + input_args.script_args
subp = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,

View File

@ -119,9 +119,17 @@ template("host_moduletest_action") {
script = "//ark/js_runtime/test/run_ark_executable.py"
js_vm_options = " "
if (defined(invoker.is_set_maxNonmovableSpaceCapacity) &&
invoker.is_set_maxNonmovableSpaceCapacity) {
js_vm_options += "--maxNonmovableSpaceCapacity=524288" # 0.5M
}
args = [
"--script-file",
rebase_path(_root_out_dir_) + "/ark/ark_js_runtime/ark_js_vm",
"--script-options",
js_vm_options,
"--script-args",
_test_abc_paths_,
"--expect-file",