[js weak refs] Migrate the WeakRef parts into the new API
New API is here: https://github.com/tc39/proposal-weakrefs/issues/55 The WeakCell parts stay in the old API, resulting in temporary code duplication in some parts. Those parts will go away once the WeakCell-related parts are migrated to the new API (but the spec needs some work first). BUG=v8:8179 Change-Id: I81ca824a14d830e3c5fa515d5ad7e5f78c10e19d Reviewed-on: https://chromium-review.googlesource.com/c/1378171 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org> Cr-Commit-Position: refs/heads/master@{#58264}
This commit is contained in:
parent
9b42c4c132
commit
fef6f8eddc
@ -4549,9 +4549,6 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
SimpleInstallFunction(isolate(), weak_factory_prototype, "makeCell",
|
||||
Builtins::kWeakFactoryMakeCell, 2, false);
|
||||
|
||||
SimpleInstallFunction(isolate(), weak_factory_prototype, "makeRef",
|
||||
Builtins::kWeakFactoryMakeRef, 2, false);
|
||||
|
||||
SimpleInstallFunction(isolate(), weak_factory_prototype, "cleanupSome",
|
||||
Builtins::kWeakFactoryCleanupSome, 0, false);
|
||||
}
|
||||
@ -4579,6 +4576,7 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
// Create %WeakRefPrototype%
|
||||
Handle<Map> weak_ref_map =
|
||||
factory->NewMap(JS_WEAK_REF_TYPE, JSWeakRef::kSize);
|
||||
DCHECK(weak_ref_map->IsJSObjectMap());
|
||||
native_context()->set_js_weak_ref_map(*weak_ref_map);
|
||||
|
||||
Handle<JSObject> weak_ref_prototype =
|
||||
@ -4593,6 +4591,23 @@ void Genesis::InitializeGlobal_harmony_weak_refs() {
|
||||
|
||||
SimpleInstallFunction(isolate(), weak_ref_prototype, "deref",
|
||||
Builtins::kWeakRefDeref, 0, false);
|
||||
|
||||
// Create %WeakRef%
|
||||
Handle<String> weak_ref_name = factory->InternalizeUtf8String("WeakRef");
|
||||
Handle<JSFunction> weak_ref_fun = CreateFunction(
|
||||
isolate(), weak_ref_name, JS_WEAK_REF_TYPE, JSWeakRef::kSize, 0,
|
||||
weak_ref_prototype, Builtins::kWeakRefConstructor);
|
||||
|
||||
weak_ref_fun->shared()->DontAdaptArguments();
|
||||
weak_ref_fun->shared()->set_length(1);
|
||||
|
||||
// Install the "constructor" property on the prototype.
|
||||
JSObject::AddProperty(isolate(), weak_ref_prototype,
|
||||
factory->constructor_string(), weak_ref_fun,
|
||||
DONT_ENUM);
|
||||
|
||||
JSObject::AddProperty(isolate(), global, weak_ref_name, weak_ref_fun,
|
||||
DONT_ENUM);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1368,7 +1368,7 @@ namespace internal {
|
||||
CPP(WeakFactoryCleanupSome) \
|
||||
CPP(WeakFactoryConstructor) \
|
||||
CPP(WeakFactoryMakeCell) \
|
||||
CPP(WeakFactoryMakeRef) \
|
||||
CPP(WeakRefConstructor) \
|
||||
CPP(WeakRefDeref)
|
||||
|
||||
#ifdef V8_INTL_SUPPORT
|
||||
|
@ -77,44 +77,6 @@ BUILTIN(WeakFactoryMakeCell) {
|
||||
return *weak_cell;
|
||||
}
|
||||
|
||||
BUILTIN(WeakFactoryMakeRef) {
|
||||
HandleScope scope(isolate);
|
||||
const char* method_name = "WeakFactory.prototype.makeRef";
|
||||
|
||||
CHECK_RECEIVER(JSWeakFactory, weak_factory, method_name);
|
||||
|
||||
Handle<Object> target = args.atOrUndefined(isolate, 1);
|
||||
if (!target->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError(MessageTemplate::kWeakRefsMakeRefTargetMustBeObject));
|
||||
}
|
||||
Handle<JSReceiver> target_receiver = Handle<JSReceiver>::cast(target);
|
||||
Handle<Object> holdings = args.atOrUndefined(isolate, 2);
|
||||
if (target->SameValue(*holdings)) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError(
|
||||
MessageTemplate::kWeakRefsMakeRefTargetAndHoldingsMustNotBeSame));
|
||||
}
|
||||
|
||||
// TODO(marja): Realms.
|
||||
|
||||
Handle<Map> weak_ref_map(isolate->native_context()->js_weak_ref_map(),
|
||||
isolate);
|
||||
|
||||
Handle<JSWeakRef> weak_ref =
|
||||
Handle<JSWeakRef>::cast(isolate->factory()->NewJSObjectFromMap(
|
||||
weak_ref_map, TENURED, Handle<AllocationSite>::null()));
|
||||
weak_ref->set_target(*target_receiver);
|
||||
weak_ref->set_holdings(*holdings);
|
||||
weak_factory->AddWeakCell(*weak_ref);
|
||||
|
||||
isolate->heap()->AddKeepDuringJobTarget(target_receiver);
|
||||
|
||||
return *weak_ref;
|
||||
}
|
||||
|
||||
BUILTIN(WeakFactoryCleanupSome) {
|
||||
HandleScope scope(isolate);
|
||||
const char* method_name = "WeakFactory.prototype.cleanupSome";
|
||||
@ -156,6 +118,38 @@ BUILTIN(WeakCellClear) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
BUILTIN(WeakRefConstructor) {
|
||||
HandleScope scope(isolate);
|
||||
Handle<JSFunction> target = args.target();
|
||||
if (args.new_target()->IsUndefined(isolate)) { // [[Call]]
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kConstructorNotFunction,
|
||||
handle(target->shared()->Name(), isolate)));
|
||||
}
|
||||
// [[Construct]]
|
||||
Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
|
||||
Handle<Object> target_object = args.atOrUndefined(isolate, 1);
|
||||
if (!target_object->IsJSReceiver()) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate,
|
||||
NewTypeError(
|
||||
MessageTemplate::kWeakRefsWeakRefConstructorTargetMustBeObject));
|
||||
}
|
||||
isolate->heap()->AddKeepDuringJobTarget(
|
||||
Handle<JSReceiver>::cast(target_object));
|
||||
|
||||
// TODO(marja): Realms.
|
||||
|
||||
Handle<JSObject> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
JSObject::New(target, new_target, Handle<AllocationSite>::null()));
|
||||
|
||||
Handle<JSWeakRef> weak_ref = Handle<JSWeakRef>::cast(result);
|
||||
weak_ref->set_target(*target_object);
|
||||
return *weak_ref;
|
||||
}
|
||||
|
||||
BUILTIN(WeakRefDeref) {
|
||||
HandleScope scope(isolate);
|
||||
CHECK_RECEIVER(JSWeakRef, weak_ref, "WeakRef.prototype.deref");
|
||||
|
@ -221,6 +221,28 @@ class ConcurrentMarkingVisitor final
|
||||
return VisitJSObjectSubclass(map, object);
|
||||
}
|
||||
|
||||
int VisitJSWeakRef(Map map, JSWeakRef weak_ref) {
|
||||
int size = VisitJSObjectSubclass(map, weak_ref);
|
||||
if (size == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (weak_ref->target()->IsHeapObject()) {
|
||||
HeapObject* target = HeapObject::cast(weak_ref->target());
|
||||
if (marking_state_.IsBlackOrGrey(target)) {
|
||||
// Record the slot inside the JSWeakRef, since the
|
||||
// VisitJSObjectSubclass above didn't visit it.
|
||||
ObjectSlot slot =
|
||||
HeapObject::RawField(weak_ref, JSWeakRef::kTargetOffset);
|
||||
MarkCompactCollector::RecordSlot(weak_ref, slot, target);
|
||||
} else {
|
||||
// JSWeakRef points to a potentially dead object. We have to process
|
||||
// them when we know the liveness of the whole transitive closure.
|
||||
weak_objects_->js_weak_refs.Push(task_id_, weak_ref);
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int VisitJSWeakCell(Map map, JSWeakCell weak_cell) {
|
||||
int size = VisitJSObjectSubclass(map, weak_cell);
|
||||
if (size == 0) {
|
||||
@ -474,7 +496,7 @@ class ConcurrentMarkingVisitor final
|
||||
|
||||
void VisitCustomWeakPointers(HeapObject* host, ObjectSlot start,
|
||||
ObjectSlot end) override {
|
||||
DCHECK(host->IsJSWeakCell());
|
||||
DCHECK(host->IsJSWeakCell() || host->IsJSWeakRef());
|
||||
}
|
||||
|
||||
private:
|
||||
@ -729,6 +751,7 @@ void ConcurrentMarking::Run(int task_id, TaskState* task_state) {
|
||||
weak_objects_->next_ephemerons.FlushToGlobal(task_id);
|
||||
weak_objects_->discovered_ephemerons.FlushToGlobal(task_id);
|
||||
weak_objects_->weak_references.FlushToGlobal(task_id);
|
||||
weak_objects_->js_weak_refs.FlushToGlobal(task_id);
|
||||
weak_objects_->js_weak_cells.FlushToGlobal(task_id);
|
||||
weak_objects_->weak_objects_in_code.FlushToGlobal(task_id);
|
||||
weak_objects_->bytecode_flushing_candidates.FlushToGlobal(task_id);
|
||||
|
@ -195,6 +195,29 @@ int MarkingVisitor<fixed_array_mode, retaining_path_mode,
|
||||
return size;
|
||||
}
|
||||
|
||||
template <FixedArrayVisitationMode fixed_array_mode,
|
||||
TraceRetainingPathMode retaining_path_mode, typename MarkingState>
|
||||
int MarkingVisitor<fixed_array_mode, retaining_path_mode,
|
||||
MarkingState>::VisitJSWeakRef(Map map, JSWeakRef weak_ref) {
|
||||
if (weak_ref->target()->IsHeapObject()) {
|
||||
HeapObject* target = HeapObject::cast(weak_ref->target());
|
||||
if (marking_state()->IsBlackOrGrey(target)) {
|
||||
// Record the slot inside the JSWeakRef, since the IterateBody below
|
||||
// won't visit it.
|
||||
ObjectSlot slot =
|
||||
HeapObject::RawField(weak_ref, JSWeakCell::kTargetOffset);
|
||||
collector_->RecordSlot(weak_ref, slot, target);
|
||||
} else {
|
||||
// JSWeakRef points to a potentially dead object. We have to process
|
||||
// them when we know the liveness of the whole transitive closure.
|
||||
collector_->AddWeakRef(weak_ref);
|
||||
}
|
||||
}
|
||||
int size = JSWeakRef::BodyDescriptor::SizeOf(map, weak_ref);
|
||||
JSWeakRef::BodyDescriptor::IterateBody(map, weak_ref, size, this);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <FixedArrayVisitationMode fixed_array_mode,
|
||||
TraceRetainingPathMode retaining_path_mode, typename MarkingState>
|
||||
int MarkingVisitor<fixed_array_mode, retaining_path_mode,
|
||||
|
@ -1931,6 +1931,7 @@ void MarkCompactCollector::ClearNonLiveReferences() {
|
||||
DCHECK(weak_objects_.transition_arrays.IsEmpty());
|
||||
DCHECK(weak_objects_.weak_references.IsEmpty());
|
||||
DCHECK(weak_objects_.weak_objects_in_code.IsEmpty());
|
||||
DCHECK(weak_objects_.js_weak_refs.IsEmpty());
|
||||
DCHECK(weak_objects_.js_weak_cells.IsEmpty());
|
||||
DCHECK(weak_objects_.bytecode_flushing_candidates.IsEmpty());
|
||||
}
|
||||
@ -2267,6 +2268,20 @@ void MarkCompactCollector::ClearJSWeakCells() {
|
||||
if (!FLAG_harmony_weak_refs) {
|
||||
return;
|
||||
}
|
||||
JSWeakRef weak_ref;
|
||||
while (weak_objects_.js_weak_refs.Pop(kMainThread, &weak_ref)) {
|
||||
// We do not insert cleared weak cells into the list, so the value
|
||||
// cannot be undefined here.
|
||||
JSReceiver target = JSReceiver::cast(weak_ref->target());
|
||||
if (!non_atomic_marking_state()->IsBlackOrGrey(target)) {
|
||||
weak_ref->set_target(ReadOnlyRoots(isolate()).undefined_value());
|
||||
} else {
|
||||
// The value of the JSWeakRef is alive.
|
||||
ObjectSlot slot =
|
||||
HeapObject::RawField(weak_ref, JSWeakRef::kTargetOffset);
|
||||
RecordSlot(weak_ref, slot, target);
|
||||
}
|
||||
}
|
||||
JSWeakCell weak_cell;
|
||||
while (weak_objects_.js_weak_cells.Pop(kMainThread, &weak_cell)) {
|
||||
// We do not insert cleared weak cells into the list, so the value
|
||||
@ -2312,6 +2327,7 @@ void MarkCompactCollector::AbortWeakObjects() {
|
||||
weak_objects_.discovered_ephemerons.Clear();
|
||||
weak_objects_.weak_references.Clear();
|
||||
weak_objects_.weak_objects_in_code.Clear();
|
||||
weak_objects_.js_weak_refs.Clear();
|
||||
weak_objects_.js_weak_cells.Clear();
|
||||
weak_objects_.bytecode_flushing_candidates.Clear();
|
||||
}
|
||||
|
@ -444,6 +444,7 @@ struct WeakObjects {
|
||||
Worklist<std::pair<HeapObject*, HeapObjectSlot>, 64> weak_references;
|
||||
Worklist<std::pair<HeapObject*, Code>, 64> weak_objects_in_code;
|
||||
|
||||
Worklist<JSWeakRef, 64> js_weak_refs;
|
||||
Worklist<JSWeakCell, 64> js_weak_cells;
|
||||
|
||||
Worklist<SharedFunctionInfo, 64> bytecode_flushing_candidates;
|
||||
@ -683,6 +684,10 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
|
||||
std::make_pair(object, code));
|
||||
}
|
||||
|
||||
void AddWeakRef(JSWeakRef weak_ref) {
|
||||
weak_objects_.js_weak_refs.Push(kMainThread, weak_ref);
|
||||
}
|
||||
|
||||
void AddWeakCell(JSWeakCell weak_cell) {
|
||||
weak_objects_.js_weak_cells.Push(kMainThread, weak_cell);
|
||||
}
|
||||
@ -951,6 +956,7 @@ class MarkingVisitor final
|
||||
V8_INLINE int VisitSharedFunctionInfo(Map map, SharedFunctionInfo object);
|
||||
V8_INLINE int VisitTransitionArray(Map map, TransitionArray object);
|
||||
V8_INLINE int VisitJSWeakCell(Map map, JSWeakCell object);
|
||||
V8_INLINE int VisitJSWeakRef(Map map, JSWeakRef object);
|
||||
|
||||
// ObjectVisitor implementation.
|
||||
V8_INLINE void VisitPointer(HeapObject* host, ObjectSlot p) final {
|
||||
|
@ -64,8 +64,6 @@ ResultType HeapVisitor<ResultType, ConcreteVisitor>::Visit(Map map,
|
||||
return visitor->VisitFreeSpace(map, FreeSpace::cast(object));
|
||||
case kVisitWeakArray:
|
||||
return visitor->VisitWeakArray(map, object);
|
||||
case kVisitJSWeakCell:
|
||||
return visitor->VisitJSWeakCell(map, JSWeakCell::cast(object));
|
||||
case kVisitorIdCount:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ class JSDataView;
|
||||
class JSRegExp;
|
||||
class JSTypedArray;
|
||||
class JSWeakCell;
|
||||
class JSWeakRef;
|
||||
class JSWeakCollection;
|
||||
class NativeContext;
|
||||
class UncompiledDataWithoutPreParsedScope;
|
||||
@ -56,7 +57,9 @@ class WasmInstanceObject;
|
||||
V(JSDataView, JSDataView) \
|
||||
V(JSObject, JSObject) \
|
||||
V(JSTypedArray, JSTypedArray) \
|
||||
V(JSWeakCell, JSWeakCell) \
|
||||
V(JSWeakCollection, JSWeakCollection) \
|
||||
V(JSWeakRef, JSWeakRef) \
|
||||
V(Map, Map) \
|
||||
V(NativeContext, NativeContext) \
|
||||
V(Oddball, Oddball*) \
|
||||
|
@ -542,8 +542,8 @@ namespace internal {
|
||||
"WeakFactory.prototype.makeCell: target must be an object") \
|
||||
T(WeakRefsMakeCellTargetAndHoldingsMustNotBeSame, \
|
||||
"WeakFactory.prototype.makeCell: target and holdings must not be same") \
|
||||
T(WeakRefsMakeRefTargetMustBeObject, \
|
||||
"WeakFactory.prototype.makeRef: target must be an object") \
|
||||
T(WeakRefsWeakRefConstructorTargetMustBeObject, \
|
||||
"WeakRef: target must be an object") \
|
||||
T(WeakRefsMakeRefTargetAndHoldingsMustNotBeSame, \
|
||||
"WeakFactory.prototype.makeRef: target and holdings must not be same")
|
||||
|
||||
|
@ -237,6 +237,25 @@ class JSWeakCell::BodyDescriptor final : public BodyDescriptorBase {
|
||||
}
|
||||
};
|
||||
|
||||
class JSWeakRef::BodyDescriptor final : public BodyDescriptorBase {
|
||||
public:
|
||||
static bool IsValidSlot(Map map, HeapObject* obj, int offset) {
|
||||
return JSObject::BodyDescriptor::IsValidSlot(map, obj, offset);
|
||||
}
|
||||
|
||||
template <typename ObjectVisitor>
|
||||
static inline void IterateBody(Map map, HeapObject* obj, int object_size,
|
||||
ObjectVisitor* v) {
|
||||
IteratePointers(obj, JSReceiver::kPropertiesOrHashOffset, kTargetOffset, v);
|
||||
IterateCustomWeakPointer(obj, kTargetOffset, v);
|
||||
IteratePointers(obj, kTargetOffset + kPointerSize, object_size, v);
|
||||
}
|
||||
|
||||
static inline int SizeOf(Map map, HeapObject* object) {
|
||||
return map->instance_size();
|
||||
}
|
||||
};
|
||||
|
||||
class SharedFunctionInfo::BodyDescriptor final : public BodyDescriptorBase {
|
||||
public:
|
||||
static bool IsValidSlot(Map map, HeapObject* obj, int offset) {
|
||||
@ -952,8 +971,9 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
|
||||
case JS_FUNCTION_TYPE:
|
||||
return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3, p4);
|
||||
case JS_WEAK_CELL_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
return Op::template apply<JSWeakCell::BodyDescriptor>(p1, p2, p3, p4);
|
||||
case JS_WEAK_REF_TYPE:
|
||||
return Op::template apply<JSWeakRef::BodyDescriptor>(p1, p2, p3, p4);
|
||||
case ODDBALL_TYPE:
|
||||
return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3, p4);
|
||||
case JS_PROXY_TYPE:
|
||||
|
@ -331,9 +331,11 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
|
||||
isolate);
|
||||
break;
|
||||
case JS_WEAK_CELL_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
JSWeakCell::cast(this)->JSWeakCellVerify(isolate);
|
||||
break;
|
||||
case JS_WEAK_REF_TYPE:
|
||||
JSWeakRef::cast(this)->JSWeakRefVerify(isolate);
|
||||
break;
|
||||
case JS_WEAK_FACTORY_TYPE:
|
||||
JSWeakFactory::cast(this)->JSWeakFactoryVerify(isolate);
|
||||
break;
|
||||
@ -1315,6 +1317,12 @@ void JSWeakCell::JSWeakCellVerify(Isolate* isolate) {
|
||||
CHECK(factory()->IsUndefined(isolate) || factory()->IsJSWeakFactory());
|
||||
}
|
||||
|
||||
void JSWeakRef::JSWeakRefVerify(Isolate* isolate) {
|
||||
CHECK(IsJSWeakRef());
|
||||
JSObjectVerify(isolate);
|
||||
CHECK(target()->IsUndefined(isolate) || target()->IsJSReceiver());
|
||||
}
|
||||
|
||||
void JSWeakFactory::JSWeakFactoryVerify(Isolate* isolate) {
|
||||
CHECK(IsJSWeakFactory());
|
||||
JSObjectVerify(isolate);
|
||||
|
@ -301,9 +301,11 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
|
||||
JSMapIterator::cast(this)->JSMapIteratorPrint(os);
|
||||
break;
|
||||
case JS_WEAK_CELL_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
JSWeakCell::cast(this)->JSWeakCellPrint(os);
|
||||
break;
|
||||
case JS_WEAK_REF_TYPE:
|
||||
JSWeakRef::cast(this)->JSWeakRefPrint(os);
|
||||
break;
|
||||
case JS_WEAK_FACTORY_TYPE:
|
||||
JSWeakFactory::cast(this)->JSWeakFactoryPrint(os);
|
||||
break;
|
||||
@ -1287,6 +1289,12 @@ void JSWeakCell::JSWeakCellPrint(std::ostream& os) {
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSWeakRef::JSWeakRefPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSWeakRef");
|
||||
os << "\n - target: " << Brief(target());
|
||||
JSObjectPrintBody(os, *this);
|
||||
}
|
||||
|
||||
void JSWeakFactory::JSWeakFactoryPrint(std::ostream& os) {
|
||||
JSObjectPrintHeader(os, *this, "JSWeakFactory");
|
||||
os << "\n - native_context: " << Brief(native_context());
|
||||
|
@ -3309,8 +3309,10 @@ VisitorId Map::GetVisitorId(Map map) {
|
||||
case JS_SPECIAL_API_OBJECT_TYPE:
|
||||
return kVisitJSApiObject;
|
||||
|
||||
case JS_WEAK_CELL_TYPE:
|
||||
case JS_WEAK_REF_TYPE:
|
||||
return kVisitJSWeakRef;
|
||||
|
||||
case JS_WEAK_CELL_TYPE:
|
||||
return kVisitJSWeakCell;
|
||||
|
||||
case FILLER_TYPE:
|
||||
|
@ -292,8 +292,8 @@ enum InstanceType : uint16_t {
|
||||
JS_SET_KEY_VALUE_ITERATOR_TYPE,
|
||||
JS_SET_VALUE_ITERATOR_TYPE,
|
||||
JS_STRING_ITERATOR_TYPE,
|
||||
JS_WEAK_CELL_TYPE, // FIRST_JS_WEAK_CELL_TYPE
|
||||
JS_WEAK_REF_TYPE, // LAST_JS_WEAK_CELL_TYPE
|
||||
JS_WEAK_CELL_TYPE,
|
||||
JS_WEAK_REF_TYPE,
|
||||
JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE,
|
||||
JS_WEAK_FACTORY_TYPE,
|
||||
JS_WEAK_MAP_TYPE,
|
||||
@ -382,9 +382,6 @@ enum InstanceType : uint16_t {
|
||||
|
||||
FIRST_MAP_ITERATOR_TYPE = JS_MAP_KEY_ITERATOR_TYPE,
|
||||
LAST_MAP_ITERATOR_TYPE = JS_MAP_VALUE_ITERATOR_TYPE,
|
||||
|
||||
FIRST_JS_WEAK_CELL_TYPE = JS_WEAK_CELL_TYPE,
|
||||
LAST_JS_WEAK_CELL_TYPE = JS_WEAK_REF_TYPE,
|
||||
};
|
||||
|
||||
// This constant is defined outside of the InstanceType enum because the
|
||||
@ -460,6 +457,7 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
|
||||
V(JSValue, JS_VALUE_TYPE) \
|
||||
V(JSWeakFactory, JS_WEAK_FACTORY_TYPE) \
|
||||
V(JSWeakFactoryCleanupIterator, JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE) \
|
||||
V(JSWeakCell, JS_WEAK_CELL_TYPE) \
|
||||
V(JSWeakMap, JS_WEAK_MAP_TYPE) \
|
||||
V(JSWeakRef, JS_WEAK_REF_TYPE) \
|
||||
V(JSWeakSet, JS_WEAK_SET_TYPE) \
|
||||
@ -531,7 +529,6 @@ V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
|
||||
V(HashTable, FIRST_HASH_TABLE_TYPE, LAST_HASH_TABLE_TYPE) \
|
||||
V(JSMapIterator, FIRST_MAP_ITERATOR_TYPE, LAST_MAP_ITERATOR_TYPE) \
|
||||
V(JSSetIterator, FIRST_SET_ITERATOR_TYPE, LAST_SET_ITERATOR_TYPE) \
|
||||
V(JSWeakCell, FIRST_JS_WEAK_CELL_TYPE, LAST_JS_WEAK_CELL_TYPE) \
|
||||
V(Microtask, FIRST_MICROTASK_TYPE, LAST_MICROTASK_TYPE) \
|
||||
V(Name, FIRST_NAME_TYPE, LAST_NAME_TYPE) \
|
||||
V(String, FIRST_STRING_TYPE, LAST_STRING_TYPE) \
|
||||
|
@ -18,7 +18,7 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSWeakCell, JSObject)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSWeakRef, JSWeakCell)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSWeakRef, JSObject)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSWeakFactory, JSObject)
|
||||
OBJECT_CONSTRUCTORS_IMPL(JSWeakFactoryCleanupIterator, JSObject)
|
||||
|
||||
@ -38,6 +38,7 @@ ACCESSORS(JSWeakCell, prev, Object, kPrevOffset)
|
||||
CAST_ACCESSOR2(JSWeakCell)
|
||||
|
||||
CAST_ACCESSOR2(JSWeakRef)
|
||||
ACCESSORS(JSWeakRef, target, Object, kTargetOffset)
|
||||
|
||||
ACCESSORS2(JSWeakFactoryCleanupIterator, factory, JSWeakFactory, kFactoryOffset)
|
||||
CAST_ACCESSOR2(JSWeakFactoryCleanupIterator)
|
||||
|
@ -115,10 +115,20 @@ class JSWeakCell : public JSObject {
|
||||
OBJECT_CONSTRUCTORS(JSWeakCell, JSObject);
|
||||
};
|
||||
|
||||
class JSWeakRef : public JSWeakCell {
|
||||
class JSWeakRef : public JSObject {
|
||||
public:
|
||||
DECL_PRINTER(JSWeakRef)
|
||||
DECL_VERIFIER(JSWeakRef)
|
||||
DECL_CAST2(JSWeakRef)
|
||||
OBJECT_CONSTRUCTORS(JSWeakRef, JSWeakCell);
|
||||
|
||||
DECL_ACCESSORS(target, Object)
|
||||
|
||||
static const int kTargetOffset = JSObject::kHeaderSize;
|
||||
static const int kSize = kTargetOffset + kPointerSize;
|
||||
|
||||
class BodyDescriptor;
|
||||
|
||||
OBJECT_CONSTRUCTORS(JSWeakRef, JSObject);
|
||||
};
|
||||
|
||||
class WeakFactoryCleanupJobTask : public Microtask {
|
||||
|
@ -47,6 +47,7 @@ enum InstanceType : uint16_t;
|
||||
V(JSObjectFast) \
|
||||
V(JSTypedArray) \
|
||||
V(JSWeakCell) \
|
||||
V(JSWeakRef) \
|
||||
V(JSWeakCollection) \
|
||||
V(Map) \
|
||||
V(NativeContext) \
|
||||
|
@ -151,14 +151,10 @@
|
||||
clear.call(wc);
|
||||
})();
|
||||
|
||||
(function TestMakeRef() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let wr = wf.makeRef({});
|
||||
let wc = wf.makeCell({});
|
||||
(function TestWeakRefConstructor() {
|
||||
let wr = new WeakRef({});
|
||||
assertEquals(wr.toString(), "[object WeakRef]");
|
||||
assertNotSame(wr.__proto__, Object.prototype);
|
||||
assertSame(wr.__proto__.__proto__, wc.__proto__);
|
||||
assertEquals(wr.holdings, undefined);
|
||||
|
||||
let deref_desc = Object.getOwnPropertyDescriptor(wr.__proto__, "deref");
|
||||
assertEquals(true, deref_desc.configurable);
|
||||
@ -166,70 +162,36 @@
|
||||
assertEquals("function", typeof deref_desc.value);
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithHoldings() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let obj = {a: 1};
|
||||
let holdings = {b: 2};
|
||||
let wr = wf.makeRef(obj, holdings);
|
||||
assertSame(wr.holdings, holdings);
|
||||
(function TestWeakRefConstructorWithNonObject() {
|
||||
let message = "WeakRef: target must be an object";
|
||||
assertThrows(() => new WeakRef(), TypeError, message);
|
||||
assertThrows(() => new WeakRef(1), TypeError, message);
|
||||
assertThrows(() => new WeakRef(false), TypeError, message);
|
||||
assertThrows(() => new WeakRef("foo"), TypeError, message);
|
||||
assertThrows(() => new WeakRef(Symbol()), TypeError, message);
|
||||
assertThrows(() => new WeakRef(null), TypeError, message);
|
||||
assertThrows(() => new WeakRef(undefined), TypeError, message);
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithHoldingsSetHoldings() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let obj = {a: 1};
|
||||
let holdings = {b: 2};
|
||||
let wr = wf.makeRef(obj, holdings);
|
||||
assertSame(wr.holdings, holdings);
|
||||
wr.holdings = 5;
|
||||
assertSame(wr.holdings, holdings);
|
||||
(function TestWeakRefConstructorCallAsFunction() {
|
||||
let caught = false;
|
||||
let message = "";
|
||||
try {
|
||||
let f = WeakRef({});
|
||||
} catch (e) {
|
||||
message = e.message;
|
||||
caught = true;
|
||||
} finally {
|
||||
assertTrue(caught);
|
||||
assertEquals(message, "Constructor WeakRef requires 'new'");
|
||||
}
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithHoldingsSetHoldingsStrict() {
|
||||
"use strict";
|
||||
let wf = new WeakFactory(() => {});
|
||||
let obj = {a: 1};
|
||||
let holdings = {b: 2};
|
||||
let wr = wf.makeRef(obj, holdings);
|
||||
assertSame(wr.holdings, holdings);
|
||||
assertThrows(() => { wr.holdings = 5; }, TypeError);
|
||||
assertSame(wr.holdings, holdings);
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithNonObject() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let message = "WeakFactory.prototype.makeRef: target must be an object";
|
||||
assertThrows(() => wf.makeRef(), TypeError, message);
|
||||
assertThrows(() => wf.makeRef(1), TypeError, message);
|
||||
assertThrows(() => wf.makeRef(false), TypeError, message);
|
||||
assertThrows(() => wf.makeRef("foo"), TypeError, message);
|
||||
assertThrows(() => wf.makeRef(Symbol()), TypeError, message);
|
||||
assertThrows(() => wf.makeRef(null), TypeError, message);
|
||||
assertThrows(() => wf.makeRef(undefined), TypeError, message);
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithProxy() {
|
||||
(function TestWeakRefWithProxy() {
|
||||
let handler = {};
|
||||
let obj = {};
|
||||
let proxy = new Proxy(obj, handler);
|
||||
let wf = new WeakFactory(() => {});
|
||||
let wr = wf.makeRef(proxy);
|
||||
})();
|
||||
|
||||
(function TestMakeRefTargetAndHoldingsSameValue() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let obj = {a: 1};
|
||||
// SameValue(target, holdings) not ok
|
||||
assertThrows(() => wf.makeRef(obj, obj), TypeError,
|
||||
"WeakFactory.prototype.makeRef: target and holdings must not be same");
|
||||
let holdings = {a: 1};
|
||||
let wr = wf.makeRef(obj, holdings);
|
||||
})();
|
||||
|
||||
(function TestMakeRefWithoutWeakFactory() {
|
||||
assertThrows(() => WeakFactory.prototype.makeRef.call({}, {}), TypeError);
|
||||
// Does not throw:
|
||||
let wf = new WeakFactory(() => {});
|
||||
WeakFactory.prototype.makeRef.call(wf, {});
|
||||
let wr = new WeakRef(proxy);
|
||||
})();
|
||||
|
||||
(function TestCleanupSomeWithoutWeakFactory() {
|
||||
@ -243,24 +205,10 @@
|
||||
(function TestDerefWithoutWeakRef() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let wc = wf.makeCell({});
|
||||
let wr = wf.makeRef({});
|
||||
let wr = new WeakRef({});
|
||||
let deref = Object.getOwnPropertyDescriptor(wr.__proto__, "deref").value;
|
||||
assertThrows(() => deref.call({}), TypeError);
|
||||
assertThrows(() => deref.call(wc), TypeError);
|
||||
// Does not throw:
|
||||
deref.call(wr);
|
||||
})();
|
||||
|
||||
(function TestWeakRefClearAfterProtoChange() {
|
||||
let wf = new WeakFactory(() => {});
|
||||
let wc = wf.makeCell({});
|
||||
let wr = wf.makeRef({});
|
||||
// Does not throw:
|
||||
wr.clear();
|
||||
wr.__proto__ = {};
|
||||
assertThrows(() => wr.clear(), TypeError);
|
||||
|
||||
let clear = Object.getOwnPropertyDescriptor(wc.__proto__, "clear").value;
|
||||
// Does not throw:
|
||||
clear.call(wr);
|
||||
})();
|
||||
|
@ -1,51 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_count = 0;
|
||||
let cleanup_cells = [];
|
||||
let cleanup = function(iter) {
|
||||
for (wc of iter) {
|
||||
cleanup_cells.push(wc);
|
||||
}
|
||||
++cleanup_count;
|
||||
}
|
||||
|
||||
let o = {};
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let weak_ref;
|
||||
(function() {
|
||||
weak_ref = wf.makeRef(o);
|
||||
|
||||
// cleanupSome won't do anything since there are no dirty WeakCells.
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
})();
|
||||
|
||||
// Clear the KeepDuringJob set.
|
||||
%PerformMicrotaskCheckpoint();
|
||||
|
||||
weak_ref.deref();
|
||||
o = null;
|
||||
|
||||
// The WeakRef is not detected as dirty, since the KeepDuringJob set keeps the
|
||||
// target object alive.
|
||||
gc();
|
||||
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
// This GC detects the WeakRef as dirty.
|
||||
gc();
|
||||
|
||||
// Clear the WeakRef just before we would've called cleanupSome.
|
||||
weak_ref.clear();
|
||||
|
||||
wf.cleanupSome();
|
||||
|
||||
assertEquals(0, cleanup_count);
|
@ -1,57 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_count = 0;
|
||||
let cleanup_cells = [];
|
||||
let cleanup = function(iter) {
|
||||
for (wc of iter) {
|
||||
cleanup_cells.push(wc);
|
||||
}
|
||||
++cleanup_count;
|
||||
}
|
||||
|
||||
let o = {};
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let weak_ref;
|
||||
(function() {
|
||||
weak_ref = wf.makeRef(o);
|
||||
|
||||
// cleanupSome won't do anything since there are no dirty WeakCells.
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
})();
|
||||
|
||||
// Clear the KeepDuringJob set.
|
||||
%PerformMicrotaskCheckpoint();
|
||||
|
||||
weak_ref.deref();
|
||||
o = null;
|
||||
|
||||
// The WeakRef is not detected as dirty, since the KeepDuringJob set keeps the
|
||||
// target object alive.
|
||||
gc();
|
||||
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
// Now the WeakRef can be cleared.
|
||||
gc();
|
||||
wf.cleanupSome();
|
||||
|
||||
assertEquals(1, cleanup_count);
|
||||
assertEquals(1, cleanup_cells.length);
|
||||
assertEquals(weak_ref, cleanup_cells[0]);
|
||||
|
||||
// The cleanup task is not executed again since all WeakCells have been
|
||||
// processed.
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
assertEquals(1, cleanup_count);
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_count = 0;
|
||||
let cleanup_cells = [];
|
||||
let cleanup = function(iter) {
|
||||
for (wc of iter) {
|
||||
cleanup_cells.push(wc);
|
||||
}
|
||||
++cleanup_count;
|
||||
}
|
||||
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let weak_ref;
|
||||
(function() {
|
||||
let o = {};
|
||||
weak_ref = wf.makeRef(o);
|
||||
|
||||
// cleanupSome won't do anything since there are no dirty WeakCells.
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
})();
|
||||
|
||||
// The WeakRef is not detected as dirty, since the KeepDuringJob set keeps the
|
||||
// target object alive.
|
||||
gc();
|
||||
|
||||
wf.cleanupSome();
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
// Now the WeakRef can be cleared.
|
||||
gc();
|
||||
wf.cleanupSome();
|
||||
|
||||
assertEquals(1, cleanup_count);
|
||||
assertEquals(1, cleanup_cells.length);
|
||||
assertEquals(weak_ref, cleanup_cells[0]);
|
@ -1,46 +0,0 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_started = false;
|
||||
let cleanup_succeeded = false;
|
||||
let cleanup = function(iter) {
|
||||
cleanup_start = true;
|
||||
let cells = [];
|
||||
for (wc of iter) {
|
||||
cells.push(wc);
|
||||
}
|
||||
assertEquals(1, cells.length);
|
||||
assertEquals(w1, cells[0]);
|
||||
cleanup_succeeded = true;
|
||||
}
|
||||
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let wr;
|
||||
(function() {
|
||||
let o = { foo: "bar" };
|
||||
wr = wf.makeRef(o);
|
||||
})();
|
||||
|
||||
// Since the WeakRef was created during this turn, they're not cleared by GC.
|
||||
gc();
|
||||
assertNotEquals(undefined, wr.deref());
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// New turn.
|
||||
|
||||
let o = wr.deref();
|
||||
assertEquals("bar", o.foo);
|
||||
|
||||
wr.clear();
|
||||
assertEquals(undefined, wr.deref());
|
||||
|
||||
let timeout_func1 = function() {
|
||||
assertFalse(cleanup_started);
|
||||
assertFalse(cleanup_succeeded);
|
||||
}
|
||||
|
||||
// Assert that the cleanup function won't be called.
|
||||
setTimeout(timeout_func1, 0);
|
@ -4,35 +4,18 @@
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_count = 0;
|
||||
let cleared_cells1 = [];
|
||||
let cleared_cells2 = [];
|
||||
let cleanup = function(iter) {
|
||||
if (cleanup_count == 0) {
|
||||
for (wc of iter) {
|
||||
cleared_cells1.push(wc);
|
||||
}
|
||||
} else {
|
||||
assertEquals(1, cleanup_count);
|
||||
for (wc of iter) {
|
||||
cleared_cells2.push(wc);
|
||||
}
|
||||
}
|
||||
++cleanup_count;
|
||||
}
|
||||
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let o1 = {};
|
||||
let o2 = {};
|
||||
let wr1;
|
||||
let wr2;
|
||||
(function() {
|
||||
wr1 = wf.makeRef(o1);
|
||||
wr2 = wf.makeRef(o2);
|
||||
wr1 = new WeakRef(o1);
|
||||
wr2 = new WeakRef(o2);
|
||||
})();
|
||||
|
||||
// Since the WeakRefs were created during this turn, they're not cleared by GC.
|
||||
gc();
|
||||
|
||||
(function() {
|
||||
assertNotEquals(undefined, wr1.deref());
|
||||
assertNotEquals(undefined, wr2.deref());
|
||||
@ -41,8 +24,6 @@ gc();
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// New turn.
|
||||
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
wr1.deref();
|
||||
o1 = null;
|
||||
gc(); // deref makes sure we don't clean up wr1
|
||||
@ -50,8 +31,6 @@ gc(); // deref makes sure we don't clean up wr1
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// New turn.
|
||||
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
wr2.deref();
|
||||
o2 = null;
|
||||
gc(); // deref makes sure we don't clean up wr2
|
||||
@ -59,13 +38,11 @@ gc(); // deref makes sure we don't clean up wr2
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// New turn.
|
||||
|
||||
assertEquals(1, cleanup_count);
|
||||
assertEquals(wr1, cleared_cells1[0]);
|
||||
assertEquals(undefined, wr1.deref());
|
||||
|
||||
gc();
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// New turn.
|
||||
|
||||
assertEquals(2, cleanup_count);
|
||||
assertEquals(wr2, cleared_cells2[0]);
|
||||
assertEquals(undefined, wr2.deref());
|
||||
|
@ -11,9 +11,8 @@ let cleanup = function(iter) {
|
||||
for (wc of iter) {
|
||||
cells.push(wc);
|
||||
}
|
||||
assertEquals(2, cells.length);
|
||||
assertTrue(cells.includes(weak_ref));
|
||||
assertTrue(cells.includes(weak_cell));
|
||||
assertEquals(1, cells.length);
|
||||
assertEquals(weak_cell, cells[0]);
|
||||
cleanup_called = true;
|
||||
}
|
||||
|
||||
@ -22,8 +21,8 @@ let weak_ref;
|
||||
let weak_cell;
|
||||
(function() {
|
||||
let o = {};
|
||||
weak_ref = wf.makeRef(o);
|
||||
weak_cell = wf.makeRef(o);
|
||||
weak_ref = new WeakRef(o);
|
||||
weak_cell = wf.makeCell(o);
|
||||
})();
|
||||
|
||||
// Since the WeakRef was created during this turn, it is not cleared by GC. The
|
||||
@ -43,3 +42,4 @@ gc();
|
||||
// Next turn.
|
||||
|
||||
assertTrue(cleanup_called);
|
||||
assertEquals(undefined, weak_ref.deref());
|
||||
|
@ -4,24 +4,10 @@
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_called = false;
|
||||
let cleanup = function(iter) {
|
||||
assertFalse(cleanup_called);
|
||||
let count = 0;
|
||||
for (wc of iter) {
|
||||
++count;
|
||||
assertEquals(wr, wc);
|
||||
assertEquals(undefined, wc.deref());
|
||||
}
|
||||
assertEquals(1, count);
|
||||
cleanup_called = true;
|
||||
}
|
||||
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let wr;
|
||||
(function() {
|
||||
let o = {};
|
||||
wr = wf.makeRef(o);
|
||||
wr = new WeakRef(o);
|
||||
// Don't deref here, we want to test that the creation is enough to keep the
|
||||
// WeakRef alive until the end of the turn.
|
||||
})();
|
||||
@ -36,11 +22,6 @@ gc();
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
assertFalse(cleanup_called);
|
||||
|
||||
gc();
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
assertTrue(cleanup_called);
|
||||
assertEquals(undefined, wr.deref());
|
||||
|
@ -4,25 +4,13 @@
|
||||
|
||||
// Flags: --harmony-weak-refs --expose-gc --noincremental-marking --allow-natives-syntax
|
||||
|
||||
let cleanup_count = 0;
|
||||
let cleanup_cells = [];
|
||||
let cleanup = function(iter) {
|
||||
for (wc of iter) {
|
||||
assertEquals(undefined, wc.deref());
|
||||
cleanup_cells.push(wc);
|
||||
}
|
||||
++cleanup_count;
|
||||
}
|
||||
|
||||
let wf = new WeakFactory(cleanup);
|
||||
let wf_control = new WeakFactory(cleanup);
|
||||
let wr;
|
||||
let wr_control; // control WeakRef for testing what happens without deref
|
||||
(function() {
|
||||
let o1 = {};
|
||||
wr = wf.makeRef(o1);
|
||||
wr = new WeakRef(o1);
|
||||
let o2 = {};
|
||||
wr_control = wf_control.makeRef(o2);
|
||||
wr_control = new WeakRef(o2);
|
||||
})();
|
||||
|
||||
let strong = {a: wr.deref(), b: wr_control.deref()};
|
||||
@ -32,14 +20,6 @@ gc();
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
gc();
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
// We have a strong reference to the objects, so the WeakRefs are not cleared yet.
|
||||
assertEquals(0, cleanup_count);
|
||||
|
||||
// Call deref inside a closure, trying to avoid accidentally storing a strong
|
||||
// reference into the object in the stack frame.
|
||||
(function() {
|
||||
@ -60,17 +40,6 @@ gc();
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
assertEquals(1, cleanup_count);
|
||||
assertEquals(1, cleanup_cells.length);
|
||||
assertEquals(wc, cleanup_cells[0]);
|
||||
|
||||
gc();
|
||||
|
||||
%PerformMicrotaskCheckpoint();
|
||||
// Next turn.
|
||||
|
||||
assertEquals(2, cleanup_count);
|
||||
assertEquals(2, cleanup_cells.length);
|
||||
assertEquals(wr, cleanup_cells[1]);
|
||||
|
||||
assertEquals(undefined, wr.deref());
|
||||
|
Loading…
Reference in New Issue
Block a user