Revert of Reland "Remove the weak list of views from array buffers" (patchset #2...
authorjochen <jochen@chromium.org>
Fri, 24 Apr 2015 06:46:38 +0000 (23:46 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 24 Apr 2015 06:46:23 +0000 (06:46 +0000)
Reason for revert:
still working on perf

Original issue's description:
> Reland "Remove the weak list of views from array buffers"
>
> Original description:
> > 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
>
> BUG=v8:3996
> R=hpayer@chromium.org,dslomov@chromium.org,verwaest@chromium.org
> LOG=n
>
> Committed: https://crrev.com/655b04637e9da2749f53c866bca8f5f6abb05a3f
> Cr-Commit-Position: refs/heads/master@{#28029}

TBR=dslomov@chromium.org,hpayer@chromium.org,verwaest@chromium.org,dcarney@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:3996

Review URL: https://codereview.chromium.org/1053203007

Cr-Commit-Position: refs/heads/master@{#28038}

26 files changed:
src/accessors.cc
src/accessors.h
src/code-stubs-hydrogen.cc
src/code-stubs.h
src/elements.cc
src/elements.h
src/factory.cc
src/factory.h
src/heap-snapshot-generator.cc
src/heap/heap.cc
src/heap/heap.h
src/heap/objects-visiting-inl.h
src/heap/objects-visiting.cc
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ic/ic.cc
src/objects-debug.cc
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime/runtime-typedarray.cc
src/snapshot/serialize.cc
test/cctest/test-api.cc
test/cctest/test-heap-profiler.cc
test/cctest/test-weaktypedarrays.cc

index f220b82..5ef8bf1 100644 (file)
@@ -78,26 +78,6 @@ bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
       return
         CheckForName(name, isolate->factory()->length_string(),
                      JSArray::kLengthOffset, object_offset);
-    case JS_ARRAY_BUFFER_TYPE:
-      return CheckForName(name, isolate->factory()->byte_length_string(),
-                          JSArrayBuffer::kByteLengthOffset, object_offset);
-    default:
-      if (map->instance_type() < FIRST_NONSTRING_TYPE) {
-        return CheckForName(name, isolate->factory()->length_string(),
-                            String::kLengthOffset, object_offset);
-      }
-
-      return false;
-  }
-}
-
-
-bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
-                                                 Handle<Name> name,
-                                                 int* object_offset) {
-  Isolate* isolate = name->GetIsolate();
-
-  switch (map->instance_type()) {
     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
@@ -107,19 +87,29 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
           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);
-
+      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);
+      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(),
+                            String::kLengthOffset, object_offset);
+      }
+
       return false;
   }
 }
index d37b6b7..6b586a0 100644 (file)
@@ -80,14 +80,6 @@ class Accessors : public AllStatic {
   static bool IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
                                       int* object_offset);
 
-  // Returns true for properties that are accessors to ArrayBufferView and
-  // derived classes fields. If true, *object_offset contains offset of
-  // object field. The caller still has to check whether the underlying
-  // buffer was neutered.
-  static bool IsJSArrayBufferViewFieldAccessor(Handle<Map> map,
-                                               Handle<Name> name,
-                                               int* object_offset);
-
   static Handle<AccessorInfo> MakeAccessor(
       Isolate* isolate,
       Handle<Name> name,
index 47e7ddb..3ca301c 100644 (file)
@@ -625,18 +625,6 @@ Handle<Code> LoadFieldStub::GenerateCode() {
 
 
 template <>
-HValue* CodeStubGraphBuilder<ArrayBufferViewLoadFieldStub>::BuildCodeStub() {
-  return BuildArrayBufferViewFieldAccessor(GetParameter(0), nullptr,
-                                           casted_stub()->index());
-}
-
-
-Handle<Code> ArrayBufferViewLoadFieldStub::GenerateCode() {
-  return DoGenerateCode(this);
-}
-
-
-template <>
 HValue* CodeStubGraphBuilder<LoadConstantStub>::BuildCodeStub() {
   HValue* map = AddLoadMap(GetParameter(0), NULL);
   HObjectAccess descriptors_access = HObjectAccess::ForObservableJSObjectOffset(
index 6ce369d..424026f 100644 (file)
@@ -88,7 +88,6 @@ namespace internal {
   V(VectorRawKeyedLoad)                     \
   V(VectorRawLoad)                          \
   /* IC Handler stubs */                    \
-  V(ArrayBufferViewLoadField)               \
   V(LoadConstant)                           \
   V(LoadField)                              \
   V(KeyedLoadSloppyArguments)               \
@@ -974,32 +973,6 @@ class LoadFieldStub: public HandlerStub {
 };
 
 
-class ArrayBufferViewLoadFieldStub : public HandlerStub {
- public:
-  ArrayBufferViewLoadFieldStub(Isolate* isolate, FieldIndex index)
-      : HandlerStub(isolate) {
-    int property_index_key = index.GetFieldAccessStubKey();
-    set_sub_minor_key(
-        ArrayBufferViewLoadFieldByIndexBits::encode(property_index_key));
-  }
-
-  FieldIndex index() const {
-    int property_index_key =
-        ArrayBufferViewLoadFieldByIndexBits::decode(sub_minor_key());
-    return FieldIndex::FromFieldAccessStubKey(property_index_key);
-  }
-
- protected:
-  Code::Kind kind() const override { return Code::LOAD_IC; }
-  Code::StubType GetStubType() const override { return Code::FAST; }
-
- private:
-  class ArrayBufferViewLoadFieldByIndexBits : public BitField<int, 0, 13> {};
-
-  DEFINE_HANDLER_CODE_STUB(ArrayBufferViewLoadField, HandlerStub);
-};
-
-
 class KeyedLoadSloppyArgumentsStub : public HandlerStub {
  public:
   explicit KeyedLoadSloppyArgumentsStub(Isolate* isolate)
index ac63b75..a00cd24 100644 (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,
index e743849..1d80b25 100644 (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
index d2a8d79..eda7cdd 100644 (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) {
index 72991d9..87ec2e6 100644 (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);
index bae364c..92149a2 100644 (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;
index 985d1f6..63cdae8 100644 (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);
 }
 
 
@@ -1678,6 +1687,7 @@ void Heap::UpdateReferencesInExternalStringTable(
 
 void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
   ProcessArrayBuffers(retainer, false);
+  ProcessNewArrayBufferViews(retainer);
   ProcessNativeContexts(retainer);
   ProcessAllocationSites(retainer);
 }
@@ -1685,6 +1695,7 @@ void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
 
 void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) {
   ProcessArrayBuffers(retainer, true);
+  ProcessNewArrayBufferViews(retainer);
   ProcessNativeContexts(retainer);
 }
 
@@ -1711,6 +1722,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);
@@ -1721,6 +1733,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;) {
@@ -2152,6 +2178,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,
@@ -5376,6 +5403,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;
 }
index dcf7bde..d60a3f0 100644 (file)
@@ -883,6 +883,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;
   }
@@ -1489,6 +1496,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.
 
@@ -1663,6 +1682,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.
@@ -1993,6 +2017,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
@@ -2152,6 +2177,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;
index 39803b1..06fa10e 100644 (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));
 }
 
index 8c2f198..cf71fb2 100644 (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();
@@ -345,6 +395,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) {
     obj->set_weak_next(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,
index 0e84a6e..0434a13 100644 (file)
@@ -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() {
index e48b170..1e28cea 100644 (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 {
@@ -3171,44 +3155,6 @@ HInstruction* HGraphBuilder::BuildGetArrayFunction() {
 }
 
 
-HValue* HGraphBuilder::BuildArrayBufferViewFieldAccessor(HValue* object,
-                                                         HValue* checked_object,
-                                                         FieldIndex index) {
-  NoObservableSideEffectsScope scope(this);
-  HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset(
-      index.offset(), Representation::Tagged());
-  HInstruction* buffer = Add<HLoadNamedField>(
-      object, checked_object, HObjectAccess::ForJSArrayBufferViewBuffer());
-  HInstruction* field = Add<HLoadNamedField>(object, checked_object, access);
-
-  IfBuilder if_has_buffer(this);
-  HValue* has_buffer = if_has_buffer.IfNot<HIsSmiAndBranch>(buffer);
-  if_has_buffer.Then();
-  {
-    HInstruction* flags = Add<HLoadNamedField>(
-        buffer, has_buffer, 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 Pop();
-}
-
-
 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder,
     ElementsKind kind,
     HValue* allocation_site_payload,
@@ -5708,7 +5654,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
 
             Handle<Map> map = property->GetReceiverType();
             Handle<String> name = key->AsPropertyName();
-            HValue* store;
+            HInstruction* store;
             if (map.is_null()) {
               // If we don't know the monomorphic type, do a generic store.
               CHECK_ALIVE(store = BuildNamedGeneric(
@@ -5726,9 +5672,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
                     STORE, NULL, literal, name, value));
               }
             }
-            if (store->IsInstruction()) {
-              AddInstruction(HInstruction::cast(store));
-            }
+            AddInstruction(store);
             DCHECK(store->HasObservableSideEffects());
             Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
           } else {
@@ -6189,7 +6133,6 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::IsIntegerIndexedExotic() {
 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() {
   if (!CanInlinePropertyAccess(map_)) return false;
   if (IsJSObjectFieldAccessor()) return IsLoad();
-  if (IsJSArrayBufferViewFieldAccessor()) return IsLoad();
   if (map_->function_with_prototype() && !map_->has_non_instance_prototype() &&
       name_.is_identical_to(isolate()->factory()->prototype_string())) {
     return IsLoad();
@@ -6238,18 +6181,6 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic(
     return true;
   }
 
-  if (GetJSArrayBufferViewFieldAccess(&access)) {
-    for (int i = 1; i < maps->length(); ++i) {
-      PropertyAccessInfo test_info(builder_, access_type_, maps->at(i), name_);
-      HObjectAccess test_access = HObjectAccess::ForMap();  // bogus default
-      if (!test_info.GetJSArrayBufferViewFieldAccess(&test_access)) {
-        return false;
-      }
-      if (!access.Equals(test_access)) return false;
-    }
-    return true;
-  }
-
   // Currently only handle numbers as a polymorphic case.
   // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber
   // instruction.
@@ -6289,22 +6220,21 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
 }
 
 
-HValue* HOptimizedGraphBuilder::BuildMonomorphicAccess(
-    PropertyAccessInfo* info, HValue* object, HValue* checked_object,
-    HValue* value, BailoutId ast_id, BailoutId return_id,
+HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
+    PropertyAccessInfo* info,
+    HValue* object,
+    HValue* checked_object,
+    HValue* value,
+    BailoutId ast_id,
+    BailoutId return_id,
     bool can_inline_accessor) {
+
   HObjectAccess access = HObjectAccess::ForMap();  // bogus default
   if (info->GetJSObjectFieldAccess(&access)) {
     DCHECK(info->IsLoad());
     return New<HLoadNamedField>(object, checked_object, access);
   }
 
-  if (info->GetJSArrayBufferViewFieldAccess(&access)) {
-    DCHECK(info->IsLoad());
-    return BuildArrayBufferViewFieldAccessor(
-        object, checked_object, FieldIndex::ForInObjectOffset(access.offset()));
-  }
-
   if (info->name().is_identical_to(isolate()->factory()->prototype_string()) &&
       info->map()->function_with_prototype()) {
     DCHECK(!info->map()->has_non_instance_prototype());
@@ -6454,9 +6384,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
 
     set_current_block(if_true);
 
-    HValue* access =
-        BuildMonomorphicAccess(&info, object, dependency, value, ast_id,
-                               return_id, FLAG_polymorphic_inlining);
+    HInstruction* access = BuildMonomorphicAccess(
+        &info, object, dependency, value, ast_id,
+        return_id, FLAG_polymorphic_inlining);
 
     HValue* result = NULL;
     switch (access_type) {
@@ -6471,10 +6401,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
     if (access == NULL) {
       if (HasStackOverflow()) return;
     } else {
-      if (access->IsInstruction()) {
-        HInstruction* instr = HInstruction::cast(access);
-        if (!instr->IsLinked()) AddInstruction(instr);
-      }
+      if (!access->IsLinked()) AddInstruction(access);
       if (!ast_context()->IsEffect()) Push(result);
     }
 
@@ -6568,13 +6495,13 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
   Handle<String> name = Handle<String>::cast(key->value());
   DCHECK(!name.is_null());
 
-  HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, object,
-                                    name, value, is_uninitialized);
-  if (access == NULL) return;
+  HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr,
+                                         object, name, value, is_uninitialized);
+  if (instr == NULL) return;
 
   if (!ast_context()->IsEffect()) Push(value);
-  if (access->IsInstruction()) AddInstruction(HInstruction::cast(access));
-  if (access->HasObservableSideEffects()) {
+  AddInstruction(instr);
+  if (instr->HasObservableSideEffects()) {
     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
   }
   if (!ast_context()->IsEffect()) Drop(1);
@@ -7323,18 +7250,16 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
         constant = isolate()->factory()->InternalizeString(
             Handle<String>::cast(constant));
       }
-      HValue* access =
+      HInstruction* instr =
           BuildNamedAccess(access_type, ast_id, return_id, expr, obj,
                            Handle<String>::cast(constant), val, false);
-      if (access == NULL || access->IsPhi() ||
-          HInstruction::cast(access)->IsLinked()) {
+      if (instr == NULL || instr->IsLinked()) {
         *has_side_effects = false;
       } else {
-        HInstruction* instr = HInstruction::cast(access);
         AddInstruction(instr);
         *has_side_effects = instr->HasObservableSideEffects();
       }
-      return access;
+      return instr;
     }
   }
 
@@ -7493,9 +7418,14 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
 }
 
 
-HValue* HOptimizedGraphBuilder::BuildNamedAccess(
-    PropertyAccessType access, BailoutId ast_id, BailoutId return_id,
-    Expression* expr, HValue* object, Handle<String> name, HValue* value,
+HInstruction* HOptimizedGraphBuilder::BuildNamedAccess(
+    PropertyAccessType access,
+    BailoutId ast_id,
+    BailoutId return_id,
+    Expression* expr,
+    HValue* object,
+    Handle<String> name,
+    HValue* value,
     bool is_uninitialized) {
   SmallMapList* maps;
   ComputeReceiverTypes(expr, object, &maps, zone());
@@ -7551,11 +7481,9 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
     Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
     HValue* object = Pop();
 
-    HValue* value = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, object,
-                                     name, NULL, expr->IsUninitialized());
-    if (value == NULL) return;
-    if (value->IsPhi()) return ast_context()->ReturnValue(value);
-    instr = HInstruction::cast(value);
+    instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
+                             object, name, NULL, expr->IsUninitialized());
+    if (instr == NULL) return;
     if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
 
   } else {
@@ -9689,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());
   }
 }
 
@@ -9989,40 +9926,34 @@ void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
 
 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
     CallRuntime* expr) {
-  NoObservableSideEffectsScope scope(this);
   DCHECK(expr->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
-  HValue* view = Pop();
-
-  return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
-      view, nullptr,
-      FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset)));
+  HValue* buffer = Pop();
+  HInstruction* result = New<HLoadNamedField>(
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength());
+  return ast_context()->ReturnInstruction(result, expr->id());
 }
 
 
 void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
     CallRuntime* expr) {
-  NoObservableSideEffectsScope scope(this);
   DCHECK(expr->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
-  HValue* view = Pop();
-
-  return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
-      view, nullptr,
-      FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset)));
+  HValue* buffer = Pop();
+  HInstruction* result = New<HLoadNamedField>(
+      buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset());
+  return ast_context()->ReturnInstruction(result, expr->id());
 }
 
 
 void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
     CallRuntime* expr) {
-  NoObservableSideEffectsScope scope(this);
   DCHECK(expr->arguments()->length() == 1);
   CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
-  HValue* view = Pop();
-
-  return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
-      view, nullptr,
-      FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset)));
+  HValue* buffer = Pop();
+  HInstruction* result = New<HLoadNamedField>(
+      buffer, nullptr, HObjectAccess::ForJSTypedArrayLength());
+  return ast_context()->ReturnInstruction(result, expr->id());
 }
 
 
index 01f7107..8617d38 100644 (file)
@@ -1862,10 +1862,6 @@ class HGraphBuilder {
   HInstruction* BuildGetNativeContext();
   HInstruction* BuildGetScriptContext(int context_index);
   HInstruction* BuildGetArrayFunction();
-  HValue* BuildArrayBufferViewFieldAccessor(HValue* object,
-                                            HValue* checked_object,
-                                            FieldIndex index);
-
 
  protected:
   void SetSourcePosition(int position) {
@@ -2558,20 +2554,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
       return false;
     }
 
-    bool IsJSArrayBufferViewFieldAccessor() {
-      int offset;  // unused
-      return Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset);
-    }
-
-    bool GetJSArrayBufferViewFieldAccess(HObjectAccess* access) {
-      int offset;
-      if (Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset)) {
-        *access = HObjectAccess::ForMapAndOffset(map_, offset);
-        return true;
-      }
-      return false;
-    }
-
     bool has_holder() { return !holder_.is_null(); }
     bool IsLoad() const { return access_type_ == LOAD; }
 
@@ -2696,15 +2678,22 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
     PropertyDetails details_;
   };
 
-  HValue* BuildMonomorphicAccess(PropertyAccessInfo* info, HValue* object,
-                                 HValue* checked_object, HValue* value,
-                                 BailoutId ast_id, BailoutId return_id,
-                                 bool can_inline_accessor = true);
-
-  HValue* BuildNamedAccess(PropertyAccessType access, BailoutId ast_id,
-                           BailoutId reutrn_id, Expression* expr,
-                           HValue* object, Handle<String> name, HValue* value,
-                           bool is_uninitialized = false);
+  HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
+                                       HValue* object,
+                                       HValue* checked_object,
+                                       HValue* value,
+                                       BailoutId ast_id,
+                                       BailoutId return_id,
+                                       bool can_inline_accessor = true);
+
+  HInstruction* BuildNamedAccess(PropertyAccessType access,
+                                 BailoutId ast_id,
+                                 BailoutId reutrn_id,
+                                 Expression* expr,
+                                 HValue* object,
+                                 Handle<String> name,
+                                 HValue* value,
+                                 bool is_uninitialized = false);
 
   void HandlePolymorphicCallNamed(Call* expr,
                                   HValue* receiver,
index 699e90f..a6ae92a 100644 (file)
@@ -1227,12 +1227,6 @@ Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup,
         FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
         return SimpleFieldLoad(index);
       }
-      if (Accessors::IsJSArrayBufferViewFieldAccessor(map, lookup->name(),
-                                                      &object_offset)) {
-        FieldIndex index = FieldIndex::ForInObjectOffset(object_offset, *map);
-        ArrayBufferViewLoadFieldStub stub(isolate(), index);
-        return stub.GetCode();
-      }
 
       Handle<Object> accessors = lookup->GetAccessors();
       if (accessors->IsExecutableAccessorInfo()) {
index eebf00b..3495ad6 100644 (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());
 }
index 2e77f92..e9db3c5 100644 (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)
 
index f373329..4909c95 100644 (file)
@@ -13333,17 +13333,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)
 
@@ -15209,183 +15209,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);
 }
@@ -16947,7 +16932,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()));
 }
 
 
@@ -16991,6 +16994,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);
 
index 68db075..bfec772 100644 (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;
 
- 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<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.
index 02b5579..a1aacd7 100644 (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();
 }
 
index 26f8da3..bf0a4eb 100644 (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.
index 4206736..857f817 100644 (file)
@@ -13831,10 +13831,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());
@@ -13848,7 +13847,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,
index 1d998d1..4b78644 100644 (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);
index c0d2950..8c5459a 100644 (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();
+    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();
+  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();
+    CHECK_EQ(1, CountViews(isolate->heap(), *iab));
+    Handle<JSArrayBufferView> ita1 = v8::Utils::OpenHandle(*ta1);
+    CHECK(HasViewInWeakList(isolate->heap(), *iab, *ita1));
+  }
+  isolate->heap()->CollectAllGarbage();
+
+  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();
+
+    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();
+
+    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");
+}