[typedarray] Move JSArrayBuffer functionality to js-array-buffer.cc
This is a cleanup CL that is preparation for making the byte length and offsets of typed arrays into unboxed size_t fields. R=mstarzinger@chromium.org BUG=v8:7881 Change-Id: Iee8bb2142124c88c71cec7343149ae3f08b40c6c Reviewed-on: https://chromium-review.googlesource.com/1179829 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#55196}
This commit is contained in:
parent
2b89727539
commit
b11cbbc6d5
1
BUILD.gn
1
BUILD.gn
@ -2161,6 +2161,7 @@ v8_source_set("v8_base") {
|
||||
"src/objects/intl-objects.cc",
|
||||
"src/objects/intl-objects.h",
|
||||
"src/objects/js-array-buffer-inl.h",
|
||||
"src/objects/js-array-buffer.cc",
|
||||
"src/objects/js-array-buffer.h",
|
||||
"src/objects/js-array-inl.h",
|
||||
"src/objects/js-array.h",
|
||||
|
303
src/objects.cc
303
src/objects.cc
@ -16878,128 +16878,6 @@ uint32_t HashTable<Derived, Shape>::FindInsertionEntry(uint32_t hash) {
|
||||
return entry;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
|
||||
Handle<Object>* index) {
|
||||
DCHECK(s->IsString() || s->IsSmi());
|
||||
|
||||
Handle<Object> result;
|
||||
if (s->IsSmi()) {
|
||||
result = s;
|
||||
} else {
|
||||
result = String::ToNumber(isolate, Handle<String>::cast(s));
|
||||
if (!result->IsMinusZero()) {
|
||||
Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
|
||||
// Avoid treating strings like "2E1" and "20" as the same key.
|
||||
if (!str->SameValue(*s)) return false;
|
||||
}
|
||||
}
|
||||
*index = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
// ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
|
||||
// static
|
||||
Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
|
||||
Handle<JSTypedArray> o,
|
||||
Handle<Object> key,
|
||||
PropertyDescriptor* desc,
|
||||
ShouldThrow should_throw) {
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
DCHECK(key->IsName() || key->IsNumber());
|
||||
// 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
|
||||
// 3. If Type(P) is String, then
|
||||
if (key->IsString() || key->IsSmi()) {
|
||||
// 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
|
||||
// 3b. If numericIndex is not undefined, then
|
||||
Handle<Object> numeric_index;
|
||||
if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
|
||||
// 3b i. If IsInteger(numericIndex) is false, return false.
|
||||
// 3b ii. If numericIndex = -0, return false.
|
||||
// 3b iii. If numericIndex < 0, return false.
|
||||
// FIXME: the standard allows up to 2^53 elements.
|
||||
uint32_t index;
|
||||
if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
|
||||
}
|
||||
// 3b iv. Let length be O.[[ArrayLength]].
|
||||
uint32_t length = o->length()->Number();
|
||||
// 3b v. If numericIndex ≥ length, return false.
|
||||
if (index >= length) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
|
||||
}
|
||||
// 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
|
||||
if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kRedefineDisallowed, key));
|
||||
}
|
||||
// 3b vii. If Desc has a [[Configurable]] field and if
|
||||
// Desc.[[Configurable]] is true, return false.
|
||||
// 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
|
||||
// is false, return false.
|
||||
// 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
|
||||
// false, return false.
|
||||
if ((desc->has_configurable() && desc->configurable()) ||
|
||||
(desc->has_enumerable() && !desc->enumerable()) ||
|
||||
(desc->has_writable() && !desc->writable())) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kRedefineDisallowed, key));
|
||||
}
|
||||
// 3b x. If Desc has a [[Value]] field, then
|
||||
// 3b x 1. Let value be Desc.[[Value]].
|
||||
// 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
|
||||
if (desc->has_value()) {
|
||||
if (!desc->has_configurable()) desc->set_configurable(false);
|
||||
if (!desc->has_enumerable()) desc->set_enumerable(true);
|
||||
if (!desc->has_writable()) desc->set_writable(true);
|
||||
Handle<Object> value = desc->value();
|
||||
RETURN_ON_EXCEPTION_VALUE(isolate,
|
||||
SetOwnElementIgnoreAttributes(
|
||||
o, index, value, desc->ToAttributes()),
|
||||
Nothing<bool>());
|
||||
}
|
||||
// 3b xi. Return true.
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
// 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
|
||||
return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
|
||||
}
|
||||
|
||||
ExternalArrayType JSTypedArray::type() {
|
||||
switch (elements()->map()->instance_type()) {
|
||||
#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype) \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
return kExternal##Type##Array;
|
||||
|
||||
TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
|
||||
#undef INSTANCE_TYPE_TO_ARRAY_TYPE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t JSTypedArray::element_size() {
|
||||
switch (elements()->map()->instance_type()) {
|
||||
#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
return sizeof(ctype);
|
||||
|
||||
TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
|
||||
#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void JSGlobalObject::InvalidatePropertyCell(Handle<JSGlobalObject> global,
|
||||
Handle<Name> name) {
|
||||
// Regardless of whether the property is there or not invalidate
|
||||
@ -18653,187 +18531,6 @@ Handle<String> JSMessageObject::GetSourceLine() const {
|
||||
return isolate->factory()->NewSubString(src, info.line_start, info.line_end);
|
||||
}
|
||||
|
||||
void JSArrayBuffer::Neuter() {
|
||||
CHECK(is_neuterable());
|
||||
CHECK(!was_neutered());
|
||||
CHECK(is_external());
|
||||
set_backing_store(nullptr);
|
||||
set_byte_length(Smi::kZero);
|
||||
set_was_neutered(true);
|
||||
set_is_neuterable(false);
|
||||
// Invalidate the neutering protector.
|
||||
Isolate* const isolate = GetIsolate();
|
||||
if (isolate->IsArrayBufferNeuteringIntact()) {
|
||||
isolate->InvalidateArrayBufferNeuteringProtector();
|
||||
}
|
||||
}
|
||||
|
||||
void JSArrayBuffer::StopTrackingWasmMemory(Isolate* isolate) {
|
||||
DCHECK(is_wasm_memory());
|
||||
isolate->wasm_engine()->memory_tracker()->ReleaseAllocation(isolate,
|
||||
backing_store());
|
||||
set_is_wasm_memory(false);
|
||||
}
|
||||
|
||||
void JSArrayBuffer::FreeBackingStoreFromMainThread() {
|
||||
if (allocation_base() == nullptr) {
|
||||
return;
|
||||
}
|
||||
FreeBackingStore(GetIsolate(), {allocation_base(), allocation_length(),
|
||||
backing_store(), is_wasm_memory()});
|
||||
// Zero out the backing store and allocation base to avoid dangling
|
||||
// pointers.
|
||||
set_backing_store(nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
|
||||
if (allocation.is_wasm_memory) {
|
||||
wasm::WasmMemoryTracker* memory_tracker =
|
||||
isolate->wasm_engine()->memory_tracker();
|
||||
if (!memory_tracker->FreeMemoryIfIsWasmMemory(isolate,
|
||||
allocation.backing_store)) {
|
||||
CHECK(FreePages(allocation.allocation_base, allocation.length));
|
||||
}
|
||||
} else {
|
||||
isolate->array_buffer_allocator()->Free(allocation.allocation_base,
|
||||
allocation.length);
|
||||
}
|
||||
}
|
||||
|
||||
void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
|
||||
set_bit_field(IsWasmMemory::update(bit_field(), is_wasm_memory));
|
||||
}
|
||||
|
||||
void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
|
||||
bool is_external, void* data, size_t byte_length,
|
||||
SharedFlag shared, bool is_wasm_memory) {
|
||||
DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
|
||||
v8::ArrayBuffer::kEmbedderFieldCount);
|
||||
for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
|
||||
array_buffer->SetEmbedderField(i, Smi::kZero);
|
||||
}
|
||||
array_buffer->set_bit_field(0);
|
||||
array_buffer->set_is_external(is_external);
|
||||
array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
|
||||
array_buffer->set_is_shared(shared == SharedFlag::kShared);
|
||||
array_buffer->set_is_wasm_memory(is_wasm_memory);
|
||||
|
||||
Handle<Object> heap_byte_length =
|
||||
isolate->factory()->NewNumberFromSize(byte_length);
|
||||
CHECK(heap_byte_length->IsSmi() || heap_byte_length->IsHeapNumber());
|
||||
array_buffer->set_byte_length(*heap_byte_length);
|
||||
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
|
||||
// are currently being constructed in the |ArrayBufferTracker|. The
|
||||
// registration method below handles the case of registering a buffer that has
|
||||
// already been promoted.
|
||||
array_buffer->set_backing_store(data);
|
||||
|
||||
if (data && !is_external) {
|
||||
isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
inline int ConvertToMb(size_t size) {
|
||||
return static_cast<int>(size / static_cast<size_t>(MB));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
|
||||
Isolate* isolate,
|
||||
size_t allocated_length,
|
||||
bool initialize, SharedFlag shared) {
|
||||
void* data;
|
||||
CHECK_NOT_NULL(isolate->array_buffer_allocator());
|
||||
if (allocated_length != 0) {
|
||||
if (allocated_length >= MB)
|
||||
isolate->counters()->array_buffer_big_allocations()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
if (shared == SharedFlag::kShared)
|
||||
isolate->counters()->shared_array_allocations()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
if (initialize) {
|
||||
data = isolate->array_buffer_allocator()->Allocate(allocated_length);
|
||||
} else {
|
||||
data = isolate->array_buffer_allocator()->AllocateUninitialized(
|
||||
allocated_length);
|
||||
}
|
||||
if (data == nullptr) {
|
||||
isolate->counters()->array_buffer_new_size_failures()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
const bool is_external = false;
|
||||
JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
|
||||
allocated_length, shared);
|
||||
return true;
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
|
||||
Handle<JSTypedArray> typed_array) {
|
||||
DCHECK(typed_array->is_on_heap());
|
||||
|
||||
Isolate* isolate = typed_array->GetIsolate();
|
||||
|
||||
DCHECK(IsFixedTypedArrayElementsKind(typed_array->GetElementsKind()));
|
||||
|
||||
Handle<FixedTypedArrayBase> fixed_typed_array(
|
||||
FixedTypedArrayBase::cast(typed_array->elements()), isolate);
|
||||
|
||||
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
|
||||
isolate);
|
||||
// This code does not know how to materialize from wasm buffers.
|
||||
DCHECK(!buffer->is_wasm_memory());
|
||||
|
||||
void* backing_store =
|
||||
isolate->array_buffer_allocator()->AllocateUninitialized(
|
||||
fixed_typed_array->DataSize());
|
||||
if (backing_store == nullptr) {
|
||||
isolate->heap()->FatalProcessOutOfMemory(
|
||||
"JSTypedArray::MaterializeArrayBuffer");
|
||||
}
|
||||
buffer->set_is_external(false);
|
||||
DCHECK(buffer->byte_length()->IsSmi() ||
|
||||
buffer->byte_length()->IsHeapNumber());
|
||||
DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
|
||||
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
|
||||
// are currently being constructed in the |ArrayBufferTracker|. The
|
||||
// registration method below handles the case of registering a buffer that has
|
||||
// already been promoted.
|
||||
buffer->set_backing_store(backing_store);
|
||||
// RegisterNewArrayBuffer expects a valid length for adjusting counters.
|
||||
isolate->heap()->RegisterNewArrayBuffer(*buffer);
|
||||
memcpy(buffer->backing_store(),
|
||||
fixed_typed_array->DataPtr(),
|
||||
fixed_typed_array->DataSize());
|
||||
Handle<FixedTypedArrayBase> new_elements =
|
||||
isolate->factory()->NewFixedTypedArrayWithExternalPointer(
|
||||
fixed_typed_array->length(), typed_array->type(),
|
||||
static_cast<uint8_t*>(buffer->backing_store()));
|
||||
|
||||
typed_array->set_elements(*new_elements);
|
||||
DCHECK(!typed_array->is_on_heap());
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
|
||||
if (!is_on_heap()) {
|
||||
Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
|
||||
GetIsolate());
|
||||
return array_buffer;
|
||||
}
|
||||
Handle<JSTypedArray> self(this, GetIsolate());
|
||||
return MaterializeArrayBuffer(self);
|
||||
}
|
||||
|
||||
Handle<PropertyCell> PropertyCell::InvalidateEntry(
|
||||
Isolate* isolate, Handle<GlobalDictionary> dictionary, int entry) {
|
||||
// Swap with a copy.
|
||||
|
310
src/objects/js-array-buffer.cc
Normal file
310
src/objects/js-array-buffer.cc
Normal file
@ -0,0 +1,310 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/objects/js-array-buffer.h"
|
||||
#include "src/objects/js-array-buffer-inl.h"
|
||||
#include "src/property-descriptor.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
bool CanonicalNumericIndexString(Isolate* isolate, Handle<Object> s,
|
||||
Handle<Object>* index) {
|
||||
DCHECK(s->IsString() || s->IsSmi());
|
||||
|
||||
Handle<Object> result;
|
||||
if (s->IsSmi()) {
|
||||
result = s;
|
||||
} else {
|
||||
result = String::ToNumber(isolate, Handle<String>::cast(s));
|
||||
if (!result->IsMinusZero()) {
|
||||
Handle<String> str = Object::ToString(isolate, result).ToHandleChecked();
|
||||
// Avoid treating strings like "2E1" and "20" as the same key.
|
||||
if (!str->SameValue(*s)) return false;
|
||||
}
|
||||
}
|
||||
*index = result;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int ConvertToMb(size_t size) {
|
||||
return static_cast<int>(size / static_cast<size_t>(MB));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void JSArrayBuffer::Neuter() {
|
||||
CHECK(is_neuterable());
|
||||
CHECK(!was_neutered());
|
||||
CHECK(is_external());
|
||||
set_backing_store(nullptr);
|
||||
set_byte_length(Smi::kZero);
|
||||
set_was_neutered(true);
|
||||
set_is_neuterable(false);
|
||||
// Invalidate the neutering protector.
|
||||
Isolate* const isolate = GetIsolate();
|
||||
if (isolate->IsArrayBufferNeuteringIntact()) {
|
||||
isolate->InvalidateArrayBufferNeuteringProtector();
|
||||
}
|
||||
}
|
||||
|
||||
void JSArrayBuffer::StopTrackingWasmMemory(Isolate* isolate) {
|
||||
DCHECK(is_wasm_memory());
|
||||
isolate->wasm_engine()->memory_tracker()->ReleaseAllocation(isolate,
|
||||
backing_store());
|
||||
set_is_wasm_memory(false);
|
||||
}
|
||||
|
||||
void JSArrayBuffer::FreeBackingStoreFromMainThread() {
|
||||
if (allocation_base() == nullptr) {
|
||||
return;
|
||||
}
|
||||
FreeBackingStore(GetIsolate(), {allocation_base(), allocation_length(),
|
||||
backing_store(), is_wasm_memory()});
|
||||
// Zero out the backing store and allocation base to avoid dangling
|
||||
// pointers.
|
||||
set_backing_store(nullptr);
|
||||
}
|
||||
|
||||
// static
|
||||
void JSArrayBuffer::FreeBackingStore(Isolate* isolate, Allocation allocation) {
|
||||
if (allocation.is_wasm_memory) {
|
||||
wasm::WasmMemoryTracker* memory_tracker =
|
||||
isolate->wasm_engine()->memory_tracker();
|
||||
if (!memory_tracker->FreeMemoryIfIsWasmMemory(isolate,
|
||||
allocation.backing_store)) {
|
||||
CHECK(FreePages(allocation.allocation_base, allocation.length));
|
||||
}
|
||||
} else {
|
||||
isolate->array_buffer_allocator()->Free(allocation.allocation_base,
|
||||
allocation.length);
|
||||
}
|
||||
}
|
||||
|
||||
void JSArrayBuffer::set_is_wasm_memory(bool is_wasm_memory) {
|
||||
set_bit_field(IsWasmMemory::update(bit_field(), is_wasm_memory));
|
||||
}
|
||||
|
||||
void JSArrayBuffer::Setup(Handle<JSArrayBuffer> array_buffer, Isolate* isolate,
|
||||
bool is_external, void* data, size_t byte_length,
|
||||
SharedFlag shared, bool is_wasm_memory) {
|
||||
DCHECK_EQ(array_buffer->GetEmbedderFieldCount(),
|
||||
v8::ArrayBuffer::kEmbedderFieldCount);
|
||||
for (int i = 0; i < v8::ArrayBuffer::kEmbedderFieldCount; i++) {
|
||||
array_buffer->SetEmbedderField(i, Smi::kZero);
|
||||
}
|
||||
array_buffer->set_bit_field(0);
|
||||
array_buffer->set_is_external(is_external);
|
||||
array_buffer->set_is_neuterable(shared == SharedFlag::kNotShared);
|
||||
array_buffer->set_is_shared(shared == SharedFlag::kShared);
|
||||
array_buffer->set_is_wasm_memory(is_wasm_memory);
|
||||
|
||||
Handle<Object> heap_byte_length =
|
||||
isolate->factory()->NewNumberFromSize(byte_length);
|
||||
CHECK(heap_byte_length->IsSmi() || heap_byte_length->IsHeapNumber());
|
||||
array_buffer->set_byte_length(*heap_byte_length);
|
||||
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
|
||||
// are currently being constructed in the |ArrayBufferTracker|. The
|
||||
// registration method below handles the case of registering a buffer that has
|
||||
// already been promoted.
|
||||
array_buffer->set_backing_store(data);
|
||||
|
||||
if (data && !is_external) {
|
||||
isolate->heap()->RegisterNewArrayBuffer(*array_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer> array_buffer,
|
||||
Isolate* isolate,
|
||||
size_t allocated_length,
|
||||
bool initialize, SharedFlag shared) {
|
||||
void* data;
|
||||
CHECK_NOT_NULL(isolate->array_buffer_allocator());
|
||||
if (allocated_length != 0) {
|
||||
if (allocated_length >= MB)
|
||||
isolate->counters()->array_buffer_big_allocations()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
if (shared == SharedFlag::kShared)
|
||||
isolate->counters()->shared_array_allocations()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
if (initialize) {
|
||||
data = isolate->array_buffer_allocator()->Allocate(allocated_length);
|
||||
} else {
|
||||
data = isolate->array_buffer_allocator()->AllocateUninitialized(
|
||||
allocated_length);
|
||||
}
|
||||
if (data == nullptr) {
|
||||
isolate->counters()->array_buffer_new_size_failures()->AddSample(
|
||||
ConvertToMb(allocated_length));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
data = nullptr;
|
||||
}
|
||||
|
||||
const bool is_external = false;
|
||||
JSArrayBuffer::Setup(array_buffer, isolate, is_external, data,
|
||||
allocated_length, shared);
|
||||
return true;
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::MaterializeArrayBuffer(
|
||||
Handle<JSTypedArray> typed_array) {
|
||||
DCHECK(typed_array->is_on_heap());
|
||||
|
||||
Isolate* isolate = typed_array->GetIsolate();
|
||||
|
||||
DCHECK(IsFixedTypedArrayElementsKind(typed_array->GetElementsKind()));
|
||||
|
||||
Handle<FixedTypedArrayBase> fixed_typed_array(
|
||||
FixedTypedArrayBase::cast(typed_array->elements()), isolate);
|
||||
|
||||
Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(typed_array->buffer()),
|
||||
isolate);
|
||||
// This code does not know how to materialize from wasm buffers.
|
||||
DCHECK(!buffer->is_wasm_memory());
|
||||
|
||||
void* backing_store =
|
||||
isolate->array_buffer_allocator()->AllocateUninitialized(
|
||||
fixed_typed_array->DataSize());
|
||||
if (backing_store == nullptr) {
|
||||
isolate->heap()->FatalProcessOutOfMemory(
|
||||
"JSTypedArray::MaterializeArrayBuffer");
|
||||
}
|
||||
buffer->set_is_external(false);
|
||||
DCHECK(buffer->byte_length()->IsSmi() ||
|
||||
buffer->byte_length()->IsHeapNumber());
|
||||
DCHECK(NumberToInt32(buffer->byte_length()) == fixed_typed_array->DataSize());
|
||||
// Initialize backing store at last to avoid handling of |JSArrayBuffers| that
|
||||
// are currently being constructed in the |ArrayBufferTracker|. The
|
||||
// registration method below handles the case of registering a buffer that has
|
||||
// already been promoted.
|
||||
buffer->set_backing_store(backing_store);
|
||||
// RegisterNewArrayBuffer expects a valid length for adjusting counters.
|
||||
isolate->heap()->RegisterNewArrayBuffer(*buffer);
|
||||
memcpy(buffer->backing_store(), fixed_typed_array->DataPtr(),
|
||||
fixed_typed_array->DataSize());
|
||||
Handle<FixedTypedArrayBase> new_elements =
|
||||
isolate->factory()->NewFixedTypedArrayWithExternalPointer(
|
||||
fixed_typed_array->length(), typed_array->type(),
|
||||
static_cast<uint8_t*>(buffer->backing_store()));
|
||||
|
||||
typed_array->set_elements(*new_elements);
|
||||
DCHECK(!typed_array->is_on_heap());
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
Handle<JSArrayBuffer> JSTypedArray::GetBuffer() {
|
||||
if (!is_on_heap()) {
|
||||
Handle<JSArrayBuffer> array_buffer(JSArrayBuffer::cast(buffer()),
|
||||
GetIsolate());
|
||||
return array_buffer;
|
||||
}
|
||||
Handle<JSTypedArray> self(this, GetIsolate());
|
||||
return MaterializeArrayBuffer(self);
|
||||
}
|
||||
|
||||
// ES#sec-integer-indexed-exotic-objects-defineownproperty-p-desc
|
||||
// static
|
||||
Maybe<bool> JSTypedArray::DefineOwnProperty(Isolate* isolate,
|
||||
Handle<JSTypedArray> o,
|
||||
Handle<Object> key,
|
||||
PropertyDescriptor* desc,
|
||||
ShouldThrow should_throw) {
|
||||
// 1. Assert: IsPropertyKey(P) is true.
|
||||
DCHECK(key->IsName() || key->IsNumber());
|
||||
// 2. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot.
|
||||
// 3. If Type(P) is String, then
|
||||
if (key->IsString() || key->IsSmi()) {
|
||||
// 3a. Let numericIndex be ! CanonicalNumericIndexString(P)
|
||||
// 3b. If numericIndex is not undefined, then
|
||||
Handle<Object> numeric_index;
|
||||
if (CanonicalNumericIndexString(isolate, key, &numeric_index)) {
|
||||
// 3b i. If IsInteger(numericIndex) is false, return false.
|
||||
// 3b ii. If numericIndex = -0, return false.
|
||||
// 3b iii. If numericIndex < 0, return false.
|
||||
// FIXME: the standard allows up to 2^53 elements.
|
||||
uint32_t index;
|
||||
if (numeric_index->IsMinusZero() || !numeric_index->ToUint32(&index)) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
|
||||
}
|
||||
// 3b iv. Let length be O.[[ArrayLength]].
|
||||
uint32_t length = o->length()->Number();
|
||||
// 3b v. If numericIndex ≥ length, return false.
|
||||
if (index >= length) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kInvalidTypedArrayIndex));
|
||||
}
|
||||
// 3b vi. If IsAccessorDescriptor(Desc) is true, return false.
|
||||
if (PropertyDescriptor::IsAccessorDescriptor(desc)) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kRedefineDisallowed, key));
|
||||
}
|
||||
// 3b vii. If Desc has a [[Configurable]] field and if
|
||||
// Desc.[[Configurable]] is true, return false.
|
||||
// 3b viii. If Desc has an [[Enumerable]] field and if Desc.[[Enumerable]]
|
||||
// is false, return false.
|
||||
// 3b ix. If Desc has a [[Writable]] field and if Desc.[[Writable]] is
|
||||
// false, return false.
|
||||
if ((desc->has_configurable() && desc->configurable()) ||
|
||||
(desc->has_enumerable() && !desc->enumerable()) ||
|
||||
(desc->has_writable() && !desc->writable())) {
|
||||
RETURN_FAILURE(isolate, should_throw,
|
||||
NewTypeError(MessageTemplate::kRedefineDisallowed, key));
|
||||
}
|
||||
// 3b x. If Desc has a [[Value]] field, then
|
||||
// 3b x 1. Let value be Desc.[[Value]].
|
||||
// 3b x 2. Return ? IntegerIndexedElementSet(O, numericIndex, value).
|
||||
if (desc->has_value()) {
|
||||
if (!desc->has_configurable()) desc->set_configurable(false);
|
||||
if (!desc->has_enumerable()) desc->set_enumerable(true);
|
||||
if (!desc->has_writable()) desc->set_writable(true);
|
||||
Handle<Object> value = desc->value();
|
||||
RETURN_ON_EXCEPTION_VALUE(isolate,
|
||||
SetOwnElementIgnoreAttributes(
|
||||
o, index, value, desc->ToAttributes()),
|
||||
Nothing<bool>());
|
||||
}
|
||||
// 3b xi. Return true.
|
||||
return Just(true);
|
||||
}
|
||||
}
|
||||
// 4. Return ! OrdinaryDefineOwnProperty(O, P, Desc).
|
||||
return OrdinaryDefineOwnProperty(isolate, o, key, desc, should_throw);
|
||||
}
|
||||
|
||||
ExternalArrayType JSTypedArray::type() {
|
||||
switch (elements()->map()->instance_type()) {
|
||||
#define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype) \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
return kExternal##Type##Array;
|
||||
|
||||
TYPED_ARRAYS(INSTANCE_TYPE_TO_ARRAY_TYPE)
|
||||
#undef INSTANCE_TYPE_TO_ARRAY_TYPE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
size_t JSTypedArray::element_size() {
|
||||
switch (elements()->map()->instance_type()) {
|
||||
#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype) \
|
||||
case FIXED_##TYPE##_ARRAY_TYPE: \
|
||||
return sizeof(ctype);
|
||||
|
||||
TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE)
|
||||
#undef INSTANCE_TYPE_TO_ELEMENT_SIZE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
Loading…
Reference in New Issue
Block a user