From 47f2dfa9bd29e5a2f9f362e49bb0d0711f774169 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 22 Apr 2015 08:03:25 -0700 Subject: [PATCH] Revert of Remove the weak list of views from array buffers (patchset #6 id:100001 of https://codereview.chromium.org/1094863002/) Reason for revert: I'm reverting this while working on the regression fix Original issue's description: > Remove the weak list of views from array buffers > > Instead, views have to check their array buffer for whether > it's neutered or not. > > BUG=v8:3996 > R=hpayer@chromium.org,dslomov@chromium.org,verwaest@chromium.org > LOG=n > > Committed: https://crrev.com/5ae083a05a6743d6cb91585f449539f7846a5d8c > Cr-Commit-Position: refs/heads/master@{#27995} TBR=dslomov@chromium.org,hpayer@chromium.org,verwaest@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:3996 Review URL: https://codereview.chromium.org/1061753008 Cr-Commit-Position: refs/heads/master@{#28014} --- src/accessors.cc | 22 +++ src/elements.cc | 36 ++--- src/elements.h | 3 +- src/factory.cc | 97 ++---------- src/factory.h | 6 - src/heap-snapshot-generator.cc | 5 + src/heap/heap.cc | 30 +++- src/heap/heap.h | 32 ++++ src/heap/objects-visiting-inl.h | 28 +++- src/heap/objects-visiting.cc | 79 ++++++++++ src/hydrogen-instructions.h | 13 +- src/hydrogen.cc | 87 ++++------- src/hydrogen.h | 3 - src/objects-debug.cc | 18 +-- src/objects-inl.h | 98 +++--------- src/objects.cc | 256 ++++++++++++++++--------------- src/objects.h | 98 ++++++------ src/runtime/runtime-typedarray.cc | 62 ++++++++ src/snapshot/serialize.cc | 2 + test/cctest/test-api.cc | 14 +- test/cctest/test-heap-profiler.cc | 3 + test/cctest/test-weaktypedarrays.cc | 295 ++++++++++++++++++++++++++++++++++++ 22 files changed, 838 insertions(+), 449 deletions(-) diff --git a/src/accessors.cc b/src/accessors.cc index df981dc..5ef8bf1 100644 --- a/src/accessors.cc +++ b/src/accessors.cc @@ -78,10 +78,32 @@ bool Accessors::IsJSObjectFieldAccessor(Handle map, Handle name, return CheckForName(name, isolate->factory()->length_string(), JSArray::kLengthOffset, object_offset); + case JS_TYPED_ARRAY_TYPE: + // %TypedArray%.prototype is non-configurable, and so are the following + // named properties on %TypedArray%.prototype, so we can directly inline + // the field-load for typed array maps that still use their + // %TypedArray%.prototype. + if (JSFunction::cast(map->GetConstructor())->prototype() != + map->prototype()) { + return false; + } + return + CheckForName(name, isolate->factory()->length_string(), + JSTypedArray::kLengthOffset, object_offset) || + CheckForName(name, isolate->factory()->byte_length_string(), + JSTypedArray::kByteLengthOffset, object_offset) || + CheckForName(name, isolate->factory()->byte_offset_string(), + JSTypedArray::kByteOffsetOffset, object_offset); case JS_ARRAY_BUFFER_TYPE: return CheckForName(name, isolate->factory()->byte_length_string(), JSArrayBuffer::kByteLengthOffset, object_offset); + case JS_DATA_VIEW_TYPE: + return + CheckForName(name, isolate->factory()->byte_length_string(), + JSDataView::kByteLengthOffset, object_offset) || + CheckForName(name, isolate->factory()->byte_offset_string(), + JSDataView::kByteOffsetOffset, object_offset); default: if (map->instance_type() < FIRST_NONSTRING_TYPE) { return CheckForName(name, isolate->factory()->length_string(), diff --git a/src/elements.cc b/src/elements.cc index ac63b75..a00cd24 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -620,7 +620,7 @@ class ElementsAccessorBase : public ElementsAccessor { Handle obj, uint32_t key, Handle backing_store) { - if (key < ElementsAccessorSubclass::GetCapacityImpl(obj, backing_store)) { + if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { return BackingStore::get(Handle::cast(backing_store), key); } else { return backing_store->GetIsolate()->factory()->the_hole_value(); @@ -638,7 +638,7 @@ class ElementsAccessorBase : public ElementsAccessor { Handle obj, uint32_t key, Handle backing_store) { - if (key >= ElementsAccessorSubclass::GetCapacityImpl(obj, backing_store)) { + if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) { return ABSENT; } return @@ -751,7 +751,7 @@ class ElementsAccessorBase : public ElementsAccessor { // Optimize if 'other' is empty. // We cannot optimize if 'this' is empty, as other may have holes. - uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(holder, from); + uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from); if (len1 == 0) return to; Isolate* isolate = from->GetIsolate(); @@ -817,14 +817,12 @@ class ElementsAccessorBase : public ElementsAccessor { } protected: - static uint32_t GetCapacityImpl(Handle holder, - Handle backing_store) { + static uint32_t GetCapacityImpl(Handle backing_store) { return backing_store->length(); } - uint32_t GetCapacity(Handle holder, - Handle backing_store) final { - return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store); + uint32_t GetCapacity(Handle backing_store) final { + return ElementsAccessorSubclass::GetCapacityImpl(backing_store); } static uint32_t GetKeyForIndexImpl(Handle backing_store, @@ -1262,7 +1260,7 @@ class TypedElementsAccessor Handle obj, uint32_t key, Handle backing_store) { - if (key < AccessorClass::GetCapacityImpl(obj, backing_store)) { + if (key < AccessorClass::GetCapacityImpl(backing_store)) { return BackingStore::get(Handle::cast(backing_store), key); } else { return backing_store->GetIsolate()->factory()->undefined_value(); @@ -1273,8 +1271,9 @@ class TypedElementsAccessor Handle obj, uint32_t key, Handle backing_store) { - return key < AccessorClass::GetCapacityImpl(obj, backing_store) ? NONE - : ABSENT; + return + key < AccessorClass::GetCapacityImpl(backing_store) + ? NONE : ABSENT; } MUST_USE_RESULT static MaybeHandle SetLengthImpl( @@ -1294,16 +1293,10 @@ class TypedElementsAccessor static bool HasElementImpl(Handle holder, uint32_t key, Handle backing_store) { - uint32_t capacity = AccessorClass::GetCapacityImpl(holder, backing_store); + uint32_t capacity = + AccessorClass::GetCapacityImpl(backing_store); return key < capacity; } - - static uint32_t GetCapacityImpl(Handle holder, - Handle backing_store) { - Handle view = Handle::cast(holder); - if (view->WasNeutered()) return 0; - return backing_store->length(); - } }; @@ -1639,13 +1632,12 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase< UNREACHABLE(); } - static uint32_t GetCapacityImpl(Handle holder, - Handle backing_store) { + static uint32_t GetCapacityImpl(Handle backing_store) { Handle parameter_map = Handle::cast(backing_store); Handle arguments( FixedArrayBase::cast(parameter_map->get(1))); return Max(static_cast(parameter_map->length() - 2), - ForArray(arguments)->GetCapacity(holder, arguments)); + ForArray(arguments)->GetCapacity(arguments)); } static uint32_t GetKeyForIndexImpl(Handle dict, diff --git a/src/elements.h b/src/elements.h index e743849..1d80b25 100644 --- a/src/elements.h +++ b/src/elements.h @@ -183,8 +183,7 @@ class ElementsAccessor { protected: friend class SloppyArgumentsElementsAccessor; - virtual uint32_t GetCapacity(Handle holder, - Handle backing_store) = 0; + virtual uint32_t GetCapacity(Handle backing_store) = 0; // Element handlers distinguish between indexes and keys when they manipulate // elements. Indexes refer to elements in terms of their location in the diff --git a/src/factory.cc b/src/factory.cc index d2a8d79..eda7cdd 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -1825,38 +1825,9 @@ size_t GetExternalArrayElementSize(ExternalArrayType type) { case kExternal##Type##Array: \ return size; TYPED_ARRAYS(TYPED_ARRAY_CASE) - default: - UNREACHABLE(); - return 0; - } -#undef TYPED_ARRAY_CASE -} - - -size_t GetFixedTypedArraysElementSize(ElementsKind kind) { - switch (kind) { -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ - case TYPE##_ELEMENTS: \ - return size; - TYPED_ARRAYS(TYPED_ARRAY_CASE) - default: - UNREACHABLE(); - return 0; - } -#undef TYPED_ARRAY_CASE -} - - -ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { - switch (kind) { -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ - case TYPE##_ELEMENTS: \ - return kExternal##Type##Array; - TYPED_ARRAYS(TYPED_ARRAY_CASE) - default: - UNREACHABLE(); - return kExternalInt8Array; } + UNREACHABLE(); + return 0; #undef TYPED_ARRAY_CASE } @@ -1878,23 +1849,6 @@ JSFunction* GetTypedArrayFun(ExternalArrayType type, Isolate* isolate) { } -JSFunction* GetTypedArrayFun(ElementsKind elements_kind, Isolate* isolate) { - Context* native_context = isolate->context()->native_context(); - switch (elements_kind) { -#define TYPED_ARRAY_FUN(Type, type, TYPE, ctype, size) \ - case TYPE##_ELEMENTS: \ - return native_context->type##_array_fun(); - - TYPED_ARRAYS(TYPED_ARRAY_FUN) -#undef TYPED_ARRAY_FUN - - default: - UNREACHABLE(); - return NULL; - } -} - - void SetupArrayBufferView(i::Isolate* isolate, i::Handle obj, i::Handle buffer, @@ -1904,6 +1858,15 @@ void SetupArrayBufferView(i::Isolate* isolate, obj->set_buffer(*buffer); + Heap* heap = isolate->heap(); + if (heap->InNewSpace(*obj)) { + obj->set_weak_next(heap->new_array_buffer_views_list()); + heap->set_new_array_buffer_views_list(*obj); + } else { + obj->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*obj); + } + i::Handle byte_offset_object = isolate->factory()->NewNumberFromSize(byte_offset); obj->set_byte_offset(*byte_offset_object); @@ -1927,16 +1890,6 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type) { } -Handle Factory::NewJSTypedArray(ElementsKind elements_kind) { - Handle typed_array_fun_handle( - GetTypedArrayFun(elements_kind, isolate())); - - CALL_HEAP_FUNCTION( - isolate(), isolate()->heap()->AllocateJSObject(*typed_array_fun_handle), - JSTypedArray); -} - - Handle Factory::NewJSTypedArray(ExternalArrayType type, Handle buffer, size_t byte_offset, @@ -1965,34 +1918,6 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type, } -Handle Factory::NewJSTypedArray(ElementsKind elements_kind, - size_t number_of_elements) { - Handle obj = NewJSTypedArray(elements_kind); - - size_t element_size = GetFixedTypedArraysElementSize(elements_kind); - ExternalArrayType array_type = GetArrayTypeFromElementsKind(elements_kind); - - CHECK(number_of_elements <= - (std::numeric_limits::max() / element_size)); - CHECK(number_of_elements <= static_cast(Smi::kMaxValue)); - size_t byte_length = number_of_elements * element_size; - - obj->set_byte_offset(Smi::FromInt(0)); - i::Handle byte_length_object = - isolate()->factory()->NewNumberFromSize(byte_length); - obj->set_byte_length(*byte_length_object); - Handle length_object = NewNumberFromSize(number_of_elements); - obj->set_length(*length_object); - - obj->set_buffer(Smi::FromInt(0)); - Handle elements = - isolate()->factory()->NewFixedTypedArray( - static_cast(number_of_elements), array_type); - obj->set_elements(*elements); - return obj; -} - - Handle Factory::NewJSDataView(Handle buffer, size_t byte_offset, size_t byte_length) { diff --git a/src/factory.h b/src/factory.h index 72991d9..87ec2e6 100644 --- a/src/factory.h +++ b/src/factory.h @@ -448,17 +448,11 @@ class Factory final { Handle NewJSTypedArray(ExternalArrayType type); - Handle NewJSTypedArray(ElementsKind elements_kind); - // Creates a new JSTypedArray with the specified buffer. Handle NewJSTypedArray(ExternalArrayType type, Handle buffer, size_t byte_offset, size_t length); - // Creates a new on-heap JSTypedArray. - Handle NewJSTypedArray(ElementsKind elements_kind, - size_t number_of_elements); - Handle NewJSDataView(); Handle NewJSDataView(Handle buffer, size_t byte_offset, size_t byte_length); diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index bae364c..92149a2 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -1175,6 +1175,8 @@ void V8HeapExplorer::ExtractJSObjectReferences( JSArrayBufferView* view = JSArrayBufferView::cast(obj); SetInternalReference(view, entry, "buffer", view->buffer(), JSArrayBufferView::kBufferOffset); + SetWeakReference(view, entry, "weak_next", view->weak_next(), + JSArrayBufferView::kWeakNextOffset); } TagObject(js_obj->properties(), "(object properties)"); SetInternalReference(obj, entry, @@ -1568,6 +1570,9 @@ void V8HeapExplorer::ExtractJSArrayBufferReferences( int entry, JSArrayBuffer* buffer) { SetWeakReference(buffer, entry, "weak_next", buffer->weak_next(), JSArrayBuffer::kWeakNextOffset); + SetWeakReference(buffer, entry, + "weak_first_view", buffer->weak_first_view(), + JSArrayBuffer::kWeakFirstViewOffset); // Setup a reference to a native memory backing_store object. if (!buffer->backing_store()) return; diff --git a/src/heap/heap.cc b/src/heap/heap.cc index 84d383b..ecf8be1 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -141,7 +141,9 @@ Heap::Heap() chunks_queued_for_free_(NULL), gc_callbacks_depth_(0), deserialization_complete_(false), - concurrent_sweeping_enabled_(false) { + concurrent_sweeping_enabled_(false), + migration_failure_(false), + previous_migration_failure_(false) { // Allow build-time customization of the max semispace size. Building // V8 with snapshots and a non-default max semispace size is much // easier if you can define it as part of the build environment. @@ -703,6 +705,13 @@ void Heap::GarbageCollectionEpilogue() { // Remember the last top pointer so that we can later find out // whether we allocated in new space since the last GC. new_space_top_after_last_gc_ = new_space()->top(); + + if (migration_failure_) { + set_previous_migration_failure(true); + } else { + set_previous_migration_failure(false); + } + set_migration_failure(false); } @@ -1677,6 +1686,7 @@ void Heap::UpdateReferencesInExternalStringTable( void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) { ProcessArrayBuffers(retainer, false); + ProcessNewArrayBufferViews(retainer); ProcessNativeContexts(retainer); ProcessAllocationSites(retainer); } @@ -1684,6 +1694,7 @@ void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) { void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) { ProcessArrayBuffers(retainer, true); + ProcessNewArrayBufferViews(retainer); ProcessNativeContexts(retainer); } @@ -1710,6 +1721,7 @@ void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer, Object* undefined = undefined_value(); Object* next = array_buffers_list(); bool old_objects_recorded = false; + if (migration_failure()) return; while (next != undefined) { if (!old_objects_recorded) { old_objects_recorded = !InNewSpace(next); @@ -1720,6 +1732,20 @@ void Heap::ProcessArrayBuffers(WeakObjectRetainer* retainer, } +void Heap::ProcessNewArrayBufferViews(WeakObjectRetainer* retainer) { + // Retain the list of new space views. + Object* typed_array_obj = VisitWeakList( + this, new_array_buffer_views_list_, retainer, false, NULL); + set_new_array_buffer_views_list(typed_array_obj); + + // Some objects in the list may be in old space now. Find them + // and move them to the corresponding array buffer. + Object* view = VisitNewArrayBufferViewsWeakList( + this, new_array_buffer_views_list_, retainer); + set_new_array_buffer_views_list(view); +} + + void Heap::TearDownArrayBuffers() { Object* undefined = undefined_value(); for (Object* o = array_buffers_list(); o != undefined;) { @@ -2151,6 +2177,7 @@ class ScavengingVisitor : public StaticVisitorBase { if (SemiSpaceCopyObject(map, slot, object, object_size)) { return; } + heap->set_migration_failure(true); } if (PromoteObject(map, slot, object, @@ -5375,6 +5402,7 @@ bool Heap::CreateHeapObjects() { set_native_contexts_list(undefined_value()); set_array_buffers_list(undefined_value()); set_last_array_buffer_in_list(undefined_value()); + set_new_array_buffer_views_list(undefined_value()); set_allocation_sites_list(undefined_value()); return true; } diff --git a/src/heap/heap.h b/src/heap/heap.h index 7573c67..fcec005 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -882,6 +882,13 @@ class Heap { return last_array_buffer_in_list_; } + void set_new_array_buffer_views_list(Object* object) { + new_array_buffer_views_list_ = object; + } + Object* new_array_buffer_views_list() const { + return new_array_buffer_views_list_; + } + void set_allocation_sites_list(Object* object) { allocation_sites_list_ = object; } @@ -1488,6 +1495,18 @@ class Heap { bool deserialization_complete() const { return deserialization_complete_; } + bool migration_failure() const { return migration_failure_; } + void set_migration_failure(bool migration_failure) { + migration_failure_ = migration_failure; + } + + bool previous_migration_failure() const { + return previous_migration_failure_; + } + void set_previous_migration_failure(bool previous_migration_failure) { + previous_migration_failure_ = previous_migration_failure; + } + protected: // Methods made available to tests. @@ -1662,6 +1681,11 @@ class Heap { Object* last_array_buffer_in_list_; Object* allocation_sites_list_; + // This is a global list of array buffer views in new space. When the views + // get promoted, they are removed form the list and added to the corresponding + // array buffer. + Object* new_array_buffer_views_list_; + // List of encountered weak collections (JSWeakMap and JSWeakSet) during // marking. It is initialized during marking, destroyed after marking and // contains Smi(0) while marking is not active. @@ -1992,6 +2016,7 @@ class Heap { void ProcessNativeContexts(WeakObjectRetainer* retainer); void ProcessArrayBuffers(WeakObjectRetainer* retainer, bool stop_after_young); + void ProcessNewArrayBufferViews(WeakObjectRetainer* retainer); void ProcessAllocationSites(WeakObjectRetainer* retainer); // Deopts all code that contains allocation instruction which are tenured or @@ -2151,6 +2176,13 @@ class Heap { bool concurrent_sweeping_enabled_; + // A migration failure indicates that a semi-space copy of an object during + // a scavenge failed and the object got promoted instead. + bool migration_failure_; + + // A migration failure happened in the previous scavenge. + bool previous_migration_failure_; + friend class AlwaysAllocateScope; friend class Deserializer; friend class Factory; diff --git a/src/heap/objects-visiting-inl.h b/src/heap/objects-visiting-inl.h index 39803b1..06fa10e 100644 --- a/src/heap/objects-visiting-inl.h +++ b/src/heap/objects-visiting-inl.h @@ -80,12 +80,14 @@ int StaticNewSpaceVisitor::VisitJSArrayBuffer( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); + STATIC_ASSERT(JSArrayBuffer::kWeakFirstViewOffset == + JSArrayBuffer::kWeakNextOffset + kPointerSize); VisitPointers(heap, HeapObject::RawField( object, JSArrayBuffer::BodyDescriptor::kStartOffset), HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset)); VisitPointers( - heap, HeapObject::RawField(object, - JSArrayBuffer::kWeakNextOffset + kPointerSize), + heap, HeapObject::RawField( + object, JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize), HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields)); return JSArrayBuffer::kSizeWithInternalFields; } @@ -97,6 +99,10 @@ int StaticNewSpaceVisitor::VisitJSTypedArray( VisitPointers( map->GetHeap(), HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset), + HeapObject::RawField(object, JSTypedArray::kWeakNextOffset)); + VisitPointers( + map->GetHeap(), HeapObject::RawField( + object, JSTypedArray::kWeakNextOffset + kPointerSize), HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields)); return JSTypedArray::kSizeWithInternalFields; } @@ -108,6 +114,10 @@ int StaticNewSpaceVisitor::VisitJSDataView(Map* map, VisitPointers( map->GetHeap(), HeapObject::RawField(object, JSDataView::BodyDescriptor::kStartOffset), + HeapObject::RawField(object, JSDataView::kWeakNextOffset)); + VisitPointers( + map->GetHeap(), + HeapObject::RawField(object, JSDataView::kWeakNextOffset + kPointerSize), HeapObject::RawField(object, JSDataView::kSizeWithInternalFields)); return JSDataView::kSizeWithInternalFields; } @@ -530,13 +540,15 @@ void StaticMarkingVisitor::VisitJSArrayBuffer( Map* map, HeapObject* object) { Heap* heap = map->GetHeap(); + STATIC_ASSERT(JSArrayBuffer::kWeakFirstViewOffset == + JSArrayBuffer::kWeakNextOffset + kPointerSize); StaticVisitor::VisitPointers( heap, HeapObject::RawField(object, JSArrayBuffer::BodyDescriptor::kStartOffset), HeapObject::RawField(object, JSArrayBuffer::kWeakNextOffset)); StaticVisitor::VisitPointers( - heap, HeapObject::RawField(object, - JSArrayBuffer::kWeakNextOffset + kPointerSize), + heap, HeapObject::RawField( + object, JSArrayBuffer::kWeakNextOffset + 2 * kPointerSize), HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields)); } @@ -547,6 +559,10 @@ void StaticMarkingVisitor::VisitJSTypedArray( StaticVisitor::VisitPointers( map->GetHeap(), HeapObject::RawField(object, JSTypedArray::BodyDescriptor::kStartOffset), + HeapObject::RawField(object, JSTypedArray::kWeakNextOffset)); + StaticVisitor::VisitPointers( + map->GetHeap(), HeapObject::RawField( + object, JSTypedArray::kWeakNextOffset + kPointerSize), HeapObject::RawField(object, JSTypedArray::kSizeWithInternalFields)); } @@ -557,6 +573,10 @@ void StaticMarkingVisitor::VisitJSDataView(Map* map, StaticVisitor::VisitPointers( map->GetHeap(), HeapObject::RawField(object, JSDataView::BodyDescriptor::kStartOffset), + HeapObject::RawField(object, JSDataView::kWeakNextOffset)); + StaticVisitor::VisitPointers( + map->GetHeap(), + HeapObject::RawField(object, JSDataView::kWeakNextOffset + kPointerSize), HeapObject::RawField(object, JSDataView::kSizeWithInternalFields)); } diff --git a/src/heap/objects-visiting.cc b/src/heap/objects-visiting.cc index 8c2f198..cf71fb2 100644 --- a/src/heap/objects-visiting.cc +++ b/src/heap/objects-visiting.cc @@ -243,6 +243,56 @@ Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer, } +Object* VisitNewArrayBufferViewsWeakList(Heap* heap, Object* list, + WeakObjectRetainer* retainer) { + Object* undefined = heap->undefined_value(); + Object* previous = undefined; + Object* head = undefined; + Object* next; + MarkCompactCollector* collector = heap->mark_compact_collector(); + bool record_slots = MustRecordSlots(heap); + + for (Object* o = list; o != undefined;) { + JSArrayBufferView* view = JSArrayBufferView::cast(o); + next = view->weak_next(); + if (!heap->InNewSpace(view)) { + if (previous != undefined) { + // We are in the middle of the list, skip the old space element. + JSArrayBufferView* previous_view = JSArrayBufferView::cast(previous); + previous_view->set_weak_next(next); + if (record_slots) { + Object** next_slot = HeapObject::RawField( + previous_view, JSArrayBufferView::kWeakNextOffset); + collector->RecordSlot(next_slot, next_slot, next); + } + } + JSArrayBuffer* buffer = JSArrayBuffer::cast(view->buffer()); + view->set_weak_next(buffer->weak_first_view()); + if (record_slots) { + Object** next_slot = + HeapObject::RawField(view, JSArrayBufferView::kWeakNextOffset); + collector->RecordSlot(next_slot, next_slot, buffer->weak_first_view()); + } + buffer->set_weak_first_view(view); + if (record_slots) { + Object** slot = + HeapObject::RawField(buffer, JSArrayBuffer::kWeakFirstViewOffset); + heap->mark_compact_collector()->RecordSlot(slot, slot, view); + } + } else { + // We found a valid new space view, remember it. + previous = view; + if (head == undefined) { + // We are at the list head. + head = view; + } + } + o = next; + } + return head; +} + + template static void ClearWeakList(Heap* heap, Object* list) { Object* undefined = heap->undefined_value(); @@ -345,6 +395,22 @@ struct WeakListVisitor { template <> +struct WeakListVisitor { + static void SetWeakNext(JSArrayBufferView* obj, Object* next) { + obj->set_weak_next(next); + } + + static Object* WeakNext(JSArrayBufferView* obj) { return obj->weak_next(); } + + static int WeakNextOffset() { return JSArrayBufferView::kWeakNextOffset; } + + static void VisitLiveObject(Heap*, JSArrayBufferView*, WeakObjectRetainer*) {} + + static void VisitPhantomObject(Heap*, JSArrayBufferView*) {} +}; + + +template <> struct WeakListVisitor { static void SetWeakNext(JSArrayBuffer* obj, Object* next) { obj->set_weak_next(next); @@ -356,6 +422,14 @@ struct WeakListVisitor { static void VisitLiveObject(Heap* heap, JSArrayBuffer* array_buffer, WeakObjectRetainer* retainer) { + Object* typed_array_obj = VisitWeakList( + heap, array_buffer->weak_first_view(), retainer, false, NULL); + array_buffer->set_weak_first_view(typed_array_obj); + if (typed_array_obj != heap->undefined_value() && MustRecordSlots(heap)) { + Object** slot = HeapObject::RawField(array_buffer, + JSArrayBuffer::kWeakFirstViewOffset); + heap->mark_compact_collector()->RecordSlot(slot, slot, typed_array_obj); + } } static void VisitPhantomObject(Heap* heap, JSArrayBuffer* phantom) { @@ -391,6 +465,11 @@ template Object* VisitWeakList(Heap* heap, Object* list, bool stop_after_young, Object** list_tail); +template Object* VisitWeakList(Heap* heap, Object* list, + WeakObjectRetainer* retainer, + bool stop_after_young, + Object** list_tail); + template Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer, bool stop_after_young, diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 0e84a6e..0434a13 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -6097,14 +6097,19 @@ class HObjectAccess final { JSArrayBuffer::kByteLengthOffset, Representation::Tagged()); } - static HObjectAccess ForJSArrayBufferFlag() { + static HObjectAccess ForExternalArrayExternalPointer() { return HObjectAccess::ForObservableJSObjectOffset( - JSArrayBuffer::kFlagOffset, Representation::Smi()); + ExternalArray::kExternalPointerOffset, Representation::External()); } - static HObjectAccess ForExternalArrayExternalPointer() { + static HObjectAccess ForJSArrayBufferViewWeakNext() { return HObjectAccess::ForObservableJSObjectOffset( - ExternalArray::kExternalPointerOffset, Representation::External()); + JSArrayBufferView::kWeakNextOffset); + } + + static HObjectAccess ForJSArrayBufferWeakFirstView() { + return HObjectAccess::ForObservableJSObjectOffset( + JSArrayBuffer::kWeakFirstViewOffset); } static HObjectAccess ForJSArrayBufferViewBuffer() { diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 0faa4af..1e28cea 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -2427,22 +2427,6 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( IsFixedTypedArrayElementsKind(elements_kind)) { HValue* backing_store; if (IsExternalArrayElementsKind(elements_kind)) { - NoObservableSideEffectsScope no_effects(this); - HInstruction* buffer = Add( - checked_object, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer()); - HInstruction* flags = Add( - buffer, nullptr, HObjectAccess::ForJSArrayBufferFlag()); - HValue* was_neutered_mask = - Add(1 << JSArrayBuffer::kWasNeuteredBit); - HValue* was_neutered_test = - AddUncasted(Token::BIT_AND, flags, was_neutered_mask); - - IfBuilder if_was_neutered(this); - if_was_neutered.If( - was_neutered_test, graph()->GetConstant0(), Token::NE); - if_was_neutered.ThenDeopt(Deoptimizer::kOutOfBounds); - if_was_neutered.End(); - backing_store = Add( elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer()); } else { @@ -9633,11 +9617,20 @@ void HGraphBuilder::BuildArrayBufferViewInitialization( Add( obj, HObjectAccess::ForJSArrayBufferViewBuffer(), buffer); + HObjectAccess weak_first_view_access = + HObjectAccess::ForJSArrayBufferWeakFirstView(); + Add( + obj, HObjectAccess::ForJSArrayBufferViewWeakNext(), + Add(buffer, nullptr, weak_first_view_access)); + Add(buffer, weak_first_view_access, obj); } else { Add( obj, HObjectAccess::ForJSArrayBufferViewBuffer(), Add(static_cast(0))); + Add(obj, + HObjectAccess::ForJSArrayBufferViewWeakNext(), + graph()->GetConstantUndefined()); } } @@ -9931,62 +9924,36 @@ void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength( } -void HOptimizedGraphBuilder::GenerateArrayBufferViewIndirectAccessor( - CallRuntime* expr, HObjectAccess access) { - NoObservableSideEffectsScope scope(this); - DCHECK(expr->arguments()->length() == 1); - CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); - HValue* view = Pop(); - HInstruction* buffer = Add( - view, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer()); - HInstruction* field = Add(view, nullptr, access); - - IfBuilder if_has_buffer(this); - if_has_buffer.IfNot(buffer); - if_has_buffer.Then(); - { - HInstruction* flags = Add( - buffer, nullptr, HObjectAccess::ForJSArrayBufferFlag()); - HValue* was_neutered_mask = - Add(1 << JSArrayBuffer::kWasNeuteredBit); - HValue* was_neutered_test = - AddUncasted(Token::BIT_AND, flags, was_neutered_mask); - - IfBuilder if_was_neutered(this); - if_was_neutered.If( - was_neutered_test, graph()->GetConstant0(), Token::NE); - if_was_neutered.Then(); - Push(graph()->GetConstant0()); - if_was_neutered.Else(); - Push(field); - if_was_neutered.End(); - } - if_has_buffer.Else(); - Push(field); - if_has_buffer.End(); - - return ast_context()->ReturnValue(Pop()); -} - - void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength( CallRuntime* expr) { - return GenerateArrayBufferViewIndirectAccessor( - expr, HObjectAccess::ForJSArrayBufferViewByteLength()); + DCHECK(expr->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); + HValue* buffer = Pop(); + HInstruction* result = New( + buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength()); + return ast_context()->ReturnInstruction(result, expr->id()); } void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset( CallRuntime* expr) { - return GenerateArrayBufferViewIndirectAccessor( - expr, HObjectAccess::ForJSArrayBufferViewByteOffset()); + DCHECK(expr->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); + HValue* buffer = Pop(); + HInstruction* result = New( + buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset()); + return ast_context()->ReturnInstruction(result, expr->id()); } void HOptimizedGraphBuilder::GenerateTypedArrayGetLength( CallRuntime* expr) { - return GenerateArrayBufferViewIndirectAccessor( - expr, HObjectAccess::ForJSTypedArrayLength()); + DCHECK(expr->arguments()->length() == 1); + CHECK_ALIVE(VisitForValue(expr->arguments()->at(0))); + HValue* buffer = Pop(); + HInstruction* result = New( + buffer, nullptr, HObjectAccess::ForJSTypedArrayLength()); + return ast_context()->ReturnInstruction(result, expr->id()); } diff --git a/src/hydrogen.h b/src/hydrogen.h index b11d856..8617d38 100644 --- a/src/hydrogen.h +++ b/src/hydrogen.h @@ -2244,9 +2244,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { FOR_EACH_HYDROGEN_INTRINSIC(GENERATOR_DECLARATION) #undef GENERATOR_DECLARATION - void GenerateArrayBufferViewIndirectAccessor(CallRuntime* call, - HObjectAccess access); - void VisitDelete(UnaryOperation* expr); void VisitVoid(UnaryOperation* expr); void VisitTypeof(UnaryOperation* expr); diff --git a/src/objects-debug.cc b/src/objects-debug.cc index eebf00b..3495ad6 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -841,22 +841,22 @@ void JSArrayBufferView::JSArrayBufferViewVerify() { CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined() || buffer() == Smi::FromInt(0)); - VerifyPointer(raw_byte_offset()); - CHECK(raw_byte_offset()->IsSmi() || raw_byte_offset()->IsHeapNumber() || - raw_byte_offset()->IsUndefined()); + VerifyPointer(byte_offset()); + CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber() + || byte_offset()->IsUndefined()); - VerifyPointer(raw_byte_length()); - CHECK(raw_byte_length()->IsSmi() || raw_byte_length()->IsHeapNumber() || - raw_byte_length()->IsUndefined()); + VerifyPointer(byte_length()); + CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber() + || byte_length()->IsUndefined()); } void JSTypedArray::JSTypedArrayVerify() { CHECK(IsJSTypedArray()); JSArrayBufferViewVerify(); - VerifyPointer(raw_length()); - CHECK(raw_length()->IsSmi() || raw_length()->IsHeapNumber() || - raw_length()->IsUndefined()); + VerifyPointer(length()); + CHECK(length()->IsSmi() || length()->IsHeapNumber() + || length()->IsUndefined()); VerifyPointer(elements()); } diff --git a/src/objects-inl.h b/src/objects-inl.h index 2e77f92..e9db3c5 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -4377,25 +4377,23 @@ Handle FixedTypedArray::get( template Handle FixedTypedArray::SetValue( - Handle holder, Handle > array, - uint32_t index, Handle value) { + Handle > array, + uint32_t index, + Handle value) { ElementType cast_value = Traits::defaultValue(); - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(array->length())) { - if (value->IsSmi()) { - int int_value = Handle::cast(value)->value(); - cast_value = from_int(int_value); - } else if (value->IsHeapNumber()) { - double double_value = Handle::cast(value)->value(); - cast_value = from_double(double_value); - } else { - // Clamp undefined to the default value. All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); - } - array->set(index, cast_value); + if (index < static_cast(array->length())) { + if (value->IsSmi()) { + int int_value = Handle::cast(value)->value(); + cast_value = from_int(int_value); + } else if (value->IsHeapNumber()) { + double double_value = Handle::cast(value)->value(); + cast_value = from_double(double_value); + } else { + // Clamp undefined to the default value. All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + array->set(index, cast_value); } return Traits::ToHandle(array->GetIsolate(), cast_value); } @@ -6457,71 +6455,15 @@ void JSArrayBuffer::set_is_neuterable(bool value) { } -bool JSArrayBuffer::was_neutered() { - return BooleanBit::get(flag(), kWasNeuteredBit); -} - - -void JSArrayBuffer::set_was_neutered(bool value) { - set_flag(BooleanBit::set(flag(), kWasNeuteredBit, value)); -} - - ACCESSORS(JSArrayBuffer, weak_next, Object, kWeakNextOffset) - - -Object* JSArrayBufferView::byte_offset() const { - if (WasNeutered()) return Smi::FromInt(0); - return Object::cast(READ_FIELD(this, kByteOffsetOffset)); -} - - -void JSArrayBufferView::set_byte_offset(Object* value, WriteBarrierMode mode) { - WRITE_FIELD(this, kByteOffsetOffset, value); - CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kByteOffsetOffset, value, mode); -} - - -Object* JSArrayBufferView::byte_length() const { - if (WasNeutered()) return Smi::FromInt(0); - return Object::cast(READ_FIELD(this, kByteLengthOffset)); -} - - -void JSArrayBufferView::set_byte_length(Object* value, WriteBarrierMode mode) { - WRITE_FIELD(this, kByteLengthOffset, value); - CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kByteLengthOffset, value, mode); -} +ACCESSORS(JSArrayBuffer, weak_first_view, Object, kWeakFirstViewOffset) ACCESSORS(JSArrayBufferView, buffer, Object, kBufferOffset) -#ifdef VERIFY_HEAP -ACCESSORS(JSArrayBufferView, raw_byte_offset, Object, kByteOffsetOffset) -ACCESSORS(JSArrayBufferView, raw_byte_length, Object, kByteLengthOffset) -#endif - - -bool JSArrayBufferView::WasNeutered() const { - return !buffer()->IsSmi() && JSArrayBuffer::cast(buffer())->was_neutered(); -} - - -Object* JSTypedArray::length() const { - if (WasNeutered()) return Smi::FromInt(0); - return Object::cast(READ_FIELD(this, kLengthOffset)); -} - - -void JSTypedArray::set_length(Object* value, WriteBarrierMode mode) { - WRITE_FIELD(this, kLengthOffset, value); - CONDITIONAL_WRITE_BARRIER(GetHeap(), this, kLengthOffset, value, mode); -} - - -#ifdef VERIFY_HEAP -ACCESSORS(JSTypedArray, raw_length, Object, kLengthOffset) -#endif - +ACCESSORS(JSArrayBufferView, byte_offset, Object, kByteOffsetOffset) +ACCESSORS(JSArrayBufferView, byte_length, Object, kByteLengthOffset) +ACCESSORS(JSArrayBufferView, weak_next, Object, kWeakNextOffset) +ACCESSORS(JSTypedArray, length, Object, kLengthOffset) ACCESSORS(JSRegExp, data, Object, kDataOffset) diff --git a/src/objects.cc b/src/objects.cc index 76e97b1..fa158fa 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -13317,17 +13317,17 @@ MaybeHandle JSObject::SetElementWithoutInterceptor( return SetFastDoubleElement(object, index, value, language_mode, check_prototype); -#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ - case EXTERNAL_##TYPE##_ELEMENTS: { \ - Handle array( \ - External##Type##Array::cast(object->elements())); \ - return External##Type##Array::SetValue(object, array, index, value); \ - } \ - case TYPE##_ELEMENTS: { \ - Handle array( \ - Fixed##Type##Array::cast(object->elements())); \ - return Fixed##Type##Array::SetValue(object, array, index, value); \ - } +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: { \ + Handle array( \ + External##Type##Array::cast(object->elements())); \ + return External##Type##Array::SetValue(array, index, value); \ + } \ + case TYPE##_ELEMENTS: { \ + Handle array( \ + Fixed##Type##Array::cast(object->elements())); \ + return Fixed##Type##Array::SetValue(array, index, value); \ + } TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -15193,183 +15193,168 @@ size_t JSTypedArray::element_size() { Handle ExternalUint8ClampedArray::SetValue( - Handle holder, Handle array, - uint32_t index, Handle value) { + Handle array, + uint32_t index, + Handle value) { uint8_t clamped_value = 0; - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(array->length())) { - if (value->IsSmi()) { - int int_value = Handle::cast(value)->value(); - if (int_value < 0) { - clamped_value = 0; - } else if (int_value > 255) { - clamped_value = 255; - } else { - clamped_value = static_cast(int_value); - } - } else if (value->IsHeapNumber()) { - double double_value = Handle::cast(value)->value(); - if (!(double_value > 0)) { - // NaN and less than zero clamp to zero. - clamped_value = 0; - } else if (double_value > 255) { - // Greater than 255 clamp to 255. - clamped_value = 255; - } else { - // Other doubles are rounded to the nearest integer. - clamped_value = static_cast(lrint(double_value)); - } + if (index < static_cast(array->length())) { + if (value->IsSmi()) { + int int_value = Handle::cast(value)->value(); + if (int_value < 0) { + clamped_value = 0; + } else if (int_value > 255) { + clamped_value = 255; } else { - // Clamp undefined to zero (default). All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); + clamped_value = static_cast(int_value); } - array->set(index, clamped_value); + } else if (value->IsHeapNumber()) { + double double_value = Handle::cast(value)->value(); + if (!(double_value > 0)) { + // NaN and less than zero clamp to zero. + clamped_value = 0; + } else if (double_value > 255) { + // Greater than 255 clamp to 255. + clamped_value = 255; + } else { + // Other doubles are rounded to the nearest integer. + clamped_value = static_cast(lrint(double_value)); + } + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + array->set(index, clamped_value); } return handle(Smi::FromInt(clamped_value), array->GetIsolate()); } -template +template static Handle ExternalArrayIntSetter( - Isolate* isolate, Handle holder, - Handle receiver, uint32_t index, Handle value) { + Isolate* isolate, + Handle receiver, + uint32_t index, + Handle value) { ValueType cast_value = 0; - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(receiver->length())) { - if (value->IsSmi()) { - int int_value = Handle::cast(value)->value(); - cast_value = static_cast(int_value); - } else if (value->IsHeapNumber()) { - double double_value = Handle::cast(value)->value(); - cast_value = static_cast(DoubleToInt32(double_value)); - } else { - // Clamp undefined to zero (default). All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); - } - receiver->set(index, cast_value); + if (index < static_cast(receiver->length())) { + if (value->IsSmi()) { + int int_value = Handle::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = Handle::cast(value)->value(); + cast_value = static_cast(DoubleToInt32(double_value)); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + receiver->set(index, cast_value); } return isolate->factory()->NewNumberFromInt(cast_value); } -Handle ExternalInt8Array::SetValue(Handle holder, - Handle array, +Handle ExternalInt8Array::SetValue(Handle array, uint32_t index, Handle value) { return ExternalArrayIntSetter( - array->GetIsolate(), holder, array, index, value); + array->GetIsolate(), array, index, value); } -Handle ExternalUint8Array::SetValue(Handle holder, - Handle array, +Handle ExternalUint8Array::SetValue(Handle array, uint32_t index, Handle value) { return ExternalArrayIntSetter( - array->GetIsolate(), holder, array, index, value); + array->GetIsolate(), array, index, value); } -Handle ExternalInt16Array::SetValue(Handle holder, - Handle array, +Handle ExternalInt16Array::SetValue(Handle array, uint32_t index, Handle value) { return ExternalArrayIntSetter( - array->GetIsolate(), holder, array, index, value); + array->GetIsolate(), array, index, value); } -Handle ExternalUint16Array::SetValue(Handle holder, - Handle array, +Handle ExternalUint16Array::SetValue(Handle array, uint32_t index, Handle value) { return ExternalArrayIntSetter( - array->GetIsolate(), holder, array, index, value); + array->GetIsolate(), array, index, value); } -Handle ExternalInt32Array::SetValue(Handle holder, - Handle array, +Handle ExternalInt32Array::SetValue(Handle array, uint32_t index, Handle value) { return ExternalArrayIntSetter( - array->GetIsolate(), holder, array, index, value); + array->GetIsolate(), array, index, value); } -Handle ExternalUint32Array::SetValue(Handle holder, - Handle array, - uint32_t index, - Handle value) { +Handle ExternalUint32Array::SetValue( + Handle array, + uint32_t index, + Handle value) { uint32_t cast_value = 0; - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(array->length())) { - if (value->IsSmi()) { - int int_value = Handle::cast(value)->value(); - cast_value = static_cast(int_value); - } else if (value->IsHeapNumber()) { - double double_value = Handle::cast(value)->value(); - cast_value = static_cast(DoubleToUint32(double_value)); - } else { - // Clamp undefined to zero (default). All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); - } - array->set(index, cast_value); + if (index < static_cast(array->length())) { + if (value->IsSmi()) { + int int_value = Handle::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = Handle::cast(value)->value(); + cast_value = static_cast(DoubleToUint32(double_value)); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + array->set(index, cast_value); } return array->GetIsolate()->factory()->NewNumberFromUint(cast_value); } Handle ExternalFloat32Array::SetValue( - Handle holder, Handle array, uint32_t index, + Handle array, + uint32_t index, Handle value) { float cast_value = std::numeric_limits::quiet_NaN(); - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(array->length())) { - if (value->IsSmi()) { - int int_value = Handle::cast(value)->value(); - cast_value = static_cast(int_value); - } else if (value->IsHeapNumber()) { - double double_value = Handle::cast(value)->value(); - cast_value = static_cast(double_value); - } else { - // Clamp undefined to NaN (default). All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); - } - array->set(index, cast_value); + if (index < static_cast(array->length())) { + if (value->IsSmi()) { + int int_value = Handle::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = Handle::cast(value)->value(); + cast_value = static_cast(double_value); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + array->set(index, cast_value); } return array->GetIsolate()->factory()->NewNumber(cast_value); } Handle ExternalFloat64Array::SetValue( - Handle holder, Handle array, uint32_t index, + Handle array, + uint32_t index, Handle value) { double double_value = std::numeric_limits::quiet_NaN(); - Handle view = Handle::cast(holder); - if (!view->WasNeutered()) { - if (index < static_cast(array->length())) { - if (value->IsNumber()) { - double_value = value->Number(); - } else { - // Clamp undefined to NaN (default). All other types have been - // converted to a number type further up in the call chain. - DCHECK(value->IsUndefined()); - } - array->set(index, double_value); + if (index < static_cast(array->length())) { + if (value->IsNumber()) { + double_value = value->Number(); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); } + array->set(index, double_value); } return array->GetIsolate()->factory()->NewNumber(double_value); } @@ -16931,7 +16916,25 @@ void JSArrayBuffer::Neuter() { CHECK(is_external()); set_backing_store(NULL); set_byte_length(Smi::FromInt(0)); - set_was_neutered(true); +} + + +void JSArrayBufferView::NeuterView() { + CHECK(JSArrayBuffer::cast(buffer())->is_neuterable()); + set_byte_offset(Smi::FromInt(0)); + set_byte_length(Smi::FromInt(0)); +} + + +void JSDataView::Neuter() { + NeuterView(); +} + + +void JSTypedArray::Neuter() { + NeuterView(); + set_length(Smi::FromInt(0)); + set_elements(GetHeap()->EmptyExternalArrayForMap(map())); } @@ -16975,6 +16978,15 @@ Handle JSTypedArray::MaterializeArrayBuffer( fixed_typed_array->length(), typed_array->type(), static_cast(buffer->backing_store())); + Heap* heap = isolate->heap(); + if (heap->InNewSpace(*typed_array)) { + DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value()); + typed_array->set_weak_next(heap->new_array_buffer_views_list()); + heap->set_new_array_buffer_views_list(*typed_array); + } else { + buffer->set_weak_first_view(*typed_array); + DCHECK(typed_array->weak_next() == isolate->heap()->undefined_value()); + } typed_array->set_buffer(*buffer); JSObject::SetMapAndElements(typed_array, new_map, new_elements); diff --git a/src/objects.h b/src/objects.h index 68db075..bfec772 100644 --- a/src/objects.h +++ b/src/objects.h @@ -4660,9 +4660,9 @@ class ExternalUint8ClampedArray: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined and clamps the converted value between 0 and 255. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalUint8ClampedArray) @@ -4684,9 +4684,9 @@ class ExternalInt8Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalInt8Array) @@ -4708,9 +4708,9 @@ class ExternalUint8Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalUint8Array) @@ -4732,9 +4732,9 @@ class ExternalInt16Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalInt16Array) @@ -4757,9 +4757,9 @@ class ExternalUint16Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalUint16Array) @@ -4781,9 +4781,9 @@ class ExternalInt32Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalInt32Array) @@ -4806,9 +4806,9 @@ class ExternalUint32Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalUint32Array) @@ -4831,9 +4831,9 @@ class ExternalFloat32Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalFloat32Array) @@ -4856,9 +4856,9 @@ class ExternalFloat64Array: public ExternalArray { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle array, - uint32_t index, Handle value); + static Handle SetValue(Handle array, + uint32_t index, + Handle value); DECLARE_CAST(ExternalFloat64Array) @@ -4921,9 +4921,9 @@ class FixedTypedArray: public FixedTypedArrayBase { // This accessor applies the correct conversion from Smi, HeapNumber // and undefined. - static Handle SetValue(Handle holder, - Handle > array, - uint32_t index, Handle value); + static Handle SetValue(Handle > array, + uint32_t index, + Handle value); DECLARE_PRINTER(FixedTypedArray) DECLARE_VERIFIER(FixedTypedArray) @@ -10244,14 +10244,15 @@ class JSArrayBuffer: public JSObject { inline bool is_neuterable(); inline void set_is_neuterable(bool value); - inline bool was_neutered(); - inline void set_was_neutered(bool value); - // [weak_next]: linked list of array buffers. DECL_ACCESSORS(weak_next, Object) + // [weak_first_array]: weak linked list of views. + DECL_ACCESSORS(weak_first_view, Object) + DECLARE_CAST(JSArrayBuffer) + // Neutering. Only neuters the buffer, not associated typed arrays. void Neuter(); // Dispatched behavior. @@ -10262,18 +10263,18 @@ class JSArrayBuffer: public JSObject { static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize; static const int kFlagOffset = kByteLengthOffset + kPointerSize; static const int kWeakNextOffset = kFlagOffset + kPointerSize; - static const int kSize = kWeakNextOffset + kPointerSize; + static const int kWeakFirstViewOffset = kWeakNextOffset + kPointerSize; + static const int kSize = kWeakFirstViewOffset + kPointerSize; static const int kSizeWithInternalFields = kSize + v8::ArrayBuffer::kInternalFieldCount * kPointerSize; + private: // Bit position in a flag static const int kIsExternalBit = 0; static const int kShouldBeFreed = 1; static const int kIsNeuterableBit = 2; - static const int kWasNeuteredBit = 3; - private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBuffer); }; @@ -10289,23 +10290,23 @@ class JSArrayBufferView: public JSObject { // [byte_length]: length of typed array in bytes. DECL_ACCESSORS(byte_length, Object) + // [weak_next]: linked list of typed arrays over the same array buffer. + DECL_ACCESSORS(weak_next, Object) + DECLARE_CAST(JSArrayBufferView) DECLARE_VERIFIER(JSArrayBufferView) - inline bool WasNeutered() const; - static const int kBufferOffset = JSObject::kHeaderSize; static const int kByteOffsetOffset = kBufferOffset + kPointerSize; static const int kByteLengthOffset = kByteOffsetOffset + kPointerSize; - static const int kViewSize = kByteLengthOffset + kPointerSize; + static const int kWeakNextOffset = kByteLengthOffset + kPointerSize; + static const int kViewSize = kWeakNextOffset + kPointerSize; - private: -#ifdef VERIFY_HEAP - DECL_ACCESSORS(raw_byte_offset, Object) - DECL_ACCESSORS(raw_byte_length, Object) -#endif + protected: + void NeuterView(); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(JSArrayBufferView); }; @@ -10315,6 +10316,9 @@ class JSTypedArray: public JSArrayBufferView { // [length]: length of typed array in elements. DECL_ACCESSORS(length, Object) + // Neutering. Only neuters this typed array. + void Neuter(); + DECLARE_CAST(JSTypedArray) ExternalArrayType type(); @@ -10335,9 +10339,6 @@ class JSTypedArray: public JSArrayBufferView { private: static Handle MaterializeArrayBuffer( Handle typed_array); -#ifdef VERIFY_HEAP - DECL_ACCESSORS(raw_length, Object) -#endif DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray); }; @@ -10345,6 +10346,9 @@ class JSTypedArray: public JSArrayBufferView { class JSDataView: public JSArrayBufferView { public: + // Only neuters this DataView + void Neuter(); + DECLARE_CAST(JSDataView) // Dispatched behavior. diff --git a/src/runtime/runtime-typedarray.cc b/src/runtime/runtime-typedarray.cc index 02b5579..a1aacd7 100644 --- a/src/runtime/runtime-typedarray.cc +++ b/src/runtime/runtime-typedarray.cc @@ -63,6 +63,7 @@ void Runtime::SetupArrayBuffer(Isolate* isolate, ->set_weak_next(*array_buffer); isolate->heap()->set_last_array_buffer_in_list(*array_buffer); } + array_buffer->set_weak_first_view(isolate->heap()->undefined_value()); } @@ -96,6 +97,39 @@ bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate, void Runtime::NeuterArrayBuffer(Handle array_buffer) { + Isolate* isolate = array_buffer->GetIsolate(); + // Firstly, iterate over the views which are referenced directly by the array + // buffer. + for (Handle view_obj(array_buffer->weak_first_view(), isolate); + !view_obj->IsUndefined();) { + Handle view(JSArrayBufferView::cast(*view_obj)); + if (view->IsJSTypedArray()) { + JSTypedArray::cast(*view)->Neuter(); + } else if (view->IsJSDataView()) { + JSDataView::cast(*view)->Neuter(); + } else { + UNREACHABLE(); + } + view_obj = handle(view->weak_next(), isolate); + } + + // Secondly, iterate over the global list of new space views to find views + // that belong to the neutered array buffer. + Heap* heap = isolate->heap(); + for (Handle view_obj(heap->new_array_buffer_views_list(), isolate); + !view_obj->IsUndefined();) { + Handle view(JSArrayBufferView::cast(*view_obj)); + if (view->buffer() == *array_buffer) { + if (view->IsJSTypedArray()) { + JSTypedArray::cast(*view)->Neuter(); + } else if (view->IsJSDataView()) { + JSDataView::cast(*view)->Neuter(); + } else { + UNREACHABLE(); + } + } + view_obj = handle(view->weak_next(), isolate); + } array_buffer->Neuter(); } @@ -261,10 +295,19 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { holder->set_byte_offset(*byte_offset_object); holder->set_byte_length(*byte_length_object); + Heap* heap = isolate->heap(); if (!maybe_buffer->IsNull()) { Handle buffer = Handle::cast(maybe_buffer); holder->set_buffer(*buffer); + if (heap->InNewSpace(*holder)) { + holder->set_weak_next(heap->new_array_buffer_views_list()); + heap->set_new_array_buffer_views_list(*holder); + } else { + holder->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*holder); + } + Handle elements = isolate->factory()->NewExternalArray( static_cast(length), array_type, static_cast(buffer->backing_store()) + byte_offset); @@ -274,6 +317,7 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind())); } else { holder->set_buffer(Smi::FromInt(0)); + holder->set_weak_next(isolate->heap()->undefined_value()); Handle elements = isolate->factory()->NewFixedTypedArray(static_cast(length), array_type); @@ -361,6 +405,15 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { holder->set_byte_length(*byte_length_obj); holder->set_length(*length_obj); + Heap* heap = isolate->heap(); + if (heap->InNewSpace(*holder)) { + holder->set_weak_next(heap->new_array_buffer_views_list()); + heap->set_new_array_buffer_views_list(*holder); + } else { + holder->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*holder); + } + Handle elements = isolate->factory()->NewExternalArray( static_cast(length), array_type, static_cast(buffer->backing_store())); @@ -533,6 +586,15 @@ RUNTIME_FUNCTION(Runtime_DataViewInitialize) { holder->set_byte_offset(*byte_offset); holder->set_byte_length(*byte_length); + Heap* heap = isolate->heap(); + if (heap->InNewSpace(*holder)) { + holder->set_weak_next(heap->new_array_buffer_views_list()); + heap->set_new_array_buffer_views_list(*holder); + } else { + holder->set_weak_next(buffer->weak_first_view()); + buffer->set_weak_first_view(*holder); + } + return isolate->heap()->undefined_value(); } diff --git a/src/snapshot/serialize.cc b/src/snapshot/serialize.cc index 26f8da3..bf0a4eb 100644 --- a/src/snapshot/serialize.cc +++ b/src/snapshot/serialize.cc @@ -567,6 +567,8 @@ void Deserializer::Deserialize(Isolate* isolate) { isolate_->heap()->undefined_value()); isolate_->heap()->set_last_array_buffer_in_list( isolate_->heap()->undefined_value()); + isolate->heap()->set_new_array_buffer_views_list( + isolate_->heap()->undefined_value()); // The allocation site list is build during root iteration, but if no sites // were encountered then it needs to be initialized to undefined. diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 7954598..88c49ce 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -13833,10 +13833,9 @@ static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type, i::Factory* factory = isolate->factory(); v8::HandleScope scope(context->GetIsolate()); const int kElementCount = 260; - i::Handle jsobj = - factory->NewJSTypedArray(elements_kind, kElementCount); - i::Handle fixed_array( - FixedTypedArrayClass::cast(jsobj->elements())); + i::Handle fixed_array = + i::Handle::cast( + factory->NewFixedTypedArray(kElementCount, array_type)); CHECK_EQ(FixedTypedArrayClass::kInstanceType, fixed_array->map()->instance_type()); CHECK_EQ(kElementCount, fixed_array->length()); @@ -13850,7 +13849,12 @@ static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type, CHECK_EQ(static_cast(static_cast(i)), static_cast(fixed_array->get_scalar(i))); } - v8::Handle obj = v8::Utils::ToLocal(jsobj); + v8::Handle obj = v8::Object::New(CcTest::isolate()); + i::Handle jsobj = v8::Utils::OpenHandle(*obj); + i::Handle fixed_array_map = + i::JSObject::GetElementsTransitionMap(jsobj, elements_kind); + jsobj->set_map(*fixed_array_map); + jsobj->set_elements(*fixed_array); ObjectWithExternalArrayTestHelper( context.local(), obj, kElementCount, array_type, diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc index 0a255b6..f461eff 100644 --- a/test/cctest/test-heap-profiler.cc +++ b/test/cctest/test-heap-profiler.cc @@ -2577,6 +2577,9 @@ TEST(ArrayBufferAndArrayBufferView) { const v8::HeapGraphNode* arr1_buffer = GetProperty(arr1_obj, v8::HeapGraphEdge::kInternal, "buffer"); CHECK(arr1_buffer); + const v8::HeapGraphNode* first_view = + GetProperty(arr1_buffer, v8::HeapGraphEdge::kWeak, "weak_first_view"); + CHECK(first_view); const v8::HeapGraphNode* backing_store = GetProperty(arr1_buffer, v8::HeapGraphEdge::kInternal, "backing_store"); CHECK(backing_store); diff --git a/test/cctest/test-weaktypedarrays.cc b/test/cctest/test-weaktypedarrays.cc index aa3e432..c1f59de 100644 --- a/test/cctest/test-weaktypedarrays.cc +++ b/test/cctest/test-weaktypedarrays.cc @@ -62,6 +62,87 @@ static bool HasArrayBufferInWeakList(Heap* heap, JSArrayBuffer* ab) { } +static int CountViewsInNewSpaceList(Heap* heap, JSArrayBuffer* array_buffer) { + int count = 0; + for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined();) { + JSArrayBufferView* view = JSArrayBufferView::cast(o); + if (array_buffer == view->buffer()) { + count++; + } + o = view->weak_next(); + } + return count; +} + + +static int CountViews(Heap* heap, JSArrayBuffer* array_buffer) { + int count = 0; + for (Object* o = array_buffer->weak_first_view(); + !o->IsUndefined(); + o = JSArrayBufferView::cast(o)->weak_next()) { + count++; + } + + return count + CountViewsInNewSpaceList(heap, array_buffer); +} + + +static bool HasViewInNewSpaceList(Heap* heap, JSArrayBufferView* ta) { + for (Object* o = heap->new_array_buffer_views_list(); !o->IsUndefined(); + o = JSArrayBufferView::cast(o)->weak_next()) { + if (ta == o) return true; + } + return false; +} + + +static bool HasViewInWeakList(Heap* heap, JSArrayBuffer* array_buffer, + JSArrayBufferView* ta) { + for (Object* o = array_buffer->weak_first_view(); + !o->IsUndefined(); + o = JSArrayBufferView::cast(o)->weak_next()) { + if (ta == o) return true; + } + return HasViewInNewSpaceList(heap, ta); +} + + +TEST(WeakArrayBuffersFromApi) { + v8::V8::Initialize(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + + int start = CountArrayBuffersInWeakList(isolate->heap()); + { + v8::HandleScope s1(context->GetIsolate()); + v8::Handle ab1 = + v8::ArrayBuffer::New(context->GetIsolate(), 256); + { + v8::HandleScope s2(context->GetIsolate()); + v8::Handle ab2 = + v8::ArrayBuffer::New(context->GetIsolate(), 128); + + Handle iab1 = v8::Utils::OpenHandle(*ab1); + Handle iab2 = v8::Utils::OpenHandle(*ab2); + CHECK_EQ(2, CountArrayBuffersInWeakList(isolate->heap()) - start); + CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); + CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab2)); + } + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); + { + HandleScope scope2(isolate); + Handle iab1 = v8::Utils::OpenHandle(*ab1); + + CHECK(HasArrayBufferInWeakList(isolate->heap(), *iab1)); + } + } + + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap())); +} + + TEST(WeakArrayBuffersFromScript) { v8::V8::Initialize(); LocalContext context; @@ -122,3 +203,217 @@ TEST(WeakArrayBuffersFromScript) { CHECK_EQ(start, CountArrayBuffersInWeakList(isolate->heap())); } } + +template +void TestViewFromApi() { + v8::V8::Initialize(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + + v8::HandleScope s1(context->GetIsolate()); + v8::Handle ab = + v8::ArrayBuffer::New(context->GetIsolate(), 2048); + Handle iab = v8::Utils::OpenHandle(*ab); + { + v8::HandleScope s2(context->GetIsolate()); + v8::Handle ta1 = View::New(ab, 0, 256); + { + v8::HandleScope s3(context->GetIsolate()); + v8::Handle ta2 = View::New(ab, 0, 128); + + Handle ita1 = v8::Utils::OpenHandle(*ta1); + Handle ita2 = v8::Utils::OpenHandle(*ta2); + CHECK_EQ(2, CountViews(isolate->heap(), *iab)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita2)); + } + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + CHECK_EQ(1, CountViews(isolate->heap(), *iab)); + Handle ita1 = v8::Utils::OpenHandle(*ta1); + CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1)); + } + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + CHECK_EQ(0, CountViews(isolate->heap(), *iab)); +} + + +TEST(Uint8ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Int8ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Uint16ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Int16ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Uint32ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Int32ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Float32ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Float64ArrayFromApi) { + TestViewFromApi(); +} + + +TEST(Uint8ClampedArrayFromApi) { + TestViewFromApi(); +} + + +TEST(DataViewFromApi) { + TestViewFromApi(); +} + +template +static void TestTypedArrayFromScript(const char* constructor) { + v8::V8::Initialize(); + LocalContext context; + Isolate* isolate = GetIsolateFrom(&context); + v8::HandleScope scope(context->GetIsolate()); + int start = CountArrayBuffersInWeakList(isolate->heap()); + CompileRun("var ab = new ArrayBuffer(2048);"); + for (int i = 1; i <= 3; i++) { + // Create 3 typed arrays, make i-th of them garbage, + // validate correct state of typed array weak list. + v8::HandleScope s0(context->GetIsolate()); + i::ScopedVector source(2048); + + CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); + + { + v8::HandleScope s1(context->GetIsolate()); + i::SNPrintF(source, + "var ta1 = new %s(ab);" + "var ta2 = new %s(ab);" + "var ta3 = new %s(ab)", + constructor, constructor, constructor); + + CompileRun(source.start()); + v8::Handle ab = + v8::Handle::Cast(CompileRun("ab")); + v8::Handle ta1 = + v8::Handle::Cast(CompileRun("ta1")); + v8::Handle ta2 = + v8::Handle::Cast(CompileRun("ta2")); + v8::Handle ta3 = + v8::Handle::Cast(CompileRun("ta3")); + CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); + Handle iab = v8::Utils::OpenHandle(*ab); + CHECK_EQ(3, CountViews(isolate->heap(), *iab)); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta1))); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta2))); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta3))); + } + + i::SNPrintF(source, "ta%d = null;", i); + CompileRun(source.start()); + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); + + { + v8::HandleScope s2(context->GetIsolate()); + v8::Handle ab = + v8::Handle::Cast(CompileRun("ab")); + Handle iab = v8::Utils::OpenHandle(*ab); + CHECK_EQ(2, CountViews(isolate->heap(), *iab)); + for (int j = 1; j <= 3; j++) { + if (j == i) continue; + i::SNPrintF(source, "ta%d", j); + v8::Handle ta = + v8::Handle::Cast(CompileRun(source.start())); + CHECK(HasViewInWeakList(isolate->heap(), *iab, + *v8::Utils::OpenHandle(*ta))); + } + } + + CompileRun("ta1 = null; ta2 = null; ta3 = null;"); + isolate->heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask); + + CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start); + + { + v8::HandleScope s3(context->GetIsolate()); + v8::Handle ab = + v8::Handle::Cast(CompileRun("ab")); + Handle iab = v8::Utils::OpenHandle(*ab); + CHECK_EQ(0, CountViews(isolate->heap(), *iab)); + } + } +} + + +TEST(Uint8ArrayFromScript) { + TestTypedArrayFromScript("Uint8Array"); +} + + +TEST(Int8ArrayFromScript) { + TestTypedArrayFromScript("Int8Array"); +} + + +TEST(Uint16ArrayFromScript) { + TestTypedArrayFromScript("Uint16Array"); +} + + +TEST(Int16ArrayFromScript) { + TestTypedArrayFromScript("Int16Array"); +} + + +TEST(Uint32ArrayFromScript) { + TestTypedArrayFromScript("Uint32Array"); +} + + +TEST(Int32ArrayFromScript) { + TestTypedArrayFromScript("Int32Array"); +} + + +TEST(Float32ArrayFromScript) { + TestTypedArrayFromScript("Float32Array"); +} + + +TEST(Float64ArrayFromScript) { + TestTypedArrayFromScript("Float64Array"); +} + + +TEST(Uint8ClampedArrayFromScript) { + TestTypedArrayFromScript("Uint8ClampedArray"); +} + + +TEST(DataViewFromScript) { + TestTypedArrayFromScript("DataView"); +} -- 2.7.4