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
map->prototype()) {
return false;
}
- return
- CheckForName(name, isolate->factory()->length_string(),
- JSTypedArray::kLengthOffset, object_offset) ||
- CheckForName(name, isolate->factory()->byte_length_string(),
- JSTypedArray::kByteLengthOffset, object_offset) ||
- CheckForName(name, isolate->factory()->byte_offset_string(),
- JSTypedArray::kByteOffsetOffset, object_offset);
- case JS_ARRAY_BUFFER_TYPE:
- return
- CheckForName(name, isolate->factory()->byte_length_string(),
- JSArrayBuffer::kByteLengthOffset, object_offset);
+ 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_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;
}
}
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,
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(
V(VectorRawKeyedLoad) \
V(VectorRawLoad) \
/* IC Handler stubs */ \
+ V(ArrayBufferViewLoadField) \
V(LoadConstant) \
V(LoadField) \
V(KeyedLoadSloppyArguments) \
};
+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)
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
- if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
+ if (key < ElementsAccessorSubclass::GetCapacityImpl(obj, backing_store)) {
return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
} else {
return backing_store->GetIsolate()->factory()->the_hole_value();
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
- if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
+ if (key >= ElementsAccessorSubclass::GetCapacityImpl(obj, backing_store)) {
return ABSENT;
}
return
// Optimize if 'other' is empty.
// We cannot optimize if 'this' is empty, as other may have holes.
- uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
+ uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(holder, from);
if (len1 == 0) return to;
Isolate* isolate = from->GetIsolate();
}
protected:
- static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
+ static uint32_t GetCapacityImpl(Handle<JSObject> holder,
+ Handle<FixedArrayBase> backing_store) {
return backing_store->length();
}
- uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) final {
- return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
+ uint32_t GetCapacity(Handle<JSObject> holder,
+ Handle<FixedArrayBase> backing_store) final {
+ return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
}
static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> backing_store,
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
- if (key < AccessorClass::GetCapacityImpl(backing_store)) {
+ if (key < AccessorClass::GetCapacityImpl(obj, backing_store)) {
return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
} else {
return backing_store->GetIsolate()->factory()->undefined_value();
Handle<JSObject> obj,
uint32_t key,
Handle<FixedArrayBase> backing_store) {
- return
- key < AccessorClass::GetCapacityImpl(backing_store)
- ? NONE : ABSENT;
+ return key < AccessorClass::GetCapacityImpl(obj, backing_store) ? NONE
+ : ABSENT;
}
MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
static bool HasElementImpl(Handle<JSObject> holder, uint32_t key,
Handle<FixedArrayBase> backing_store) {
- uint32_t capacity =
- AccessorClass::GetCapacityImpl(backing_store);
+ uint32_t capacity = AccessorClass::GetCapacityImpl(holder, 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();
+ }
};
UNREACHABLE();
}
- static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
+ static uint32_t GetCapacityImpl(Handle<JSObject> holder,
+ 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(arguments));
+ ForArray(arguments)->GetCapacity(holder, arguments));
}
static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> dict,
protected:
friend class SloppyArgumentsElementsAccessor;
- virtual uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) = 0;
+ virtual uint32_t GetCapacity(Handle<JSObject> holder,
+ 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
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
}
}
+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,
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);
}
+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,
}
+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) {
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);
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,
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;
chunks_queued_for_free_(NULL),
gc_callbacks_depth_(0),
deserialization_complete_(false),
- concurrent_sweeping_enabled_(false),
- migration_failure_(false),
- previous_migration_failure_(false) {
+ concurrent_sweeping_enabled_(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.
// 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);
}
void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
ProcessArrayBuffers(retainer, false);
- ProcessNewArrayBufferViews(retainer);
ProcessNativeContexts(retainer);
ProcessAllocationSites(retainer);
}
void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) {
ProcessArrayBuffers(retainer, true);
- ProcessNewArrayBufferViews(retainer);
ProcessNativeContexts(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);
}
-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;) {
if (SemiSpaceCopyObject<alignment>(map, slot, object, object_size)) {
return;
}
- heap->set_migration_failure(true);
}
if (PromoteObject<object_contents, alignment>(map, slot, object,
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;
}
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;
}
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.
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.
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
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;
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 + 2 * kPointerSize),
+ heap, HeapObject::RawField(object,
+ JSArrayBuffer::kWeakNextOffset + kPointerSize),
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
return JSArrayBuffer::kSizeWithInternalFields;
}
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;
}
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;
}
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 + 2 * kPointerSize),
+ heap, HeapObject::RawField(object,
+ JSArrayBuffer::kWeakNextOffset + kPointerSize),
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
}
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));
}
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));
}
}
-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();
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);
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) {
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,
JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
}
- static HObjectAccess ForExternalArrayExternalPointer() {
+ static HObjectAccess ForJSArrayBufferFlag() {
return HObjectAccess::ForObservableJSObjectOffset(
- ExternalArray::kExternalPointerOffset, Representation::External());
+ JSArrayBuffer::kFlagOffset, Representation::Smi());
}
- static HObjectAccess ForJSArrayBufferViewWeakNext() {
- return HObjectAccess::ForObservableJSObjectOffset(
- JSArrayBufferView::kWeakNextOffset);
- }
-
- static HObjectAccess ForJSArrayBufferWeakFirstView() {
+ static HObjectAccess ForExternalArrayExternalPointer() {
return HObjectAccess::ForObservableJSObjectOffset(
- JSArrayBuffer::kWeakFirstViewOffset);
+ ExternalArray::kExternalPointerOffset, Representation::External());
}
static HObjectAccess ForJSArrayBufferViewBuffer() {
}
if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
NoObservableSideEffectsScope no_effects(this);
+ if (IsExternalArrayElementsKind(elements_kind)) {
+ 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();
+ }
IfBuilder length_checker(this);
length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT);
length_checker.Then();
length_checker.End();
return result;
} else {
+ if (IsExternalArrayElementsKind(elements_kind)) {
+ HInstruction* buffer =
+ Add<HLoadNamedField>(checked_object, nullptr,
+ HObjectAccess::ForJSArrayBufferViewBuffer());
+ HInstruction* buffer_length = Add<HLoadNamedField>(
+ buffer, nullptr, HObjectAccess::ForJSArrayBufferByteLength());
+ Add<HBoundsCheck>(graph()->GetConstant0(), buffer_length);
+ }
DCHECK(store_mode == STANDARD_STORE);
checked_key = Add<HBoundsCheck>(key, length);
return AddElementAccess(
}
+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,
Handle<Map> map = property->GetReceiverType();
Handle<String> name = key->AsPropertyName();
- HInstruction* store;
+ HValue* store;
if (map.is_null()) {
// If we don't know the monomorphic type, do a generic store.
CHECK_ALIVE(store = BuildNamedGeneric(
STORE, NULL, literal, name, value));
}
}
- AddInstruction(store);
+ if (store->IsInstruction()) {
+ AddInstruction(HInstruction::cast(store));
+ }
DCHECK(store->HasObservableSideEffects());
Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
} else {
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();
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.
}
-HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess(
- PropertyAccessInfo* info,
- HValue* object,
- HValue* checked_object,
- HValue* value,
- BailoutId ast_id,
- BailoutId return_id,
+HValue* 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());
set_current_block(if_true);
- HInstruction* access = BuildMonomorphicAccess(
- &info, object, dependency, value, ast_id,
- return_id, FLAG_polymorphic_inlining);
+ HValue* access =
+ BuildMonomorphicAccess(&info, object, dependency, value, ast_id,
+ return_id, FLAG_polymorphic_inlining);
HValue* result = NULL;
switch (access_type) {
if (access == NULL) {
if (HasStackOverflow()) return;
} else {
- if (!access->IsLinked()) AddInstruction(access);
+ if (access->IsInstruction()) {
+ HInstruction* instr = HInstruction::cast(access);
+ if (!instr->IsLinked()) AddInstruction(instr);
+ }
if (!ast_context()->IsEffect()) Push(result);
}
Handle<String> name = Handle<String>::cast(key->value());
DCHECK(!name.is_null());
- HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr,
- object, name, value, is_uninitialized);
- if (instr == NULL) return;
+ HValue* access = BuildNamedAccess(STORE, ast_id, return_id, expr, object,
+ name, value, is_uninitialized);
+ if (access == NULL) return;
if (!ast_context()->IsEffect()) Push(value);
- AddInstruction(instr);
- if (instr->HasObservableSideEffects()) {
+ if (access->IsInstruction()) AddInstruction(HInstruction::cast(access));
+ if (access->HasObservableSideEffects()) {
Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
}
if (!ast_context()->IsEffect()) Drop(1);
constant = isolate()->factory()->InternalizeString(
Handle<String>::cast(constant));
}
- HInstruction* instr =
+ HValue* access =
BuildNamedAccess(access_type, ast_id, return_id, expr, obj,
Handle<String>::cast(constant), val, false);
- if (instr == NULL || instr->IsLinked()) {
+ if (access == NULL || access->IsPhi() ||
+ HInstruction::cast(access)->IsLinked()) {
*has_side_effects = false;
} else {
+ HInstruction* instr = HInstruction::cast(access);
AddInstruction(instr);
*has_side_effects = instr->HasObservableSideEffects();
}
- return instr;
+ return access;
}
}
}
-HInstruction* HOptimizedGraphBuilder::BuildNamedAccess(
- PropertyAccessType access,
- BailoutId ast_id,
- BailoutId return_id,
- Expression* expr,
- HValue* object,
- Handle<String> name,
- HValue* value,
+HValue* 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());
Handle<String> name = expr->key()->AsLiteral()->AsPropertyName();
HValue* object = Pop();
- instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr,
- object, name, NULL, expr->IsUninitialized());
- if (instr == NULL) return;
+ 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);
if (instr->IsLinked()) return ast_context()->ReturnValue(instr);
} else {
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());
}
}
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteLength(
CallRuntime* expr) {
+ NoObservableSideEffectsScope scope(this);
DCHECK(expr->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
- HValue* buffer = Pop();
- HInstruction* result = New<HLoadNamedField>(
- buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteLength());
- return ast_context()->ReturnInstruction(result, expr->id());
+ HValue* view = Pop();
+
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
+ view, nullptr,
+ FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteLengthOffset)));
}
void HOptimizedGraphBuilder::GenerateArrayBufferViewGetByteOffset(
CallRuntime* expr) {
+ NoObservableSideEffectsScope scope(this);
DCHECK(expr->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
- HValue* buffer = Pop();
- HInstruction* result = New<HLoadNamedField>(
- buffer, nullptr, HObjectAccess::ForJSArrayBufferViewByteOffset());
- return ast_context()->ReturnInstruction(result, expr->id());
+ HValue* view = Pop();
+
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
+ view, nullptr,
+ FieldIndex::ForInObjectOffset(JSArrayBufferView::kByteOffsetOffset)));
}
void HOptimizedGraphBuilder::GenerateTypedArrayGetLength(
CallRuntime* expr) {
+ NoObservableSideEffectsScope scope(this);
DCHECK(expr->arguments()->length() == 1);
CHECK_ALIVE(VisitForValue(expr->arguments()->at(0)));
- HValue* buffer = Pop();
- HInstruction* result = New<HLoadNamedField>(
- buffer, nullptr, HObjectAccess::ForJSTypedArrayLength());
- return ast_context()->ReturnInstruction(result, expr->id());
+ HValue* view = Pop();
+
+ return ast_context()->ReturnValue(BuildArrayBufferViewFieldAccessor(
+ view, nullptr,
+ FieldIndex::ForInObjectOffset(JSTypedArray::kLengthOffset)));
}
HInstruction* BuildGetNativeContext();
HInstruction* BuildGetScriptContext(int context_index);
HInstruction* BuildGetArrayFunction();
+ HValue* BuildArrayBufferViewFieldAccessor(HValue* object,
+ HValue* checked_object,
+ FieldIndex index);
+
protected:
void SetSourcePosition(int position) {
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; }
PropertyDetails details_;
};
- 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);
+ 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);
void HandlePolymorphicCallNamed(Call* expr,
HValue* receiver,
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()) {
CHECK(buffer()->IsJSArrayBuffer() || buffer()->IsUndefined()
|| buffer() == Smi::FromInt(0));
- VerifyPointer(byte_offset());
- CHECK(byte_offset()->IsSmi() || byte_offset()->IsHeapNumber()
- || byte_offset()->IsUndefined());
+ VerifyPointer(raw_byte_offset());
+ CHECK(raw_byte_offset()->IsSmi() || raw_byte_offset()->IsHeapNumber() ||
+ raw_byte_offset()->IsUndefined());
- VerifyPointer(byte_length());
- CHECK(byte_length()->IsSmi() || byte_length()->IsHeapNumber()
- || byte_length()->IsUndefined());
+ VerifyPointer(raw_byte_length());
+ CHECK(raw_byte_length()->IsSmi() || raw_byte_length()->IsHeapNumber() ||
+ raw_byte_length()->IsUndefined());
}
void JSTypedArray::JSTypedArrayVerify() {
CHECK(IsJSTypedArray());
JSArrayBufferViewVerify();
- VerifyPointer(length());
- CHECK(length()->IsSmi() || length()->IsHeapNumber()
- || length()->IsUndefined());
+ VerifyPointer(raw_length());
+ CHECK(raw_length()->IsSmi() || raw_length()->IsHeapNumber() ||
+ raw_length()->IsUndefined());
VerifyPointer(elements());
}
template <class Traits>
Handle<Object> FixedTypedArray<Traits>::SetValue(
- Handle<FixedTypedArray<Traits> > array,
- uint32_t index,
- Handle<Object> value) {
+ Handle<JSObject> holder, Handle<FixedTypedArray<Traits> > array,
+ uint32_t index, Handle<Object> value) {
ElementType cast_value = Traits::defaultValue();
- 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());
+ 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);
}
- array->set(index, cast_value);
}
return Traits::ToHandle(array->GetIsolate(), cast_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)
-ACCESSORS(JSArrayBuffer, weak_first_view, Object, kWeakFirstViewOffset)
+
+
+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(JSArrayBufferView, buffer, Object, kBufferOffset)
-ACCESSORS(JSArrayBufferView, byte_offset, Object, kByteOffsetOffset)
-ACCESSORS(JSArrayBufferView, byte_length, Object, kByteLengthOffset)
-ACCESSORS(JSArrayBufferView, weak_next, Object, kWeakNextOffset)
-ACCESSORS(JSTypedArray, length, Object, kLengthOffset)
+#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(JSRegExp, data, Object, kDataOffset)
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(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); \
- }
+#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); \
+ }
TYPED_ARRAYS(TYPED_ARRAY_CASE)
Handle<Object> ExternalUint8ClampedArray::SetValue(
- Handle<ExternalUint8ClampedArray> array,
- uint32_t index,
- Handle<Object> value) {
+ Handle<JSObject> holder, Handle<ExternalUint8ClampedArray> array,
+ uint32_t index, Handle<Object> value) {
uint8_t clamped_value = 0;
- 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;
+ 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));
+ }
} else {
- // Other doubles are rounded to the nearest integer.
- clamped_value = static_cast<uint8_t>(lrint(double_value));
+ // Clamp undefined to zero (default). All other types have been
+ // converted to a number type further up in the call chain.
+ DCHECK(value->IsUndefined());
}
- } 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);
}
- 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<ExternalArrayClass> receiver,
- uint32_t index,
- Handle<Object> value) {
+ Isolate* isolate, Handle<JSObject> holder,
+ Handle<ExternalArrayClass> receiver, uint32_t index, Handle<Object> value) {
ValueType cast_value = 0;
- 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());
+ 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);
}
- receiver->set(index, cast_value);
}
return isolate->factory()->NewNumberFromInt(cast_value);
}
-Handle<Object> ExternalInt8Array::SetValue(Handle<ExternalInt8Array> array,
+Handle<Object> ExternalInt8Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt8Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt8Array, int8_t>(
- array->GetIsolate(), array, index, value);
+ array->GetIsolate(), holder, array, index, value);
}
-Handle<Object> ExternalUint8Array::SetValue(Handle<ExternalUint8Array> array,
+Handle<Object> ExternalUint8Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint8Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalUint8Array, uint8_t>(
- array->GetIsolate(), array, index, value);
+ array->GetIsolate(), holder, array, index, value);
}
-Handle<Object> ExternalInt16Array::SetValue(Handle<ExternalInt16Array> array,
+Handle<Object> ExternalInt16Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt16Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt16Array, int16_t>(
- array->GetIsolate(), array, index, value);
+ array->GetIsolate(), holder, array, index, value);
}
-Handle<Object> ExternalUint16Array::SetValue(Handle<ExternalUint16Array> array,
+Handle<Object> ExternalUint16Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint16Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalUint16Array, uint16_t>(
- array->GetIsolate(), array, index, value);
+ array->GetIsolate(), holder, array, index, value);
}
-Handle<Object> ExternalInt32Array::SetValue(Handle<ExternalInt32Array> array,
+Handle<Object> ExternalInt32Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt32Array> array,
uint32_t index,
Handle<Object> value) {
return ExternalArrayIntSetter<ExternalInt32Array, int32_t>(
- array->GetIsolate(), array, index, value);
+ array->GetIsolate(), holder, array, index, value);
}
-Handle<Object> ExternalUint32Array::SetValue(
- Handle<ExternalUint32Array> array,
- uint32_t index,
- Handle<Object> value) {
+Handle<Object> ExternalUint32Array::SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint32Array> array,
+ uint32_t index,
+ Handle<Object> value) {
uint32_t cast_value = 0;
- 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());
+ 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);
}
- array->set(index, cast_value);
}
return array->GetIsolate()->factory()->NewNumberFromUint(cast_value);
}
Handle<Object> ExternalFloat32Array::SetValue(
- Handle<ExternalFloat32Array> array,
- uint32_t index,
+ Handle<JSObject> holder, Handle<ExternalFloat32Array> array, uint32_t index,
Handle<Object> value) {
float cast_value = std::numeric_limits<float>::quiet_NaN();
- 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());
+ 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);
}
- array->set(index, cast_value);
}
return array->GetIsolate()->factory()->NewNumber(cast_value);
}
Handle<Object> ExternalFloat64Array::SetValue(
- Handle<ExternalFloat64Array> array,
- uint32_t index,
+ Handle<JSObject> holder, Handle<ExternalFloat64Array> array, uint32_t index,
Handle<Object> value) {
double double_value = std::numeric_limits<double>::quiet_NaN();
- 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());
+ 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);
}
- array->set(index, double_value);
}
return array->GetIsolate()->factory()->NewNumber(double_value);
}
CHECK(is_external());
set_backing_store(NULL);
set_byte_length(Smi::FromInt(0));
-}
-
-
-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()));
+ set_was_neutered(true);
}
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);
// 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<ExternalUint8ClampedArray> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint8ClampedArray> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalUint8ClampedArray)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalInt8Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt8Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalInt8Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalUint8Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint8Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalUint8Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalInt16Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt16Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalInt16Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalUint16Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint16Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalUint16Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalInt32Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalInt32Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalInt32Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalUint32Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalUint32Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalUint32Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalFloat32Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalFloat32Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalFloat32Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<ExternalFloat64Array> array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<ExternalFloat64Array> array,
+ uint32_t index, Handle<Object> value);
DECLARE_CAST(ExternalFloat64Array)
// This accessor applies the correct conversion from Smi, HeapNumber
// and undefined.
- static Handle<Object> SetValue(Handle<FixedTypedArray<Traits> > array,
- uint32_t index,
- Handle<Object> value);
+ static Handle<Object> SetValue(Handle<JSObject> holder,
+ Handle<FixedTypedArray<Traits> > array,
+ uint32_t index, Handle<Object> value);
DECLARE_PRINTER(FixedTypedArray)
DECLARE_VERIFIER(FixedTypedArray)
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.
static const int kByteLengthOffset = kBackingStoreOffset + kPointerSize;
static const int kFlagOffset = kByteLengthOffset + kPointerSize;
static const int kWeakNextOffset = kFlagOffset + kPointerSize;
- static const int kWeakFirstViewOffset = kWeakNextOffset + kPointerSize;
- static const int kSize = kWeakFirstViewOffset + kPointerSize;
+ static const int kSize = kWeakNextOffset + 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);
};
// [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 kWeakNextOffset = kByteLengthOffset + kPointerSize;
- static const int kViewSize = kWeakNextOffset + kPointerSize;
-
- protected:
- void NeuterView();
+ static const int kViewSize = kByteLengthOffset + kPointerSize;
private:
+#ifdef VERIFY_HEAP
+ DECL_ACCESSORS(raw_byte_offset, Object)
+ DECL_ACCESSORS(raw_byte_length, Object)
+#endif
+
DISALLOW_IMPLICIT_CONSTRUCTORS(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();
private:
static Handle<JSArrayBuffer> MaterializeArrayBuffer(
Handle<JSTypedArray> typed_array);
+#ifdef VERIFY_HEAP
+ DECL_ACCESSORS(raw_length, Object)
+#endif
DISALLOW_IMPLICIT_CONSTRUCTORS(JSTypedArray);
};
class JSDataView: public JSArrayBufferView {
public:
- // Only neuters this DataView
- void Neuter();
-
DECLARE_CAST(JSDataView)
// Dispatched behavior.
->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());
}
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();
}
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);
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);
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()));
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();
}
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.
i::Factory* factory = isolate->factory();
v8::HandleScope scope(context->GetIsolate());
const int kElementCount = 260;
- i::Handle<FixedTypedArrayClass> fixed_array =
- i::Handle<FixedTypedArrayClass>::cast(
- factory->NewFixedTypedArray(kElementCount, array_type));
+ i::Handle<i::JSTypedArray> jsobj =
+ factory->NewJSTypedArray(elements_kind, kElementCount);
+ i::Handle<FixedTypedArrayClass> fixed_array(
+ FixedTypedArrayClass::cast(jsobj->elements()));
CHECK_EQ(FixedTypedArrayClass::kInstanceType,
fixed_array->map()->instance_type());
CHECK_EQ(kElementCount, fixed_array->length());
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::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);
+ v8::Handle<v8::Object> obj = v8::Utils::ToLocal(jsobj);
ObjectWithExternalArrayTestHelper<FixedTypedArrayClass, ElementType>(
context.local(), obj, kElementCount, array_type,
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);
}
-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;
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");
-}