Commit b8f8deaf authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[js weak refs] Initial JS Weak Ref implementation.

Minimal implementation to run a simple example (see test) demonstrating the
weakness of WeakCell.

- Behind FLAG_harmony_weak_refs
- Add WeakFactory & WeakCell, no WeakRef in this version.

Spec clarifications: goo.gl/7ujBAk
Design doc: goo.gl/nvof2T

BUG=v8:8179

Change-Id: Iea2a7a2201e6380644235d190a542ab46e082382
Reviewed-on: https://chromium-review.googlesource.com/c/1238579Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#56483}
parent c47de293
......@@ -1638,6 +1638,7 @@ v8_source_set("v8_base") {
"src/builtins/builtins-typed-array.cc",
"src/builtins/builtins-utils-inl.h",
"src/builtins/builtins-utils.h",
"src/builtins/builtins-weak-refs.cc",
"src/builtins/builtins.cc",
"src/builtins/builtins.h",
"src/builtins/constants-table-builder.cc",
......@@ -2246,6 +2247,8 @@ v8_source_set("v8_base") {
"src/objects/js-segmenter-inl.h",
"src/objects/js-segmenter.cc",
"src/objects/js-segmenter.h",
"src/objects/js-weak-refs-inl.h",
"src/objects/js-weak-refs.h",
"src/objects/literal-objects-inl.h",
"src/objects/literal-objects.cc",
"src/objects/literal-objects.h",
......
......@@ -6,6 +6,7 @@
#define V8_API_INL_H_
#include "src/api.h"
#include "src/handles-inl.h"
#include "src/objects-inl.h"
#include "src/objects/stack-frame-info.h"
......
......@@ -44,6 +44,7 @@
#include "src/objects/js-relative-time-format.h"
#include "src/objects/js-segmenter.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-weak-refs.h"
#include "src/objects/templates.h"
#include "src/snapshot/natives.h"
#include "src/snapshot/snapshot.h"
......@@ -4538,6 +4539,87 @@ void Genesis::InitializeGlobal_harmony_string_matchall() {
}
}
void Genesis::InitializeGlobal_harmony_weak_refs() {
if (!FLAG_harmony_weak_refs) return;
Factory* factory = isolate()->factory();
Handle<JSGlobalObject> global(native_context()->global_object(), isolate());
{
// Create %WeakFactoryPrototype%
Handle<String> weak_factory_name = factory->WeakFactory_string();
Handle<JSObject> weak_factory_prototype =
factory->NewJSObject(isolate()->object_function(), TENURED);
// Create %WeakFactory%
Handle<JSFunction> weak_factory_fun =
CreateFunction(isolate(), weak_factory_name, JS_WEAK_FACTORY_TYPE,
JSWeakFactory::kSize, 0, weak_factory_prototype,
Builtins::kWeakFactoryConstructor);
weak_factory_fun->shared()->DontAdaptArguments();
weak_factory_fun->shared()->set_length(1);
// Install the "constructor" property on the prototype.
JSObject::AddProperty(isolate(), weak_factory_prototype,
factory->constructor_string(), weak_factory_fun,
DONT_ENUM);
JSObject::AddProperty(
isolate(), weak_factory_prototype, factory->to_string_tag_symbol(),
weak_factory_name,
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
JSObject::AddProperty(isolate(), global, weak_factory_name,
weak_factory_fun, DONT_ENUM);
Handle<String> make_cell_name = factory->makeCell_string();
SimpleInstallFunction(isolate(), weak_factory_prototype, make_cell_name,
Builtins::kWeakFactoryMakeCell, 2, false);
}
{
// Create %WeakCellPrototype%
Handle<Map> weak_cell_map =
factory->NewMap(JS_WEAK_CELL_TYPE, JSWeakCell::kSize);
native_context()->set_js_weak_cell_map(*weak_cell_map);
Handle<JSObject> weak_cell_prototype =
factory->NewJSObject(isolate()->object_function(), TENURED);
Map::SetPrototype(isolate(), weak_cell_map, weak_cell_prototype);
// TODO(marja): install functions here.
JSObject::AddProperty(
isolate(), weak_cell_prototype, factory->to_string_tag_symbol(),
factory->WeakCell_string(),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
}
{
// Create cleanup iterator for JSWeakFactory.
Handle<JSObject> iterator_prototype(
native_context()->initial_iterator_prototype(), isolate());
Handle<JSObject> cleanup_iterator_prototype =
factory->NewJSObject(isolate()->object_function(), TENURED);
JSObject::ForceSetPrototype(cleanup_iterator_prototype, iterator_prototype);
JSObject::AddProperty(
isolate(), cleanup_iterator_prototype, factory->to_string_tag_symbol(),
factory->NewStringFromAsciiChecked("JSWeakFactoryCleanupIterator"),
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY));
SimpleInstallFunction(isolate(), cleanup_iterator_prototype, "next",
Builtins::kWeakFactoryCleanupIteratorNext, 0, true);
Handle<Map> cleanup_iterator_map =
factory->NewMap(JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE,
JSWeakFactoryCleanupIterator::kSize);
Map::SetPrototype(isolate(), cleanup_iterator_map,
cleanup_iterator_prototype);
native_context()->set_js_weak_factory_cleanup_iterator_map(
*cleanup_iterator_map);
}
}
#ifdef V8_INTL_SUPPORT
void Genesis::InitializeGlobal_harmony_intl_list_format() {
if (!FLAG_harmony_intl_list_format) return;
......
......@@ -1330,7 +1330,12 @@ namespace internal {
\
/* Trace */ \
CPP(IsTraceCategoryEnabled) \
CPP(Trace)
CPP(Trace) \
\
/* Weak refs */ \
CPP(WeakFactoryCleanupIteratorNext) \
CPP(WeakFactoryConstructor) \
CPP(WeakFactoryMakeCell)
#ifdef V8_INTL_SUPPORT
#define BUILTIN_LIST_INTL(CPP, TFJ, TFS) \
......
// 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.
#include "src/builtins/builtins-utils-inl.h"
#include "src/objects/js-weak-refs-inl.h"
namespace v8 {
namespace internal {
BUILTIN(WeakFactoryConstructor) {
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> cleanup = args.atOrUndefined(isolate, 1);
Handle<JSObject> result;
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, result,
JSObject::New(target, new_target, Handle<AllocationSite>::null()));
// TODO(marja): (spec) here we could return an error if cleanup is not a
// function, if the spec said so.
Handle<JSWeakFactory> weak_factory = Handle<JSWeakFactory>::cast(result);
weak_factory->set_cleanup(*cleanup);
return *weak_factory;
}
BUILTIN(WeakFactoryMakeCell) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSWeakFactory, weak_factory, "WeakFactory.makeCell");
Handle<Object> object = args.atOrUndefined(isolate, 1);
// TODO(marja): if the type is not an object, throw TypeError. Ditto for
// SameValue(target, holdings).
Handle<JSObject> js_object = Handle<JSObject>::cast(object);
// TODO(marja): Realms.
Handle<Map> weak_cell_map(isolate->native_context()->js_weak_cell_map(),
isolate);
// Allocate the JSWeakCell object in the old space, because 1) JSWeakCell
// weakness handling is only implemented in the old space 2) they're
// supposedly long-living. TODO(marja): Support JSWeakCells in Scavenger.
Handle<JSWeakCell> weak_cell =
Handle<JSWeakCell>::cast(isolate->factory()->NewJSObjectFromMap(
weak_cell_map, TENURED, Handle<AllocationSite>::null()));
weak_cell->set_factory(*weak_factory);
weak_cell->set_target(*js_object);
weak_cell->set_prev(ReadOnlyRoots(isolate).undefined_value());
weak_cell->set_next(weak_factory->active_cells());
if (weak_factory->active_cells()->IsJSWeakCell()) {
JSWeakCell::cast(weak_factory->active_cells())->set_prev(*weak_cell);
}
weak_factory->set_active_cells(*weak_cell);
return *weak_cell;
}
BUILTIN(WeakFactoryCleanupIteratorNext) {
HandleScope scope(isolate);
CHECK_RECEIVER(JSWeakFactoryCleanupIterator, iterator, "next");
Handle<JSWeakFactory> weak_factory(iterator->factory(), isolate);
if (!weak_factory->NeedsCleanup()) {
return *isolate->factory()->NewJSIteratorResult(
handle(ReadOnlyRoots(isolate).undefined_value(), isolate), true);
}
Handle<JSWeakCell> weak_cell_object =
handle(weak_factory->PopClearedCell(isolate), isolate);
return *isolate->factory()->NewJSIteratorResult(weak_cell_object, false);
}
} // namespace internal
} // namespace v8
......@@ -44,7 +44,10 @@ class JSRegExpStringIterator;
class JSRelativeTimeFormat;
class JSSegmenter;
class JSV8BreakIterator;
class JSWeakCell;
class JSWeakCollection;
class JSWeakFactory;
class JSWeakFactoryCleanupIterator;
class JSWeakMap;
class JSWeakSet;
class MaybeObject;
......
......@@ -352,6 +352,9 @@ Type::bitset BitsetType::Lub(const MapRefLike& map) {
case PROMISE_FULFILL_REACTION_JOB_TASK_TYPE:
case PROMISE_REJECT_REACTION_JOB_TASK_TYPE:
case PROMISE_RESOLVE_THENABLE_JOB_TASK_TYPE:
case JS_WEAK_CELL_TYPE:
case JS_WEAK_FACTORY_TYPE:
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
UNREACHABLE();
}
UNREACHABLE();
......
......@@ -9,6 +9,7 @@
#include "src/heap/heap.h"
#include "src/objects-inl.h"
#include "src/objects/dictionary.h"
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/regexp-match-info.h"
#include "src/objects/scope-info.h"
......@@ -217,6 +218,14 @@ Map* Context::GetInitialJSArrayMap(ElementsKind kind) const {
return Map::cast(initial_js_array_map);
}
void NativeContext::AddDirtyJSWeakFactory(JSWeakFactory* weak_factory,
Isolate* isolate) {
DCHECK(dirty_js_weak_factories()->IsUndefined(isolate) ||
dirty_js_weak_factories()->IsJSWeakFactory());
weak_factory->set_next(dirty_js_weak_factories());
set_dirty_js_weak_factories(weak_factory);
}
} // namespace internal
} // namespace v8
......
......@@ -12,6 +12,7 @@ namespace internal {
class JSGlobalObject;
class JSGlobalProxy;
class JSWeakFactory;
class NativeContext;
class RegExpMatchInfo;
......@@ -165,6 +166,7 @@ enum ContextLookupFlags {
V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \
V(DATE_FUNCTION_INDEX, JSFunction, date_function) \
V(DEBUG_CONTEXT_ID_INDEX, Object, debug_context_id) \
V(DIRTY_JS_WEAK_FACTORIES_INDEX, Object, dirty_js_weak_factories) \
V(EMPTY_FUNCTION_INDEX, JSFunction, empty_function) \
V(ERROR_MESSAGE_FOR_CODE_GEN_FROM_STRINGS_INDEX, Object, \
error_message_for_code_gen_from_strings) \
......@@ -229,6 +231,9 @@ enum ContextLookupFlags {
V(JS_MODULE_NAMESPACE_MAP, Map, js_module_namespace_map) \
V(JS_SET_FUN_INDEX, JSFunction, js_set_fun) \
V(JS_SET_MAP_INDEX, Map, js_set_map) \
V(JS_WEAK_CELL_MAP_INDEX, Map, js_weak_cell_map) \
V(JS_WEAK_FACTORY_CLEANUP_ITERATOR_MAP_INDEX, Map, \
js_weak_factory_cleanup_iterator_map) \
V(JS_WEAK_MAP_FUN_INDEX, JSFunction, js_weak_map_fun) \
V(JS_WEAK_SET_FUN_INDEX, JSFunction, js_weak_set_fun) \
V(MAP_CACHE_INDEX, Object, map_cache) \
......@@ -636,6 +641,10 @@ class NativeContext : public Context {
static inline NativeContext* cast(Object* context);
// TODO(neis): Move some stuff from Context here.
// Add weak_factory into the dirty_weak_js_factories list.
inline void AddDirtyJSWeakFactory(JSWeakFactory* weak_factory,
Isolate* isolate);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(NativeContext);
};
......
......@@ -209,11 +209,12 @@ DEFINE_IMPLICATION(harmony_class_fields, harmony_private_fields)
// Update bootstrapper.cc whenever adding a new feature flag.
// Features that are still work in progress (behind individual flags).
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_await_optimization, "harmony await taking 1 tick") \
V(harmony_regexp_sequence, "RegExp Unicode sequence properties")
#define HARMONY_INPROGRESS_BASE(V) \
V(harmony_do_expressions, "harmony do-expressions") \
V(harmony_class_fields, "harmony fields in class literals") \
V(harmony_await_optimization, "harmony await taking 1 tick") \
V(harmony_regexp_sequence, "RegExp Unicode sequence properties") \
V(harmony_weak_refs, "harmony weak references")
#ifdef V8_INTL_SUPPORT
#define HARMONY_INPROGRESS(V) \
......
......@@ -171,6 +171,7 @@
V(_, LinkError_string, "LinkError") \
V(_, long_string, "long") \
V(_, loose_string, "loose") \
V(_, makeCell_string, "makeCell") \
V(_, Map_string, "Map") \
V(_, MapIterator_string, "Map Iterator") \
V(_, message_string, "message") \
......@@ -269,6 +270,8 @@
V(_, value_string, "value") \
V(_, valueOf_string, "valueOf") \
V(_, values_string, "values") \
V(_, WeakCell_string, "WeakCell") \
V(_, WeakFactory_string, "WeakFactory") \
V(_, WeakMap_string, "WeakMap") \
V(_, WeakSet_string, "WeakSet") \
V(_, week_string, "week") \
......
......@@ -188,6 +188,29 @@ class ConcurrentMarkingVisitor final
return VisitJSObjectSubclass(map, object);
}
int VisitJSWeakCell(Map* map, JSWeakCell* weak_cell) {
int size = VisitJSObjectSubclass(map, weak_cell);
if (size == 0) {
return 0;
}
if (weak_cell->target()->IsHeapObject()) {
HeapObject* target = HeapObject::cast(weak_cell->target());
if (marking_state_.IsBlackOrGrey(target)) {
// Record the slot inside the JSWeakCell, since the
// VisitJSObjectSubclass above didn't visit it.
Object** slot =
HeapObject::RawField(weak_cell, JSWeakCell::kTargetOffset);
MarkCompactCollector::RecordSlot(weak_cell, slot, target);
} else {
// JSWeakCell 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_cells.Push(task_id_, weak_cell);
}
}
return size;
}
// Some JS objects can carry back links to embedders that contain information
// relevant to the garbage collectors.
......@@ -407,6 +430,11 @@ class ConcurrentMarkingVisitor final
UNREACHABLE();
}
void VisitCustomWeakPointers(HeapObject* host, Object** start,
Object** end) override {
DCHECK(host->IsJSWeakCell());
}
private:
SlotSnapshot* slot_snapshot_;
};
......@@ -624,6 +652,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_cells.FlushToGlobal(task_id);
base::AsAtomicWord::Relaxed_Store<size_t>(&task_state->marked_bytes, 0);
total_marked_bytes_ += marked_bytes;
......
......@@ -1360,6 +1360,8 @@ Handle<NativeContext> Factory::NewNativeContext() {
context->set_errors_thrown(Smi::kZero);
context->set_math_random_index(Smi::kZero);
context->set_serialized_objects(*empty_fixed_array());
context->set_dirty_js_weak_factories(
ReadOnlyRoots(isolate()).undefined_value());
return context;
}
......
......@@ -10,6 +10,7 @@
#include "src/heap/objects-visiting-inl.h"
#include "src/heap/remembered-set.h"
#include "src/objects/js-collection-inl.h"
#include "src/objects/js-weak-refs-inl.h"
namespace v8 {
namespace internal {
......@@ -175,6 +176,30 @@ 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>::VisitJSWeakCell(Map* map,
JSWeakCell* weak_cell) {
if (weak_cell->target()->IsHeapObject()) {
HeapObject* target = HeapObject::cast(weak_cell->target());
if (marking_state()->IsBlackOrGrey(target)) {
// Record the slot inside the JSWeakCell, since the IterateBody below
// won't visit it.
Object** slot =
HeapObject::RawField(weak_cell, JSWeakCell::kTargetOffset);
collector_->RecordSlot(weak_cell, slot, target);
} else {
// JSWeakCell points to a potentially dead object. We have to process
// them when we know the liveness of the whole transitive closure.
collector_->AddWeakCell(weak_cell);
}
}
int size = JSWeakCell::BodyDescriptor::SizeOf(map, weak_cell);
JSWeakCell::BodyDescriptor::IterateBody(map, weak_cell, size, this);
return size;
}
template <FixedArrayVisitationMode fixed_array_mode,
TraceRetainingPathMode retaining_path_mode, typename MarkingState>
void MarkingVisitor<fixed_array_mode, retaining_path_mode,
......
......@@ -29,6 +29,7 @@
#include "src/heap/worklist.h"
#include "src/ic/stub-cache.h"
#include "src/objects/hash-table-inl.h"
#include "src/objects/js-objects-inl.h"
#include "src/transitions-inl.h"
#include "src/utils-inl.h"
#include "src/v8.h"
......@@ -1859,14 +1860,19 @@ void MarkCompactCollector::ClearNonLiveReferences() {
// cleared.
ClearFullMapTransitions();
}
ClearWeakReferences();
MarkDependentCodeForDeoptimization();
{
TRACE_GC(heap()->tracer(), GCTracer::Scope::MC_CLEAR_WEAK_REFERENCES);
ClearWeakReferences();
ClearWeakCollections();
ClearJSWeakCells();
}
ClearWeakCollections();
MarkDependentCodeForDeoptimization();
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_cells.IsEmpty());
}
void MarkCompactCollector::MarkDependentCodeForDeoptimization() {
......@@ -2082,6 +2088,52 @@ void MarkCompactCollector::ClearWeakReferences() {
}
}
void MarkCompactCollector::ClearJSWeakCells() {
if (!FLAG_harmony_weak_refs) {
return;
}
JSWeakCell* weak_cell;
bool schedule_cleanup_task = false;
while (weak_objects_.js_weak_cells.Pop(kMainThread, &weak_cell)) {
// We do not insert cleared weak cells into the list, so the value
// cannot be a Smi here.
HeapObject* target = HeapObject::cast(weak_cell->target());
JSWeakFactory* weak_factory = weak_cell->factory();
if (!non_atomic_marking_state()->IsBlackOrGrey(target)) {
if (!weak_factory->NeedsCleanup()) {
// This is the first dirty JSWeakCell of that JSWeakFactory. Record
// the dirty JSWeakFactory in the native context.
isolate()->native_context()->AddDirtyJSWeakFactory(weak_factory,
isolate());
schedule_cleanup_task = true;
}
// We're modifying the pointers in JSWeakCell and JSWeakFactory during GC;
// thus we need to record the slots it writes. The normal write barrier is
// not enough, since it's disabled before GC.
weak_cell->Nullify(isolate(),
[](HeapObject* object, Object** slot, Object* target) {
if (target->IsHeapObject()) {
RecordSlot(object, slot, HeapObject::cast(target));
}
});
DCHECK(weak_factory->NeedsCleanup());
} else {
// The value of the JSWeakCell is alive.
Object** slot =
HeapObject::RawField(weak_cell, JSWeakCell::kTargetOffset);
RecordSlot(weak_cell, slot, HeapObject::cast(*slot));
}
}
if (schedule_cleanup_task) {
// TODO(marja): Make this a microtask.
v8::Platform* platform = V8::GetCurrentPlatform();
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate());
platform->GetForegroundTaskRunner(v8_isolate)
->PostTask(
std::unique_ptr<v8::Task>(new JSWeakFactoryCleanupTask(isolate())));
}
}
void MarkCompactCollector::AbortWeakObjects() {
weak_objects_.transition_arrays.Clear();
weak_objects_.ephemeron_hash_tables.Clear();
......@@ -2090,6 +2142,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_cells.Clear();
}
void MarkCompactCollector::RecordRelocSlot(Code* host, RelocInfo* rinfo,
......
......@@ -21,6 +21,7 @@ namespace internal {
class EvacuationJobTraits;
class HeapObjectVisitor;
class ItemParallelJob;
class JSWeakCell;
class MigrationObserver;
class RecordMigratedSlotVisitor;
class UpdatingItem;
......@@ -436,6 +437,8 @@ struct WeakObjects {
// object. Optimize this by adding a different storage for old space.
Worklist<std::pair<HeapObject*, HeapObjectReference**>, 64> weak_references;
Worklist<std::pair<HeapObject*, Code*>, 64> weak_objects_in_code;
Worklist<JSWeakCell*, 64> js_weak_cells;
};
struct EphemeronMarking {
......@@ -670,6 +673,10 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
std::make_pair(object, code));
}
void AddWeakCell(JSWeakCell* weak_cell) {
weak_objects_.js_weak_cells.Push(kMainThread, weak_cell);
}
void AddNewlyDiscovered(HeapObject* object) {
if (ephemeron_marking_.newly_discovered_overflowed) return;
......@@ -812,6 +819,11 @@ class MarkCompactCollector final : public MarkCompactCollectorBase {
// the dead map via weak cell, then this function also clears the map
// transition.
void ClearWeakReferences();
// Goes through the list of encountered JSWeakCells and clears those with dead
// values.
void ClearJSWeakCells();
void AbortWeakObjects();
// Starts sweeping of spaces by contributing on the main thread and setting
......@@ -918,6 +930,7 @@ class MarkingVisitor final
V8_INLINE int VisitJSTypedArray(Map* map, JSTypedArray* object);
V8_INLINE int VisitMap(Map* map, Map* object);
V8_INLINE int VisitTransitionArray(Map* map, TransitionArray* object);
V8_INLINE int VisitJSWeakCell(Map* map, JSWeakCell* object);
// ObjectVisitor implementation.
V8_INLINE void VisitPointer(HeapObject* host, Object** p) final;
......
......@@ -13,6 +13,7 @@
#include "src/macro-assembler.h"
#include "src/objects-body-descriptors-inl.h"
#include "src/objects-inl.h"
#include "src/objects/js-weak-refs-inl.h"
namespace v8 {
namespace internal {
......@@ -59,6 +60,8 @@ 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();
}
......
......@@ -24,6 +24,7 @@ class JSArrayBuffer;
class JSDataView;
class JSRegExp;
class JSTypedArray;
class JSWeakCell;
class JSWeakCollection;
class UncompiledDataWithoutPreParsedScope;
class UncompiledDataWithPreParsedScope;
......@@ -134,6 +135,11 @@ class NewSpaceVisitor : public HeapVisitor<int, ConcreteVisitor> {
UNREACHABLE();
return 0;
}
int VisitJSWeakCell(Map* map, JSWeakCell* js_weak_cell) {
UNREACHABLE();
return 0;
}
};
class WeakObjectRetainer;
......
......@@ -10,6 +10,7 @@
#include "src/objects-body-descriptors.h"
#include "src/objects/hash-table.h"
#include "src/objects/js-collection.h"
#include "src/objects/js-weak-refs.h"
#include "src/transitions.h"
#include "src/wasm/wasm-objects-inl.h"
......@@ -162,6 +163,25 @@ class JSFunction::BodyDescriptor final : public BodyDescriptorBase {
}
};
class JSWeakCell::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 AllocationSite::BodyDescriptor final : public BodyDescriptorBase {
public:
STATIC_ASSERT(AllocationSite::kCommonPointerFieldEndOffset ==
......@@ -801,6 +821,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
case JS_SPECIAL_API_OBJECT_TYPE:
case JS_MESSAGE_OBJECT_TYPE:
case JS_BOUND_FUNCTION_TYPE:
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
case JS_WEAK_FACTORY_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_V8_BREAK_ITERATOR_TYPE:
case JS_INTL_COLLATOR_TYPE:
......@@ -833,6 +855,8 @@ ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3, T4 p4) {
return Op::template apply<JSTypedArray::BodyDescriptor>(p1, p2, p3, p4);
case JS_FUNCTION_TYPE:
return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3, p4);
case JS_WEAK_CELL_TYPE:
return Op::template apply<JSWeakCell::BodyDescriptor>(p1, p2, p3, p4);
case ODDBALL_TYPE:
return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3, p4);
case JS_PROXY_TYPE:
......
......@@ -40,6 +40,7 @@
#include "src/objects/js-relative-time-format-inl.h"
#include "src/objects/js-segmenter-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/maybe-object.h"
#include "src/objects/microtask-inl.h"
......@@ -307,6 +308,16 @@ void HeapObject::HeapObjectVerify(Isolate* isolate) {
JSAsyncFromSyncIterator::cast(this)->JSAsyncFromSyncIteratorVerify(
isolate);
break;
case JS_WEAK_CELL_TYPE:
JSWeakCell::cast(this)->JSWeakCellVerify(isolate);
break;
case JS_WEAK_FACTORY_TYPE:
JSWeakFactory::cast(this)->JSWeakFactoryVerify(isolate);
break;
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
JSWeakFactoryCleanupIterator::cast(this)
->JSWeakFactoryCleanupIteratorVerify(isolate);
break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapVerify(isolate);
break;
......@@ -1213,6 +1224,44 @@ void JSMapIterator::JSMapIteratorVerify(Isolate* isolate) {
CHECK(index()->IsSmi());
}
void JSWeakCell::JSWeakCellVerify(Isolate* isolate) {
CHECK(IsJSWeakCell());
JSObjectVerify(isolate);
CHECK(next()->IsJSWeakCell() || next()->IsUndefined(isolate));
if (next()->IsJSWeakCell()) {
CHECK_EQ(JSWeakCell::cast(next())->prev(), this);
}
CHECK(prev()->IsJSWeakCell() || prev()->IsUndefined(isolate));
if (prev()->IsJSWeakCell()) {
CHECK_EQ(JSWeakCell::cast(prev())->next(), this);
}
CHECK(factory()->IsJSWeakFactory());
}
void JSWeakFactory::JSWeakFactoryVerify(Isolate* isolate) {
CHECK(IsJSWeakFactory());
JSObjectVerify(isolate);
VerifyHeapPointer(isolate, cleanup());
CHECK(active_cells()->IsUndefined(isolate) || active_cells()->IsJSWeakCell());
if (active_cells()->IsJSWeakCell()) {
CHECK(JSWeakCell::cast(active_cells())->prev()->IsUndefined(isolate));
}
CHECK(cleared_cells()->IsUndefined(isolate) ||
cleared_cells()->IsJSWeakCell());
if (cleared_cells()->IsJSWeakCell()) {
CHECK(JSWeakCell::cast(cleared_cells())->prev()->IsUndefined(isolate));
}
}
void JSWeakFactoryCleanupIterator::JSWeakFactoryCleanupIteratorVerify(
Isolate* isolate) {
CHECK(IsJSWeakFactoryCleanupIterator());
JSObjectVerify(isolate);
VerifyHeapPointer(isolate, factory());
}
void JSWeakMap::JSWeakMapVerify(Isolate* isolate) {
CHECK(IsJSWeakMap());
JSObjectVerify(isolate);
......
......@@ -202,6 +202,9 @@ namespace internal {
V(JS_SET_KEY_VALUE_ITERATOR_TYPE) \
V(JS_SET_VALUE_ITERATOR_TYPE) \
V(JS_STRING_ITERATOR_TYPE) \
V(JS_WEAK_CELL_TYPE) \
V(JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE) \
V(JS_WEAK_FACTORY_TYPE) \
V(JS_WEAK_MAP_TYPE) \
V(JS_WEAK_SET_TYPE) \
V(JS_TYPED_ARRAY_TYPE) \
......
......@@ -40,6 +40,7 @@
#include "src/objects/js-relative-time-format-inl.h"
#include "src/objects/js-segmenter-inl.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/microtask-queue-inl.h"
......@@ -268,6 +269,16 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT
case JS_MAP_VALUE_ITERATOR_TYPE:
JSMapIterator::cast(this)->JSMapIteratorPrint(os);
break;
case JS_WEAK_CELL_TYPE:
JSWeakCell::cast(this)->JSWeakCellPrint(os);
break;
case JS_WEAK_FACTORY_TYPE:
JSWeakFactory::cast(this)->JSWeakFactoryPrint(os);
break;
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
JSWeakFactoryCleanupIterator::cast(this)
->JSWeakFactoryCleanupIteratorPrint(os);
break;
case JS_WEAK_MAP_TYPE:
JSWeakMap::cast(this)->JSWeakMapPrint(os);
break;
......@@ -1262,6 +1273,30 @@ void JSMapIterator::JSMapIteratorPrint(std::ostream& os) { // NOLINT
JSCollectionIteratorPrint(os);
}
void JSWeakCell::JSWeakCellPrint(std::ostream& os) {
JSObjectPrintHeader(os, this, "JSWeakCell");
os << "\n - factory: " << Brief(factory());
os << "\n - target: " << Brief(target());
os << "\n - prev: " << Brief(prev());
os << "\n - next: " << Brief(next());
os << "\n";
}
void JSWeakFactory::JSWeakFactoryPrint(std::ostream& os) {
JSObjectPrintHeader(os, this, "JSWeakFactory");
os << "\n - cleanup: " << Brief(cleanup());
os << "\n - active_cells: " << Brief(active_cells());
os << "\n - cleared_cells: " << Brief(cleared_cells());
os << "\n";
}
void JSWeakFactoryCleanupIterator::JSWeakFactoryCleanupIteratorPrint(
std::ostream& os) {
JSObjectPrintHeader(os, this, "JSWeakFactoryCleanupIterator");
os << "\n - factory: " << Brief(factory());
os << "\n";
}
void JSWeakMap::JSWeakMapPrint(std::ostream& os) { // NOLINT
JSObjectPrintHeader(os, this, "JSWeakMap");
os << "\n - table: " << Brief(table());
......
......@@ -81,6 +81,7 @@
#include "src/objects/js-relative-time-format.h"
#include "src/objects/js-segmenter.h"
#endif // V8_INTL_SUPPORT
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/map.h"
#include "src/objects/microtask-inl.h"
......@@ -1438,6 +1439,10 @@ int JSObject::GetHeaderSize(InstanceType type,
case JS_MAP_KEY_VALUE_ITERATOR_TYPE:
case JS_MAP_VALUE_ITERATOR_TYPE:
return JSMapIterator::kSize;
case JS_WEAK_CELL_TYPE:
return JSWeakCell::kSize;
case JS_WEAK_FACTORY_TYPE:
return JSWeakFactory::kSize;
case JS_WEAK_MAP_TYPE:
return JSWeakMap::kSize;
case JS_WEAK_SET_TYPE:
......@@ -3219,6 +3224,8 @@ VisitorId Map::GetVisitorId(Map* map) {
case JS_PROMISE_TYPE:
case JS_REGEXP_TYPE:
case JS_REGEXP_STRING_ITERATOR_TYPE:
case JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE:
case JS_WEAK_FACTORY_TYPE:
#ifdef V8_INTL_SUPPORT
case JS_INTL_V8_BREAK_ITERATOR_TYPE:
case JS_INTL_COLLATOR_TYPE:
......@@ -3241,6 +3248,9 @@ VisitorId Map::GetVisitorId(Map* map) {
case JS_SPECIAL_API_OBJECT_TYPE:
return kVisitJSApiObject;
case JS_WEAK_CELL_TYPE:
return kVisitJSWeakCell;
case FILLER_TYPE:
case FOREIGN_TYPE:
case HEAP_NUMBER_TYPE:
......@@ -18816,5 +18826,54 @@ template void
BaseNameDictionary<NameDictionary, NameDictionaryShape>::CollectKeysTo(
Handle<NameDictionary> dictionary, KeyAccumulator* keys);
void JSWeakFactoryCleanupTask::Run() {
DCHECK(FLAG_harmony_weak_refs);
HandleScope handle_scope(isolate_);
Handle<Context> native_context =
Handle<Context>::cast(Utils::OpenPersistent(native_context_));
while (native_context->dirty_js_weak_factories()->IsJSWeakFactory()) {
Handle<JSWeakFactory> weak_factory =
handle(JSWeakFactory::cast(native_context->dirty_js_weak_factories()),
isolate_);
native_context->set_dirty_js_weak_factories(weak_factory->next());
weak_factory->set_next(ReadOnlyRoots(isolate_).undefined_value());
// TODO(marja): After WeakCell.cleanup() is added, it's possible that it's
// called for something already in cleared_cells list. In that case, we
// shouldn't call the user's cleanup function.
// Construct the iterator.
Handle<JSWeakFactoryCleanupIterator> iterator;
{
Handle<Map> cleanup_iterator_map(
native_context->js_weak_factory_cleanup_iterator_map(), isolate_);
iterator = Handle<JSWeakFactoryCleanupIterator>::cast(
isolate_->factory()->NewJSObjectFromMap(
cleanup_iterator_map, NOT_TENURED,
Handle<AllocationSite>::null()));
iterator->set_factory(*weak_factory);
}
Handle<Object> cleanup(weak_factory->cleanup(), isolate_);
v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate_));
v8::Local<v8::Value> result;
MaybeHandle<Object> exception;
Handle<Object> args[] = {iterator};
bool has_pending_exception = !ToLocal<Value>(
Execution::TryCall(
isolate_, cleanup,
handle(ReadOnlyRoots(isolate_).undefined_value(), isolate_), 1,
args, Execution::MessageHandling::kReport, &exception,
Execution::Target::kCallable),
&result);
// TODO(marja): (spec): What if there's an exception?
USE(has_pending_exception);
// TODO(marja): (spec): Should the iterator be invalidated after the
// function returns?
}
}
} // namespace internal
} // namespace v8
This diff is collapsed.
// 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.
#ifndef V8_OBJECTS_JS_WEAK_REFS_INL_H_
#define V8_OBJECTS_JS_WEAK_REFS_INL_H_
#include "src/objects/js-weak-refs.h"
#include "src/api-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
ACCESSORS(JSWeakFactory, cleanup, Object, kCleanupOffset)
ACCESSORS(JSWeakFactory, active_cells, Object, kActiveCellsOffset)
ACCESSORS(JSWeakFactory, cleared_cells, Object, kClearedCellsOffset)
ACCESSORS(JSWeakFactory, next, Object, kNextOffset)
CAST_ACCESSOR(JSWeakFactory)
ACCESSORS(JSWeakCell, factory, JSWeakFactory, kFactoryOffset)
ACCESSORS(JSWeakCell, target, Object, kTargetOffset)
ACCESSORS(JSWeakCell, next, Object, kNextOffset)
ACCESSORS(JSWeakCell, prev, Object, kPrevOffset)
CAST_ACCESSOR(JSWeakCell)
ACCESSORS(JSWeakFactoryCleanupIterator, factory, JSWeakFactory, kFactoryOffset)
CAST_ACCESSOR(JSWeakFactoryCleanupIterator)
bool JSWeakFactory::NeedsCleanup() const {
return cleared_cells()->IsJSWeakCell();
}
JSWeakCell* JSWeakFactory::PopClearedCell(Isolate* isolate) {
JSWeakCell* weak_cell = JSWeakCell::cast(cleared_cells());
DCHECK(weak_cell->prev()->IsUndefined(isolate));
set_cleared_cells(weak_cell->next());
weak_cell->set_next(ReadOnlyRoots(isolate).undefined_value());
if (cleared_cells()->IsJSWeakCell()) {
JSWeakCell* cleared_cells_head = JSWeakCell::cast(cleared_cells());
DCHECK_EQ(cleared_cells_head->prev(), weak_cell);
cleared_cells_head->set_prev(ReadOnlyRoots(isolate).undefined_value());
} else {
DCHECK(cleared_cells()->IsUndefined(isolate));
}
return weak_cell;
}
void JSWeakCell::Nullify(
Isolate* isolate,
std::function<void(HeapObject* object, Object** slot, Object* target)>
gc_notify_updated_slot) {
DCHECK(target()->IsJSReceiver());
set_target(Smi::kZero);
JSWeakFactory* weak_factory = factory();
// Remove from the JSWeakCell from the "active_cells" list of its
// JSWeakFactory and insert it into the "cleared" list.
if (prev()->IsJSWeakCell()) {
DCHECK_NE(weak_factory->active_cells(), this);
JSWeakCell* prev_cell = JSWeakCell::cast(prev());
prev_cell->set_next(next());
gc_notify_updated_slot(
prev_cell, HeapObject::RawField(prev_cell, JSWeakCell::kNextOffset),
next());
} else {
DCHECK_EQ(weak_factory->active_cells(), this);
weak_factory->set_active_cells(next());
gc_notify_updated_slot(
weak_factory,
HeapObject::RawField(weak_factory, JSWeakFactory::kActiveCellsOffset),
next());
}
if (next()->IsJSWeakCell()) {
JSWeakCell* next_cell = JSWeakCell::cast(next());
next_cell->set_prev(prev());
gc_notify_updated_slot(
next_cell, HeapObject::RawField(next_cell, JSWeakCell::kPrevOffset),
prev());
}
set_prev(ReadOnlyRoots(isolate).undefined_value());
Object* cleared_head = weak_factory->cleared_cells();
if (cleared_head->IsJSWeakCell()) {
JSWeakCell* cleared_head_cell = JSWeakCell::cast(cleared_head);
cleared_head_cell->set_prev(this);
gc_notify_updated_slot(
cleared_head_cell,
HeapObject::RawField(cleared_head_cell, JSWeakCell::kPrevOffset), this);
}
set_next(weak_factory->cleared_cells());
gc_notify_updated_slot(
this, HeapObject::RawField(this, JSWeakCell::kNextOffset), next());
weak_factory->set_cleared_cells(this);
gc_notify_updated_slot(
weak_factory,
HeapObject::RawField(weak_factory, JSWeakFactory::kClearedCellsOffset),
this);
}
JSWeakFactoryCleanupTask::JSWeakFactoryCleanupTask(Isolate* isolate)
: isolate_(isolate) {
Handle<Context> native_context =
Handle<Context>::cast(isolate->native_context());
Local<v8::Context> native_context_local = Utils::ToLocal(native_context);
native_context_.Reset(reinterpret_cast<v8::Isolate*>(isolate),
native_context_local);
}
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_WEAK_REFS_INL_H_
// 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.
#ifndef V8_OBJECTS_JS_WEAK_REFS_H_
#define V8_OBJECTS_JS_WEAK_REFS_H_
#include "src/objects/js-objects.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
class JSWeakCell;
// WeakFactory object from the JS Weak Refs spec proposal:
// https://github.com/tc39/proposal-weakrefs
class JSWeakFactory : public JSObject {
public:
DECL_PRINTER(JSWeakFactory)
DECL_VERIFIER(JSWeakFactory)
DECL_CAST(JSWeakFactory)
DECL_ACCESSORS(cleanup, Object)
DECL_ACCESSORS(active_cells, Object)
DECL_ACCESSORS(cleared_cells, Object)
// For storing a list of JSWeakFactory objects in NativeContext.
DECL_ACCESSORS(next, Object)
// Returns true if the cleared_cells list is non-empty.
inline bool NeedsCleanup() const;
// Get and remove the first cleared JSWeakCell from the cleared_cells
// list. (Assumes there is one.)
inline JSWeakCell* PopClearedCell(Isolate* isolate);
static const int kCleanupOffset = JSObject::kHeaderSize;
static const int kActiveCellsOffset = kCleanupOffset + kPointerSize;
static const int kClearedCellsOffset = kActiveCellsOffset + kPointerSize;
static const int kNextOffset = kClearedCellsOffset + kPointerSize;
static const int kSize = kNextOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakFactory);
};
// WeakCell object from the JS Weak Refs spec proposal.
class JSWeakCell : public JSObject {
public:
DECL_PRINTER(JSWeakCell)
DECL_VERIFIER(JSWeakCell)
DECL_CAST(JSWeakCell)
DECL_ACCESSORS(factory, JSWeakFactory)
DECL_ACCESSORS(target, Object)
// For storing doubly linked lists of JSWeakCells in JSWeakFactory.
DECL_ACCESSORS(prev, Object)
DECL_ACCESSORS(next, Object)
static const int kFactoryOffset = JSObject::kHeaderSize;
static const int kTargetOffset = kFactoryOffset + kPointerSize;
static const int kPrevOffset = kTargetOffset + kPointerSize;
static const int kNextOffset = kPrevOffset + kPointerSize;
static const int kSize = kNextOffset + kPointerSize;
class BodyDescriptor;
// Nullify is called during GC and it modifies the pointers in JSWeakCell and
// JSWeakFactory. Thus we need to tell the GC about the modified slots via the
// gc_notify_updated_slot function. The normal write barrier is not enough,
// since it's disabled before GC.
inline void Nullify(
Isolate* isolate,
std::function<void(HeapObject* object, Object** slot, Object* target)>
gc_notify_updated_slot);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakCell);
};
class JSWeakFactoryCleanupIterator : public JSObject {
public:
DECL_PRINTER(JSWeakFactoryCleanupIterator)
DECL_VERIFIER(JSWeakFactoryCleanupIterator)
DECL_CAST(JSWeakFactoryCleanupIterator)
DECL_ACCESSORS(factory, JSWeakFactory)
static const int kFactoryOffset = JSObject::kHeaderSize;
static const int kSize = kFactoryOffset + kPointerSize;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakFactoryCleanupIterator);
};
class JSWeakFactoryCleanupTask : public v8::Task {
public:
inline explicit JSWeakFactoryCleanupTask(Isolate* isolate);
void Run() override;
private:
v8::Persistent<v8::Context> native_context_;
Isolate* isolate_;
DISALLOW_IMPLICIT_CONSTRUCTORS(JSWeakFactoryCleanupTask);
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_JS_WEAK_REFS_H_
......@@ -41,6 +41,7 @@ namespace internal {
V(JSObject) \
V(JSObjectFast) \
V(JSTypedArray) \
V(JSWeakCell) \
V(JSWeakCollection) \
V(Map) \
V(NativeContext) \
......
// 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
(function TestConstructWeakFactory() {
let wf = new WeakFactory();
assertEquals(wf.toString(), "[object WeakFactory]");
assertNotSame(wf.__proto__, Object.prototype);
assertSame(wf.__proto__.__proto__, Object.prototype);
})();
(function TestWeakFactoryConstructorCallAsFunction() {
let caught = false;
let message = "";
try {
let f = WeakFactory();
} catch (e) {
message = e.message;
caught = true;
} finally {
assertTrue(caught);
assertEquals(message, "Constructor WeakFactory requires 'new'");
}
})();
(function TestMakeCell() {
let wf = new WeakFactory();
let wc = wf.makeCell({});
assertEquals(wc.toString(), "[object WeakCell]");
assertNotSame(wc.__proto__, Object.prototype);
assertSame(wc.__proto__.__proto__, Object.prototype);
})();
(function TestMakeCellWithoutWeakFactory() {
assertThrows(() => WeakFactory.prototype.makeCell.call({}, {}), TypeError);
})();
// 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
let cleanup_called = false;
let cleanup = function(iter) {
assertFalse(cleanup_called);
let cells = [];
for (wc of iter) {
cells.push(wc);
}
assertEquals(cells.length, 2);
if (cells[0] == wc1) {
assertEquals(cells[1], wc2);
} else {
assertEquals(cells[0], wc2);
assertEquals(cells[1], wc1);
}
cleanup_called = true;
}
let wf = new WeakFactory(cleanup);
let o1 = {};
let o2 = {};
let wc1 = wf.makeCell(o1);
let wc2 = wf.makeCell(o2);
gc();
assertFalse(cleanup_called);
// Drop the last references to o1 and o2.
o1 = null;
o2 = null;
// GC will clear the WeakCells; the cleanup function will be called the next time
// we enter the event loop.
gc();
assertFalse(cleanup_called);
let timeout_func = function() {
assertTrue(cleanup_called);
}
setTimeout(timeout_func, 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
let cleanup_called = false;
let cleanup = function(iter) {
assertFalse(cleanup_called);
let result = iter.next();
assertEquals(result.value, wc);
assertFalse(result.done);
result = iter.next();
assertTrue(result.done);
cleanup_called = true;
}
let wf = new WeakFactory(cleanup);
let o = {};
let wc = wf.makeCell(o);
gc();
assertFalse(cleanup_called);
// Drop the last reference to o.
o = null;
// GC will clear the WeakCell; the cleanup function will be called the next time
// we enter the event loop.
gc();
assertFalse(cleanup_called);
let timeout_func = function() {
assertTrue(cleanup_called);
}
setTimeout(timeout_func, 0);
......@@ -156,27 +156,30 @@ INSTANCE_TYPES = {
1077: "JS_SET_KEY_VALUE_ITERATOR_TYPE",
1078: "JS_SET_VALUE_ITERATOR_TYPE",
1079: "JS_STRING_ITERATOR_TYPE",
1080: "JS_WEAK_MAP_TYPE",
1081: "JS_WEAK_SET_TYPE",
1082: "JS_TYPED_ARRAY_TYPE",
1083: "JS_DATA_VIEW_TYPE",
1084: "JS_INTL_V8_BREAK_ITERATOR_TYPE",
1085: "JS_INTL_COLLATOR_TYPE",
1086: "JS_INTL_DATE_TIME_FORMAT_TYPE",
1087: "JS_INTL_LIST_FORMAT_TYPE",
1088: "JS_INTL_LOCALE_TYPE",
1089: "JS_INTL_NUMBER_FORMAT_TYPE",
1090: "JS_INTL_PLURAL_RULES_TYPE",
1091: "JS_INTL_RELATIVE_TIME_FORMAT_TYPE",
1092: "JS_INTL_SEGMENTER_TYPE",
1093: "WASM_EXCEPTION_TYPE",
1094: "WASM_GLOBAL_TYPE",
1095: "WASM_INSTANCE_TYPE",
1096: "WASM_MEMORY_TYPE",
1097: "WASM_MODULE_TYPE",
1098: "WASM_TABLE_TYPE",
1099: "JS_BOUND_FUNCTION_TYPE",
1100: "JS_FUNCTION_TYPE",
1080: "JS_WEAK_CELL_TYPE",
1081: "JS_WEAK_FACTORY_CLEANUP_ITERATOR_TYPE",
1082: "JS_WEAK_FACTORY_TYPE",
1083: "JS_WEAK_MAP_TYPE",
1084: "JS_WEAK_SET_TYPE",
1085: "JS_TYPED_ARRAY_TYPE",
1086: "JS_DATA_VIEW_TYPE",
1087: "JS_INTL_V8_BREAK_ITERATOR_TYPE",
1088: "JS_INTL_COLLATOR_TYPE",
1089: "JS_INTL_DATE_TIME_FORMAT_TYPE",
1090: "JS_INTL_LIST_FORMAT_TYPE",
1091: "JS_INTL_LOCALE_TYPE",
1092: "JS_INTL_NUMBER_FORMAT_TYPE",
1093: "JS_INTL_PLURAL_RULES_TYPE",
1094: "JS_INTL_RELATIVE_TIME_FORMAT_TYPE",
1095: "JS_INTL_SEGMENTER_TYPE",
1096: "WASM_EXCEPTION_TYPE",
1097: "WASM_GLOBAL_TYPE",
1098: "WASM_INSTANCE_TYPE",
1099: "WASM_MEMORY_TYPE",
1100: "WASM_MODULE_TYPE",
1101: "WASM_TABLE_TYPE",
1102: "JS_BOUND_FUNCTION_TYPE",
1103: "JS_FUNCTION_TYPE",
}
# List of known V8 maps.
......@@ -291,41 +294,41 @@ KNOWN_MAPS = {
("RO_SPACE", 0x04761): (171, "Tuple2Map"),
("RO_SPACE", 0x04801): (173, "ArrayBoilerplateDescriptionMap"),
("RO_SPACE", 0x04af1): (161, "InterceptorInfoMap"),
("RO_SPACE", 0x06ea9): (153, "AccessCheckInfoMap"),
("RO_SPACE", 0x06ef9): (154, "AccessorInfoMap"),
("RO_SPACE", 0x06f49): (155, "AccessorPairMap"),
("RO_SPACE", 0x06f99): (156, "AliasedArgumentsEntryMap"),
("RO_SPACE", 0x06fe9): (157, "AllocationMementoMap"),
("RO_SPACE", 0x07039): (158, "AsyncGeneratorRequestMap"),
("RO_SPACE", 0x07089): (159, "DebugInfoMap"),
("RO_SPACE", 0x070d9): (160, "FunctionTemplateInfoMap"),
("RO_SPACE", 0x07129): (162, "InterpreterDataMap"),
("RO_SPACE", 0x07179): (163, "ModuleInfoEntryMap"),
("RO_SPACE", 0x071c9): (164, "ModuleMap"),
("RO_SPACE", 0x07219): (165, "ObjectTemplateInfoMap"),
("RO_SPACE", 0x07269): (166, "PromiseCapabilityMap"),
("RO_SPACE", 0x072b9): (167, "PromiseReactionMap"),
("RO_SPACE", 0x07309): (168, "PrototypeInfoMap"),
("RO_SPACE", 0x07359): (169, "ScriptMap"),
("RO_SPACE", 0x073a9): (170, "StackFrameInfoMap"),
("RO_SPACE", 0x073f9): (172, "Tuple3Map"),
("RO_SPACE", 0x07449): (174, "WasmDebugInfoMap"),
("RO_SPACE", 0x07499): (175, "WasmExportedFunctionDataMap"),
("RO_SPACE", 0x074e9): (176, "CallableTaskMap"),
("RO_SPACE", 0x07539): (177, "CallbackTaskMap"),
("RO_SPACE", 0x07589): (178, "PromiseFulfillReactionJobTaskMap"),
("RO_SPACE", 0x075d9): (179, "PromiseRejectReactionJobTaskMap"),
("RO_SPACE", 0x07629): (180, "PromiseResolveThenableJobTaskMap"),
("RO_SPACE", 0x07679): (181, "MicrotaskQueueMap"),
("RO_SPACE", 0x076c9): (182, "AllocationSiteWithWeakNextMap"),
("RO_SPACE", 0x07719): (182, "AllocationSiteWithoutWeakNextMap"),
("RO_SPACE", 0x07769): (214, "LoadHandler1Map"),
("RO_SPACE", 0x077b9): (214, "LoadHandler2Map"),
("RO_SPACE", 0x07809): (214, "LoadHandler3Map"),
("RO_SPACE", 0x07859): (221, "StoreHandler0Map"),
("RO_SPACE", 0x078a9): (221, "StoreHandler1Map"),
("RO_SPACE", 0x078f9): (221, "StoreHandler2Map"),
("RO_SPACE", 0x07949): (221, "StoreHandler3Map"),
("RO_SPACE", 0x06ef9): (153, "AccessCheckInfoMap"),
("RO_SPACE", 0x06f49): (154, "AccessorInfoMap"),
("RO_SPACE", 0x06f99): (155, "AccessorPairMap"),
("RO_SPACE", 0x06fe9): (156, "AliasedArgumentsEntryMap"),
("RO_SPACE", 0x07039): (157, "AllocationMementoMap"),
("RO_SPACE", 0x07089): (158, "AsyncGeneratorRequestMap"),
("RO_SPACE", 0x070d9): (159, "DebugInfoMap"),
("RO_SPACE", 0x07129): (160, "FunctionTemplateInfoMap"),
("RO_SPACE", 0x07179): (162, "InterpreterDataMap"),
("RO_SPACE", 0x071c9): (163, "ModuleInfoEntryMap"),
("RO_SPACE", 0x07219): (164, "ModuleMap"),
("RO_SPACE", 0x07269): (165, "ObjectTemplateInfoMap"),
("RO_SPACE", 0x072b9): (166, "PromiseCapabilityMap"),
("RO_SPACE", 0x07309): (167, "PromiseReactionMap"),
("RO_SPACE", 0x07359): (168, "PrototypeInfoMap"),
("RO_SPACE", 0x073a9): (169, "ScriptMap"),
("RO_SPACE", 0x073f9): (170, "StackFrameInfoMap"),
("RO_SPACE", 0x07449): (172, "Tuple3Map"),
("RO_SPACE", 0x07499): (174, "WasmDebugInfoMap"),
("RO_SPACE", 0x074e9): (175, "WasmExportedFunctionDataMap"),
("RO_SPACE", 0x07539): (176, "CallableTaskMap"),
("RO_SPACE", 0x07589): (177, "CallbackTaskMap"),
("RO_SPACE", 0x075d9): (178, "PromiseFulfillReactionJobTaskMap"),
("RO_SPACE", 0x07629): (179, "PromiseRejectReactionJobTaskMap"),
("RO_SPACE", 0x07679): (180, "PromiseResolveThenableJobTaskMap"),
("RO_SPACE", 0x076c9): (181, "MicrotaskQueueMap"),
("RO_SPACE", 0x07719): (182, "AllocationSiteWithWeakNextMap"),
("RO_SPACE", 0x07769): (182, "AllocationSiteWithoutWeakNextMap"),
("RO_SPACE", 0x077b9): (214, "LoadHandler1Map"),
("RO_SPACE", 0x07809): (214, "LoadHandler2Map"),
("RO_SPACE", 0x07859): (214, "LoadHandler3Map"),
("RO_SPACE", 0x078a9): (221, "StoreHandler0Map"),
("RO_SPACE", 0x078f9): (221, "StoreHandler1Map"),
("RO_SPACE", 0x07949): (221, "StoreHandler2Map"),
("RO_SPACE", 0x07999): (221, "StoreHandler3Map"),
("MAP_SPACE", 0x02201): (1057, "ExternalMap"),
("MAP_SPACE", 0x02251): (1072, "JSMessageObjectMap"),
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment