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 Review URL: https://codereview.chromium.org/1093183004 Cr-Commit-Position: refs/heads/master@{#28029}
This commit is contained in:
parent
8aa7215246
commit
655b04637e
@ -78,6 +78,26 @@ 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
|
||||
@ -87,29 +107,19 @@ bool Accessors::IsJSObjectFieldAccessor(Handle<Map> map, Handle<Name> name,
|
||||
map->prototype()) {
|
||||
return false;
|
||||
}
|
||||
return
|
||||
CheckForName(name, isolate->factory()->length_string(),
|
||||
JSTypedArray::kLengthOffset, object_offset) ||
|
||||
CheckForName(name, isolate->factory()->byte_length_string(),
|
||||
JSTypedArray::kByteLengthOffset, object_offset) ||
|
||||
CheckForName(name, isolate->factory()->byte_offset_string(),
|
||||
JSTypedArray::kByteOffsetOffset, object_offset);
|
||||
case JS_ARRAY_BUFFER_TYPE:
|
||||
return
|
||||
CheckForName(name, isolate->factory()->byte_length_string(),
|
||||
JSArrayBuffer::kByteLengthOffset, object_offset);
|
||||
case JS_DATA_VIEW_TYPE:
|
||||
return
|
||||
CheckForName(name, isolate->factory()->byte_length_string(),
|
||||
JSDataView::kByteLengthOffset, object_offset) ||
|
||||
CheckForName(name, isolate->factory()->byte_offset_string(),
|
||||
JSDataView::kByteOffsetOffset, object_offset);
|
||||
default:
|
||||
if (map->instance_type() < FIRST_NONSTRING_TYPE) {
|
||||
return CheckForName(name, isolate->factory()->length_string(),
|
||||
String::kLengthOffset, 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);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -80,6 +80,14 @@ 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,
|
||||
|
@ -624,6 +624,18 @@ 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);
|
||||
|
@ -88,6 +88,7 @@ namespace internal {
|
||||
V(VectorRawKeyedLoad) \
|
||||
V(VectorRawLoad) \
|
||||
/* IC Handler stubs */ \
|
||||
V(ArrayBufferViewLoadField) \
|
||||
V(LoadConstant) \
|
||||
V(LoadField) \
|
||||
V(KeyedLoadSloppyArguments) \
|
||||
@ -973,6 +974,32 @@ 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)
|
||||
|
@ -620,7 +620,7 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
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();
|
||||
@ -638,7 +638,7 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
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
|
||||
@ -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(from);
|
||||
uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(holder, from);
|
||||
if (len1 == 0) return to;
|
||||
|
||||
Isolate* isolate = from->GetIsolate();
|
||||
@ -817,12 +817,14 @@ class ElementsAccessorBase : public ElementsAccessor {
|
||||
}
|
||||
|
||||
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,
|
||||
@ -1260,7 +1262,7 @@ class TypedElementsAccessor
|
||||
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();
|
||||
@ -1271,9 +1273,8 @@ class TypedElementsAccessor
|
||||
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(
|
||||
@ -1293,10 +1294,16 @@ class TypedElementsAccessor
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1632,12 +1639,13 @@ class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
|
||||
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,
|
||||
|
@ -183,7 +183,8 @@ class ElementsAccessor {
|
||||
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
|
||||
|
@ -1825,9 +1825,38 @@ 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
|
||||
}
|
||||
|
||||
@ -1849,6 +1878,23 @@ 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,
|
||||
@ -1858,15 +1904,6 @@ 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);
|
||||
@ -1890,6 +1927,16 @@ 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,
|
||||
@ -1918,6 +1965,34 @@ 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) {
|
||||
|
@ -448,11 +448,17 @@ 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);
|
||||
|
@ -1175,8 +1175,6 @@ 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,
|
||||
@ -1570,9 +1568,6 @@ 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;
|
||||
|
@ -141,9 +141,7 @@ Heap::Heap()
|
||||
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.
|
||||
@ -705,13 +703,6 @@ 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);
|
||||
}
|
||||
|
||||
|
||||
@ -1687,7 +1678,6 @@ void Heap::UpdateReferencesInExternalStringTable(
|
||||
|
||||
void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
|
||||
ProcessArrayBuffers(retainer, false);
|
||||
ProcessNewArrayBufferViews(retainer);
|
||||
ProcessNativeContexts(retainer);
|
||||
ProcessAllocationSites(retainer);
|
||||
}
|
||||
@ -1695,7 +1685,6 @@ void Heap::ProcessAllWeakReferences(WeakObjectRetainer* retainer) {
|
||||
|
||||
void Heap::ProcessYoungWeakReferences(WeakObjectRetainer* retainer) {
|
||||
ProcessArrayBuffers(retainer, true);
|
||||
ProcessNewArrayBufferViews(retainer);
|
||||
ProcessNativeContexts(retainer);
|
||||
}
|
||||
|
||||
@ -1722,7 +1711,6 @@ 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);
|
||||
@ -1733,20 +1721,6 @@ 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;) {
|
||||
@ -2178,7 +2152,6 @@ 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,
|
||||
@ -5403,7 +5376,6 @@ 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;
|
||||
}
|
||||
|
@ -883,13 +883,6 @@ 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;
|
||||
}
|
||||
@ -1496,18 +1489,6 @@ 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.
|
||||
|
||||
@ -1682,11 +1663,6 @@ 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.
|
||||
@ -2017,7 +1993,6 @@ 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
|
||||
@ -2177,13 +2152,6 @@ 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;
|
||||
|
@ -80,14 +80,12 @@ 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 + 2 * kPointerSize),
|
||||
heap, HeapObject::RawField(object,
|
||||
JSArrayBuffer::kWeakNextOffset + kPointerSize),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
|
||||
return JSArrayBuffer::kSizeWithInternalFields;
|
||||
}
|
||||
@ -99,10 +97,6 @@ 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;
|
||||
}
|
||||
@ -114,10 +108,6 @@ 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;
|
||||
}
|
||||
@ -540,15 +530,13 @@ 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 + 2 * kPointerSize),
|
||||
heap, HeapObject::RawField(object,
|
||||
JSArrayBuffer::kWeakNextOffset + kPointerSize),
|
||||
HeapObject::RawField(object, JSArrayBuffer::kSizeWithInternalFields));
|
||||
}
|
||||
|
||||
@ -559,10 +547,6 @@ 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));
|
||||
}
|
||||
|
||||
@ -573,10 +557,6 @@ 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));
|
||||
}
|
||||
|
||||
|
@ -243,56 +243,6 @@ 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();
|
||||
@ -394,22 +344,6 @@ 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) {
|
||||
@ -422,14 +356,6 @@ 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) {
|
||||
@ -465,11 +391,6 @@ 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,
|
||||
|
@ -6097,21 +6097,16 @@ class HObjectAccess final {
|
||||
JSArrayBuffer::kByteLengthOffset, Representation::Tagged());
|
||||
}
|
||||
|
||||
static HObjectAccess ForJSArrayBufferFlag() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSArrayBuffer::kFlagOffset, Representation::Smi());
|
||||
}
|
||||
|
||||
static HObjectAccess ForExternalArrayExternalPointer() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
ExternalArray::kExternalPointerOffset, Representation::External());
|
||||
}
|
||||
|
||||
static HObjectAccess ForJSArrayBufferViewWeakNext() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSArrayBufferView::kWeakNextOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForJSArrayBufferWeakFirstView() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSArrayBuffer::kWeakFirstViewOffset);
|
||||
}
|
||||
|
||||
static HObjectAccess ForJSArrayBufferViewBuffer() {
|
||||
return HObjectAccess::ForObservableJSObjectOffset(
|
||||
JSArrayBufferView::kBufferOffset);
|
||||
|
177
src/hydrogen.cc
177
src/hydrogen.cc
@ -2427,6 +2427,22 @@ 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 {
|
||||
@ -3155,6 +3171,44 @@ 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,
|
||||
@ -5654,7 +5708,7 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
|
||||
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(
|
||||
@ -5672,7 +5726,9 @@ void HOptimizedGraphBuilder::VisitObjectLiteral(ObjectLiteral* expr) {
|
||||
STORE, NULL, literal, name, value));
|
||||
}
|
||||
}
|
||||
AddInstruction(store);
|
||||
if (store->IsInstruction()) {
|
||||
AddInstruction(HInstruction::cast(store));
|
||||
}
|
||||
DCHECK(store->HasObservableSideEffects());
|
||||
Add<HSimulate>(key->id(), REMOVABLE_SIMULATE);
|
||||
} else {
|
||||
@ -6133,6 +6189,7 @@ 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();
|
||||
@ -6181,6 +6238,18 @@ 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.
|
||||
@ -6220,21 +6289,22 @@ bool HOptimizedGraphBuilder::PropertyAccessInfo::NeedsWrappingFor(
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
@ -6384,9 +6454,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
|
||||
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) {
|
||||
@ -6401,7 +6471,10 @@ void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess(
|
||||
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);
|
||||
}
|
||||
|
||||
@ -6495,13 +6568,13 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
|
||||
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);
|
||||
@ -7250,16 +7323,18 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7418,14 +7493,9 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
@ -7481,9 +7551,11 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
|
||||
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 {
|
||||
@ -9617,20 +9689,11 @@ 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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -9926,34 +9989,40 @@ void HOptimizedGraphBuilder::GenerateArrayBufferGetByteLength(
|
||||
|
||||
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)));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1862,6 +1862,10 @@ 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) {
|
||||
@ -2554,6 +2558,20 @@ 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; }
|
||||
|
||||
@ -2678,22 +2696,15 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
PropertyDetails details_;
|
||||
};
|
||||
|
||||
HInstruction* BuildMonomorphicAccess(PropertyAccessInfo* info,
|
||||
HValue* object,
|
||||
HValue* checked_object,
|
||||
HValue* value,
|
||||
BailoutId ast_id,
|
||||
BailoutId return_id,
|
||||
bool can_inline_accessor = true);
|
||||
HValue* 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* 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,
|
||||
|
@ -1227,6 +1227,12 @@ 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()) {
|
||||
|
@ -841,22 +841,22 @@ void JSArrayBufferView::JSArrayBufferViewVerify() {
|
||||
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());
|
||||
}
|
||||
|
@ -4377,23 +4377,25 @@ Handle<Object> FixedTypedArray<Traits>::get(
|
||||
|
||||
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);
|
||||
}
|
||||
@ -6455,15 +6457,71 @@ 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)
|
||||
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)
|
||||
|
||||
|
256
src/objects.cc
256
src/objects.cc
@ -13330,17 +13330,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(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)
|
||||
|
||||
@ -15206,168 +15206,183 @@ size_t JSTypedArray::element_size() {
|
||||
|
||||
|
||||
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;
|
||||
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 {
|
||||
clamped_value = static_cast<uint8_t>(int_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 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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
@ -16929,25 +16944,7 @@ void JSArrayBuffer::Neuter() {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -16991,15 +16988,6 @@ 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);
|
||||
|
||||
|
@ -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<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)
|
||||
|
||||
@ -4684,9 +4684,9 @@ class ExternalInt8Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4708,9 +4708,9 @@ class ExternalUint8Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4732,9 +4732,9 @@ class ExternalInt16Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4757,9 +4757,9 @@ class ExternalUint16Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4781,9 +4781,9 @@ class ExternalInt32Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4806,9 +4806,9 @@ class ExternalUint32Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4831,9 +4831,9 @@ class ExternalFloat32Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4856,9 +4856,9 @@ class ExternalFloat64Array: public ExternalArray {
|
||||
|
||||
// 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)
|
||||
|
||||
@ -4921,9 +4921,9 @@ class FixedTypedArray: public FixedTypedArrayBase {
|
||||
|
||||
// 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)
|
||||
@ -10244,15 +10244,14 @@ 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.
|
||||
@ -10263,18 +10262,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 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);
|
||||
};
|
||||
|
||||
@ -10290,23 +10289,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 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);
|
||||
};
|
||||
|
||||
@ -10316,9 +10315,6 @@ 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();
|
||||
@ -10339,6 +10335,9 @@ 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);
|
||||
};
|
||||
@ -10346,9 +10345,6 @@ class JSTypedArray: public JSArrayBufferView {
|
||||
|
||||
class JSDataView: public JSArrayBufferView {
|
||||
public:
|
||||
// Only neuters this DataView
|
||||
void Neuter();
|
||||
|
||||
DECLARE_CAST(JSDataView)
|
||||
|
||||
// Dispatched behavior.
|
||||
|
@ -63,7 +63,6 @@ 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());
|
||||
}
|
||||
|
||||
|
||||
@ -97,39 +96,6 @@ 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();
|
||||
}
|
||||
|
||||
@ -295,19 +261,10 @@ 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);
|
||||
@ -317,7 +274,6 @@ 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);
|
||||
@ -405,15 +361,6 @@ 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()));
|
||||
@ -586,15 +533,6 @@ 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();
|
||||
}
|
||||
|
||||
|
@ -567,8 +567,6 @@ 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.
|
||||
|
@ -13831,9 +13831,10 @@ static void FixedTypedArrayTestHelper(i::ExternalArrayType array_type,
|
||||
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());
|
||||
@ -13847,12 +13848,7 @@ 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::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,
|
||||
|
@ -2577,9 +2577,6 @@ 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);
|
||||
|
@ -62,87 +62,6 @@ 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;
|
||||
@ -203,217 +122,3 @@ 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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user