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}
This commit is contained in:
jochen 2015-04-22 08:03:25 -07:00 committed by Commit bot
parent 5b6111edff
commit 47f2dfa9bd
22 changed files with 839 additions and 450 deletions

View File

@ -78,10 +78,32 @@ bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> 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(),

View File

@ -620,7 +620,7 @@ class ElementsAccessorBase : public ElementsAccessor {
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
if (key < ElementsAccessorSubclass::GetCapacityImpl(obj, backing_store)) {
if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
} else {
return backing_store->GetIsolate()->factory()->the_hole_value();
@ -638,7 +638,7 @@ class ElementsAccessorBase : public ElementsAccessor {
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> 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<JSObject> holder,
Handle<FixedArrayBase> backing_store) {
static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
return backing_store->length();
}
uint32_t GetCapacity(Handle<JSObject> holder,
Handle<FixedArrayBase> backing_store) final {
return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) final {
return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
}
static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> backing_store,
@ -1262,7 +1260,7 @@ class TypedElementsAccessor
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
if (key < AccessorClass::GetCapacityImpl(obj, backing_store)) {
if (key < AccessorClass::GetCapacityImpl(backing_store)) {
return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
} else {
return backing_store->GetIsolate()->factory()->undefined_value();
@ -1273,8 +1271,9 @@ class TypedElementsAccessor
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
return key < AccessorClass::GetCapacityImpl(obj, backing_store) ? NONE
: ABSENT;
return
key < AccessorClass::GetCapacityImpl(backing_store)
? NONE : ABSENT;
}
MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
@ -1294,16 +1293,10 @@ class TypedElementsAccessor
static bool HasElementImpl(Handle<JSObject> holder, uint32_t key,
Handle<FixedArrayBase> 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<JSObject> holder,
Handle<FixedArrayBase> backing_store) {
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::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<JSObject> holder,
Handle<FixedArrayBase> backing_store) {
static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
Handle<FixedArrayBase> arguments(
FixedArrayBase::cast(parameter_map->get(1)));
return Max(static_cast<uint32_t>(parameter_map->length() - 2),
ForArray(arguments)->GetCapacity(holder, arguments));
ForArray(arguments)->GetCapacity(arguments));
}
static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> dict,

View File

@ -183,8 +183,7 @@ class ElementsAccessor {
protected:
friend class SloppyArgumentsElementsAccessor;
virtual uint32_t GetCapacity(Handle<JSObject> holder,
Handle<FixedArrayBase> backing_store) = 0;
virtual uint32_t GetCapacity(Handle<FixedArrayBase> 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

View File

@ -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<i::JSArrayBufferView> obj,
i::Handle<i::JSArrayBuffer> 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<i::Object> byte_offset_object =
isolate->factory()->NewNumberFromSize(byte_offset);
obj->set_byte_offset(*byte_offset_object);
@ -1927,16 +1890,6 @@ Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type) {
}
Handle<JSTypedArray> Factory::NewJSTypedArray(ElementsKind elements_kind) {
Handle<JSFunction> typed_array_fun_handle(
GetTypedArrayFun(elements_kind, isolate()));
CALL_HEAP_FUNCTION(
isolate(), isolate()->heap()->AllocateJSObject(*typed_array_fun_handle),
JSTypedArray);
}
Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
Handle<JSArrayBuffer> buffer,
size_t byte_offset,
@ -1965,34 +1918,6 @@ Handle<JSTypedArray> Factory::NewJSTypedArray(ExternalArrayType type,
}
Handle<JSTypedArray> Factory::NewJSTypedArray(ElementsKind elements_kind,
size_t number_of_elements) {
Handle<JSTypedArray> obj = NewJSTypedArray(elements_kind);
size_t element_size = GetFixedTypedArraysElementSize(elements_kind);
ExternalArrayType array_type = GetArrayTypeFromElementsKind(elements_kind);
CHECK(number_of_elements <=
(std::numeric_limits<size_t>::max() / element_size));
CHECK(number_of_elements <= static_cast<size_t>(Smi::kMaxValue));
size_t byte_length = number_of_elements * element_size;
obj->set_byte_offset(Smi::FromInt(0));
i::Handle<i::Object> byte_length_object =
isolate()->factory()->NewNumberFromSize(byte_length);
obj->set_byte_length(*byte_length_object);
Handle<Object> length_object = NewNumberFromSize(number_of_elements);
obj->set_length(*length_object);
obj->set_buffer(Smi::FromInt(0));
Handle<FixedTypedArrayBase> elements =
isolate()->factory()->NewFixedTypedArray(
static_cast<int>(number_of_elements), array_type);
obj->set_elements(*elements);
return obj;
}
Handle<JSDataView> Factory::NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset,
size_t byte_length) {

View File

@ -448,17 +448,11 @@ class Factory final {
Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type);
Handle<JSTypedArray> NewJSTypedArray(ElementsKind elements_kind);
// Creates a new JSTypedArray with the specified buffer.
Handle<JSTypedArray> NewJSTypedArray(ExternalArrayType type,
Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t length);
// Creates a new on-heap JSTypedArray.
Handle<JSTypedArray> NewJSTypedArray(ElementsKind elements_kind,
size_t number_of_elements);
Handle<JSDataView> NewJSDataView();
Handle<JSDataView> NewJSDataView(Handle<JSArrayBuffer> buffer,
size_t byte_offset, size_t byte_length);

View File

@ -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;

View File

@ -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<JSArrayBufferView>(
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<alignment>(map, slot, object, object_size)) {
return;
}
heap->set_migration_failure(true);
}
if (PromoteObject<object_contents, alignment>(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;
}

View File

@ -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;

View File

@ -80,12 +80,14 @@ int StaticNewSpaceVisitor<StaticVisitor>::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<StaticVisitor>::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<StaticVisitor>::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<StaticVisitor>::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<StaticVisitor>::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<StaticVisitor>::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));
}

View File

@ -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 <class T>
static void ClearWeakList(Heap* heap, Object* list) {
Object* undefined = heap->undefined_value();
@ -344,6 +394,22 @@ struct WeakListVisitor<Context> {
};
template <>
struct WeakListVisitor<JSArrayBufferView> {
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<JSArrayBuffer> {
static void SetWeakNext(JSArrayBuffer* obj, Object* next) {
@ -356,6 +422,14 @@ struct WeakListVisitor<JSArrayBuffer> {
static void VisitLiveObject(Heap* heap, JSArrayBuffer* array_buffer,
WeakObjectRetainer* retainer) {
Object* typed_array_obj = VisitWeakList<JSArrayBufferView>(
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<JSArrayBuffer>(Heap* heap, Object* list,
bool stop_after_young,
Object** list_tail);
template Object* VisitWeakList<JSArrayBufferView>(Heap* heap, Object* list,
WeakObjectRetainer* retainer,
bool stop_after_young,
Object** list_tail);
template Object* VisitWeakList<AllocationSite>(Heap* heap, Object* list,
WeakObjectRetainer* retainer,
bool stop_after_young,

View File

@ -6097,16 +6097,21 @@ class HObjectAccess final {
JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
}
static HObjectAccess ForJSArrayBufferFlag() {
return HObjectAccess::ForObservableJSObjectOffset(
JSArrayBuffer::kFlagOffset, Representation::Smi());
}
static HObjectAccess ForExternalArrayExternalPointer() {
return HObjectAccess::ForObservableJSObjectOffset(
ExternalArray::kExternalPointerOffset, Representation::External());
}
static HObjectAccess ForJSArrayBufferViewWeakNext() {
return HObjectAccess::ForObservableJSObjectOffset(
JSArrayBufferView::kWeakNextOffset);
}
static HObjectAccess ForJSArrayBufferWeakFirstView() {
return HObjectAccess::ForObservableJSObjectOffset(
JSArrayBuffer::kWeakFirstViewOffset);
}
static HObjectAccess ForJSArrayBufferViewBuffer() {
return HObjectAccess::ForObservableJSObjectOffset(
JSArrayBufferView::kBufferOffset);

View File

@ -2427,22 +2427,6 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess(
IsFixedTypedArrayElementsKind(elements_kind)) {
HValue* backing_store;
if (IsExternalArrayElementsKind(elements_kind)) {
NoObservableSideEffectsScope no_effects(this);
HInstruction* buffer = Add<HLoadNamedField>(
checked_object, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer());
HInstruction* flags = Add<HLoadNamedField>(
buffer, nullptr, HObjectAccess::ForJSArrayBufferFlag());
HValue* was_neutered_mask =
Add<HConstant>(1 << JSArrayBuffer::kWasNeuteredBit);
HValue* was_neutered_test =
AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
IfBuilder if_was_neutered(this);
if_was_neutered.If<HCompareNumericAndBranch>(
was_neutered_test, graph()->GetConstant0(), Token::NE);
if_was_neutered.ThenDeopt(Deoptimizer::kOutOfBounds);
if_was_neutered.End();
backing_store = Add<HLoadNamedField>(
elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer());
} else {
@ -9633,11 +9617,20 @@ void HGraphBuilder::BuildArrayBufferViewInitialization(
Add<HStoreNamedField>(
obj,
HObjectAccess::ForJSArrayBufferViewBuffer(), buffer);
HObjectAccess weak_first_view_access =
HObjectAccess::ForJSArrayBufferWeakFirstView();
Add<HStoreNamedField>(
obj, HObjectAccess::ForJSArrayBufferViewWeakNext(),
Add<HLoadNamedField>(buffer, nullptr, weak_first_view_access));
Add<HStoreNamedField>(buffer, weak_first_view_access, obj);
} else {
Add<HStoreNamedField>(
obj,
HObjectAccess::ForJSArrayBufferViewBuffer(),
Add<HConstant>(static_cast<int32_t>(0)));
Add<HStoreNamedField>(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<HLoadNamedField>(
view, nullptr, HObjectAccess::ForJSArrayBufferViewBuffer());
HInstruction* field = Add<HLoadNamedField>(view, nullptr, access);
IfBuilder if_has_buffer(this);
if_has_buffer.IfNot<HIsSmiAndBranch>(buffer);
if_has_buffer.Then();
{
HInstruction* flags = Add<HLoadNamedField>(
buffer, nullptr, HObjectAccess::ForJSArrayBufferFlag());
HValue* was_neutered_mask =
Add<HConstant>(1 << JSArrayBuffer::kWasNeuteredBit);
HValue* was_neutered_test =
AddUncasted<HBitwise>(Token::BIT_AND, flags, was_neutered_mask);
IfBuilder if_was_neutered(this);
if_was_neutered.If<HCompareNumericAndBranch>(
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<HLoadNamedField>(
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<HLoadNamedField>(
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<HLoadNamedField>(
buffer, nullptr, HObjectAccess::ForJSTypedArrayLength());
return ast_context()->ReturnInstruction(result, expr->id());
}

View File

@ -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);

View File

@ -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());
}

View File

@ -4377,25 +4377,23 @@ Handle<Object> FixedTypedArray<Traits>::get(
template <class Traits>
Handle<Object> FixedTypedArray<Traits>::SetValue(
Handle<JSObject> holder, Handle<FixedTypedArray<Traits> > array,
uint32_t index, Handle<Object> value) {
Handle<FixedTypedArray<Traits> > array,
uint32_t index,
Handle<Object> value) {
ElementType cast_value = Traits::defaultValue();
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = from_int(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::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<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = from_int(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::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)

View File

@ -13317,17 +13317,17 @@ MaybeHandle<Object> 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<External##Type##Array> array( \
External##Type##Array::cast(object->elements())); \
return External##Type##Array::SetValue(object, array, index, value); \
} \
case TYPE##_ELEMENTS: { \
Handle<Fixed##Type##Array> 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<External##Type##Array> array( \
External##Type##Array::cast(object->elements())); \
return External##Type##Array::SetValue(array, index, value); \
} \
case TYPE##_ELEMENTS: { \
Handle<Fixed##Type##Array> 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<Object> ExternalUint8ClampedArray::SetValue(
Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array,
uint32_t index, Handle<Object> value) {
Handle<ExternalUint8ClampedArray> array,
uint32_t index,
Handle<Object> value) {
uint8_t clamped_value = 0;
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
if (int_value < 0) {
clamped_value = 0;
} else if (int_value > 255) {
clamped_value = 255;
} else {
clamped_value = static_cast<uint8_t>(int_value);
}
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::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<uint8_t>(lrint(double_value));
}
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::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<uint8_t>(int_value);
}
array->set(index, clamped_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::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<uint8_t>(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 <typename ExternalArrayClass, typename ValueType>
template<typename ExternalArrayClass, typename ValueType>
static Handle<Object> ExternalArrayIntSetter(
Isolate* isolate, Handle<JSObject> holder,
Handle<ExternalArrayClass> receiver, uint32_t index, Handle<Object> value) {
Isolate* isolate,
Handle<ExternalArrayClass> receiver,
uint32_t index,
Handle<Object> value) {
ValueType cast_value = 0;
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(receiver->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<ValueType>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<ValueType>(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<uint32_t>(receiver->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<ValueType>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<ValueType>(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<Object> ExternalInt8Array::SetValue(Handle<JSObject> holder,
Handle<ExternalInt8Array> array,
Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
array->GetIsolate(), holder, array, index, value);
array->GetIsolate(), array, index, value);
}
Handle<Object> ExternalUint8Array::SetValue(Handle<JSObject> holder,
Handle<ExternalUint8Array> array,
Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
array->GetIsolate(), holder, array, index, value);
array->GetIsolate(), array, index, value);
}
Handle<Object> ExternalInt16Array::SetValue(Handle<JSObject> holder,
Handle<ExternalInt16Array> array,
Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
array->GetIsolate(), holder, array, index, value);
array->GetIsolate(), array, index, value);
}
Handle<Object> ExternalUint16Array::SetValue(Handle<JSObject> holder,
Handle<ExternalUint16Array> array,
Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
array->GetIsolate(), holder, array, index, value);
array->GetIsolate(), array, index, value);
}
Handle<Object> ExternalInt32Array::SetValue(Handle<JSObject> holder,
Handle<ExternalInt32Array> array,
Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
array->GetIsolate(), holder, array, index, value);
array->GetIsolate(), array, index, value);
}
Handle<Object> ExternalUint32Array::SetValue(Handle<JSObject> holder,
Handle<ExternalUint32Array> array,
uint32_t index,
Handle<Object> value) {
Handle<Object> ExternalUint32Array::SetValue(
Handle<ExternalUint32Array> array,
uint32_t index,
Handle<Object> value) {
uint32_t cast_value = 0;
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<uint32_t>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<uint32_t>(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<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<uint32_t>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<uint32_t>(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<Object> ExternalFloat32Array::SetValue(
Handle<JSObject> holder, Handle<ExternalFloat32Array> array, uint32_t index,
Handle<ExternalFloat32Array> array,
uint32_t index,
Handle<Object> value) {
float cast_value = std::numeric_limits<float>::quiet_NaN();
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<float>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<float>(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<uint32_t>(array->length())) {
if (value->IsSmi()) {
int int_value = Handle<Smi>::cast(value)->value();
cast_value = static_cast<float>(int_value);
} else if (value->IsHeapNumber()) {
double double_value = Handle<HeapNumber>::cast(value)->value();
cast_value = static_cast<float>(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<Object> ExternalFloat64Array::SetValue(
Handle<JSObject> holder, Handle<ExternalFloat64Array> array, uint32_t index,
Handle<ExternalFloat64Array> array,
uint32_t index,
Handle<Object> value) {
double double_value = std::numeric_limits<double>::quiet_NaN();
Handle<JSArrayBufferView> view = Handle<JSArrayBufferView>::cast(holder);
if (!view->WasNeutered()) {
if (index < static_cast<uint32_t>(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<uint32_t>(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<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
fixed_typed_array->length(), typed_array->type(),
static_cast<uint8_t*>(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);

View File

@ -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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalUint8ClampedArray> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalUint8ClampedArray> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalInt8Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalInt8Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalUint8Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalUint8Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalInt16Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalInt16Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalUint16Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalUint16Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalInt32Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalInt32Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalUint32Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalUint32Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalFloat32Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalFloat32Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<ExternalFloat64Array> array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<ExternalFloat64Array> array,
uint32_t index,
Handle<Object> 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<Object> SetValue(Handle<JSObject> holder,
Handle<FixedTypedArray<Traits> > array,
uint32_t index, Handle<Object> value);
static Handle<Object> SetValue(Handle<FixedTypedArray<Traits> > array,
uint32_t index,
Handle<Object> 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;
protected:
void NeuterView();
private:
#ifdef VERIFY_HEAP
DECL_ACCESSORS(raw_byte_offset, Object)
DECL_ACCESSORS(raw_byte_length, Object)
#endif
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<JSArrayBuffer> MaterializeArrayBuffer(
Handle<JSTypedArray> 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.

View File

@ -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<JSArrayBuffer> array_buffer) {
Isolate* isolate = array_buffer->GetIsolate();
// Firstly, iterate over the views which are referenced directly by the array
// buffer.
for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
!view_obj->IsUndefined();) {
Handle<JSArrayBufferView> 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<Object> view_obj(heap->new_array_buffer_views_list(), isolate);
!view_obj->IsUndefined();) {
Handle<JSArrayBufferView> 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<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::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<ExternalArray> elements = isolate->factory()->NewExternalArray(
static_cast<int>(length), array_type,
static_cast<uint8_t*>(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<FixedTypedArrayBase> elements =
isolate->factory()->NewFixedTypedArray(static_cast<int>(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<ExternalArray> elements = isolate->factory()->NewExternalArray(
static_cast<int>(length), array_type,
static_cast<uint8_t*>(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();
}

View File

@ -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.

View File

@ -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<i::JSTypedArray> jsobj =
factory->NewJSTypedArray(elements_kind, kElementCount);
i::Handle<FixedTypedArrayClass> fixed_array(
FixedTypedArrayClass::cast(jsobj->elements()));
i::Handle<FixedTypedArrayClass> fixed_array =
i::Handle<FixedTypedArrayClass>::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<int64_t>(static_cast<ElementType>(i)),
static_cast<int64_t>(fixed_array->get_scalar(i)));
}
v8::Handle<v8::Object> obj = v8::Utils::ToLocal(jsobj);
v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj);
i::Handle<i::Map> fixed_array_map =
i::JSObject::GetElementsTransitionMap(jsobj, elements_kind);
jsobj->set_map(*fixed_array_map);
jsobj->set_elements(*fixed_array);
ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
context.local(), obj, kElementCount, array_type,

View File

@ -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);

View File

@ -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<v8::ArrayBuffer> ab1 =
v8::ArrayBuffer::New(context->GetIsolate(), 256);
{
v8::HandleScope s2(context->GetIsolate());
v8::Handle<v8::ArrayBuffer> ab2 =
v8::ArrayBuffer::New(context->GetIsolate(), 128);
Handle<JSArrayBuffer> iab1 = v8::Utils::OpenHandle(*ab1);
Handle<JSArrayBuffer> 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<JSArrayBuffer> 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 <typename View>
void TestViewFromApi() {
v8::V8::Initialize();
LocalContext context;
Isolate* isolate = GetIsolateFrom(&context);
v8::HandleScope s1(context->GetIsolate());
v8::Handle<v8::ArrayBuffer> ab =
v8::ArrayBuffer::New(context->GetIsolate(), 2048);
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
{
v8::HandleScope s2(context->GetIsolate());
v8::Handle<View> ta1 = View::New(ab, 0, 256);
{
v8::HandleScope s3(context->GetIsolate());
v8::Handle<View> ta2 = View::New(ab, 0, 128);
Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1);
Handle<JSArrayBufferView> 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<JSArrayBufferView> 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<v8::Uint8Array>();
}
TEST(Int8ArrayFromApi) {
TestViewFromApi<v8::Int8Array>();
}
TEST(Uint16ArrayFromApi) {
TestViewFromApi<v8::Uint16Array>();
}
TEST(Int16ArrayFromApi) {
TestViewFromApi<v8::Int16Array>();
}
TEST(Uint32ArrayFromApi) {
TestViewFromApi<v8::Uint32Array>();
}
TEST(Int32ArrayFromApi) {
TestViewFromApi<v8::Int32Array>();
}
TEST(Float32ArrayFromApi) {
TestViewFromApi<v8::Float32Array>();
}
TEST(Float64ArrayFromApi) {
TestViewFromApi<v8::Float64Array>();
}
TEST(Uint8ClampedArrayFromApi) {
TestViewFromApi<v8::Uint8ClampedArray>();
}
TEST(DataViewFromApi) {
TestViewFromApi<v8::DataView>();
}
template <typename TypedArray>
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<char> 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<v8::ArrayBuffer> ab =
v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab"));
v8::Handle<TypedArray> ta1 =
v8::Handle<TypedArray>::Cast(CompileRun("ta1"));
v8::Handle<TypedArray> ta2 =
v8::Handle<TypedArray>::Cast(CompileRun("ta2"));
v8::Handle<TypedArray> ta3 =
v8::Handle<TypedArray>::Cast(CompileRun("ta3"));
CHECK_EQ(1, CountArrayBuffersInWeakList(isolate->heap()) - start);
Handle<JSArrayBuffer> 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<v8::ArrayBuffer> ab =
v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab"));
Handle<JSArrayBuffer> 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<TypedArray> ta =
v8::Handle<TypedArray>::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<v8::ArrayBuffer> ab =
v8::Handle<v8::ArrayBuffer>::Cast(CompileRun("ab"));
Handle<JSArrayBuffer> iab = v8::Utils::OpenHandle(*ab);
CHECK_EQ(0, CountViews(isolate->heap(), *iab));
}
}
}
TEST(Uint8ArrayFromScript) {
TestTypedArrayFromScript<v8::Uint8Array>("Uint8Array");
}
TEST(Int8ArrayFromScript) {
TestTypedArrayFromScript<v8::Int8Array>("Int8Array");
}
TEST(Uint16ArrayFromScript) {
TestTypedArrayFromScript<v8::Uint16Array>("Uint16Array");
}
TEST(Int16ArrayFromScript) {
TestTypedArrayFromScript<v8::Int16Array>("Int16Array");
}
TEST(Uint32ArrayFromScript) {
TestTypedArrayFromScript<v8::Uint32Array>("Uint32Array");
}
TEST(Int32ArrayFromScript) {
TestTypedArrayFromScript<v8::Int32Array>("Int32Array");
}
TEST(Float32ArrayFromScript) {
TestTypedArrayFromScript<v8::Float32Array>("Float32Array");
}
TEST(Float64ArrayFromScript) {
TestTypedArrayFromScript<v8::Float64Array>("Float64Array");
}
TEST(Uint8ClampedArrayFromScript) {
TestTypedArrayFromScript<v8::Uint8ClampedArray>("Uint8ClampedArray");
}
TEST(DataViewFromScript) {
TestTypedArrayFromScript<v8::DataView>("DataView");
}