[builtins] Port TypedArrayConstructByArrayLike to CodeStubAssembler.
This helper is used directly when constructing from an object with a length, as well as by ConstructByIterable and ByTypedArray. BUG=v8:5977 Change-Id: I18a4829c2a22a6099cf3b0824ea1f698bfbf1917 Reviewed-on: https://chromium-review.googlesource.com/456707 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Reviewed-by: Franziska Hinkelmann <franzih@chromium.org> Commit-Queue: Peter Marshall <petermarshall@chromium.org> Cr-Commit-Position: refs/heads/master@{#44116}
This commit is contained in:
parent
7e08a77deb
commit
14e01da1cf
@ -2648,26 +2648,30 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Handle<JSFunction> typed_array_initialize = SimpleCreateFunction(
|
||||
isolate, factory->NewStringFromAsciiChecked("typedArrayInitialize"),
|
||||
Builtins::kTypedArrayInitialize, 6, false);
|
||||
InstallWithIntrinsicDefaultProto(isolate, typed_array_initialize,
|
||||
Context::TYPED_ARRAY_INITIALIZE_INDEX);
|
||||
native_context()->set_typed_array_initialize(*typed_array_initialize);
|
||||
|
||||
// %typed_array_construct_by_length
|
||||
Handle<JSFunction> construct_by_length = SimpleCreateFunction(
|
||||
isolate,
|
||||
factory->NewStringFromAsciiChecked("typedArrayConstructByLength"),
|
||||
Builtins::kTypedArrayConstructByLength, 3, false);
|
||||
InstallWithIntrinsicDefaultProto(
|
||||
isolate, construct_by_length,
|
||||
Context::TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX);
|
||||
native_context()->set_typed_array_construct_by_length(*construct_by_length);
|
||||
|
||||
// %typed_array_construct_by_array_buffer
|
||||
Handle<JSFunction> construct_by_buffer = SimpleCreateFunction(
|
||||
isolate,
|
||||
factory->NewStringFromAsciiChecked("typedArrayConstructByArrayBuffer"),
|
||||
Builtins::kTypedArrayConstructByArrayBuffer, 5, false);
|
||||
InstallWithIntrinsicDefaultProto(
|
||||
isolate, construct_by_buffer,
|
||||
Context::TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX);
|
||||
native_context()->set_typed_array_construct_by_array_buffer(
|
||||
*construct_by_buffer);
|
||||
|
||||
// %typed_array_construct_by_array_like
|
||||
Handle<JSFunction> construct_by_array_like = SimpleCreateFunction(
|
||||
isolate,
|
||||
factory->NewStringFromAsciiChecked("typedArrayConstructByArrayLike"),
|
||||
Builtins::kTypedArrayConstructByArrayLike, 4, false);
|
||||
native_context()->set_typed_array_construct_by_array_like(
|
||||
*construct_by_array_like);
|
||||
}
|
||||
|
||||
{ // -- D a t a V i e w
|
||||
|
@ -278,7 +278,6 @@ void TypedArrayBuiltinsAssembler::DoInitialize(Node* const holder, Node* length,
|
||||
}
|
||||
|
||||
Bind(&done);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
|
||||
@ -292,6 +291,7 @@ TF_BUILTIN(TypedArrayInitialize, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
DoInitialize(holder, length, maybe_buffer, byte_offset, byte_length,
|
||||
initialize, context);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
// ES6 #sec-typedarray-length
|
||||
@ -337,6 +337,7 @@ TF_BUILTIN(TypedArrayConstructByLength, TypedArrayBuiltinsAssembler) {
|
||||
{
|
||||
DoInitialize(holder, length, maybe_buffer.value(), byte_offset, byte_length,
|
||||
initialize, context);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
Bind(&invalid_length);
|
||||
@ -448,6 +449,7 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
|
||||
|
||||
DoInitialize(holder, new_length, buffer, offset.value(),
|
||||
new_byte_length.value(), initialize, context);
|
||||
Return(UndefinedConstant());
|
||||
}
|
||||
|
||||
Bind(&invalid_offset_error);
|
||||
@ -487,6 +489,49 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
|
||||
}
|
||||
}
|
||||
|
||||
TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
|
||||
Node* const holder = Parameter(Descriptor::kHolder);
|
||||
Node* const array_like = Parameter(Descriptor::kArrayLike);
|
||||
Node* length = Parameter(Descriptor::kLength);
|
||||
Node* const element_size = Parameter(Descriptor::kElementSize);
|
||||
CSA_ASSERT(this, TaggedIsSmi(element_size));
|
||||
Node* const context = Parameter(Descriptor::kContext);
|
||||
|
||||
Label call_init(this), call_runtime(this), invalid_length(this);
|
||||
|
||||
// The caller has looked up length on array_like, which is observable.
|
||||
length = ToSmiLength(length, context, &invalid_length);
|
||||
|
||||
// For byte_length < typed_array_max_size_in_heap, we allocate the buffer on
|
||||
// the heap. Otherwise we allocate it externally and attach it.
|
||||
Node* byte_length = SmiMul(length, element_size);
|
||||
GotoIf(TaggedIsNotSmi(byte_length), &call_runtime);
|
||||
Branch(SmiLessThanOrEqual(byte_length,
|
||||
SmiConstant(FLAG_typed_array_max_size_in_heap)),
|
||||
&call_init, &call_runtime);
|
||||
|
||||
Bind(&call_init);
|
||||
{
|
||||
DoInitialize(holder, length, NullConstant(), SmiConstant(0), byte_length,
|
||||
BooleanConstant(false), context);
|
||||
Return(CallRuntime(Runtime::kTypedArrayCopyElements, context, holder,
|
||||
array_like, length));
|
||||
}
|
||||
|
||||
Bind(&call_runtime);
|
||||
{
|
||||
Return(CallRuntime(Runtime::kTypedArrayInitializeFromArrayLike, context,
|
||||
holder, array_like, length));
|
||||
}
|
||||
|
||||
Bind(&invalid_length);
|
||||
{
|
||||
CallRuntime(Runtime::kThrowRangeError, context,
|
||||
SmiConstant(MessageTemplate::kInvalidTypedArrayLength));
|
||||
Unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter(
|
||||
Node* context, Node* receiver, const char* method_name, int object_offset) {
|
||||
// Check if the {receiver} is actually a JSTypedArray.
|
||||
|
@ -888,6 +888,8 @@ class Isolate;
|
||||
/* ES6 #sec-typedarray-buffer-byteoffset-length */ \
|
||||
TFJ(TypedArrayConstructByArrayBuffer, 5, kHolder, kBuffer, kByteOffset, \
|
||||
kLength, kElementSize) \
|
||||
TFJ(TypedArrayConstructByArrayLike, 4, kHolder, kArrayLike, kLength, \
|
||||
kElementSize) \
|
||||
/* ES6 #sec-typedarray-length */ \
|
||||
TFJ(TypedArrayConstructByLength, 3, kHolder, kLength, kElementSize) \
|
||||
TFJ(TypedArrayInitialize, 6, kHolder, kLength, kBuffer, kByteOffset, \
|
||||
|
@ -4149,12 +4149,12 @@ Node* CodeStubAssembler::JSReceiverToPrimitive(Node* context, Node* input) {
|
||||
Node* CodeStubAssembler::ToSmiIndex(Node* const input, Node* const context,
|
||||
Label* range_error) {
|
||||
Variable result(this, MachineRepresentation::kTagged, input);
|
||||
Label check_undefined(this), undefined(this), defined(this),
|
||||
Label check_undefined(this), return_zero(this), defined(this),
|
||||
negative_check(this), done(this);
|
||||
Branch(TaggedIsSmi(result.value()), &negative_check, &check_undefined);
|
||||
|
||||
Bind(&check_undefined);
|
||||
Branch(IsUndefined(result.value()), &undefined, &defined);
|
||||
Branch(IsUndefined(result.value()), &return_zero, &defined);
|
||||
|
||||
Bind(&defined);
|
||||
result.Bind(ToInteger(context, result.value(),
|
||||
@ -4164,10 +4164,33 @@ Node* CodeStubAssembler::ToSmiIndex(Node* const input, Node* const context,
|
||||
Goto(&negative_check);
|
||||
|
||||
Bind(&negative_check);
|
||||
GotoIf(SmiLessThan(result.value(), SmiConstant(0)), range_error);
|
||||
Branch(SmiLessThan(result.value(), SmiConstant(0)), range_error, &done);
|
||||
|
||||
Bind(&return_zero);
|
||||
result.Bind(SmiConstant(0));
|
||||
Goto(&done);
|
||||
|
||||
Bind(&undefined);
|
||||
Bind(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
Node* CodeStubAssembler::ToSmiLength(Node* input, Node* const context,
|
||||
Label* range_error) {
|
||||
Variable result(this, MachineRepresentation::kTagged, input);
|
||||
Label to_integer(this), negative_check(this), return_zero(this), done(this);
|
||||
Branch(TaggedIsSmi(result.value()), &negative_check, &to_integer);
|
||||
|
||||
Bind(&to_integer);
|
||||
result.Bind(ToInteger(context, result.value(),
|
||||
CodeStubAssembler::kTruncateMinusZero));
|
||||
GotoIfNot(TaggedIsSmi(result.value()), range_error);
|
||||
CSA_ASSERT(this, TaggedIsSmi(result.value()));
|
||||
Goto(&negative_check);
|
||||
|
||||
Bind(&negative_check);
|
||||
Branch(SmiLessThan(result.value(), SmiConstant(0)), &return_zero, &done);
|
||||
|
||||
Bind(&return_zero);
|
||||
result.Bind(SmiConstant(0));
|
||||
Goto(&done);
|
||||
|
||||
|
@ -799,6 +799,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
// ES6 7.1.17 ToIndex, but jumps to range_error if the result is not a Smi.
|
||||
Node* ToSmiIndex(Node* const input, Node* const context, Label* range_error);
|
||||
|
||||
// ES6 7.1.15 ToLength, but jumps to range_error if the result is not a Smi.
|
||||
Node* ToSmiLength(Node* input, Node* const context, Label* range_error);
|
||||
|
||||
// Convert any object to an Integer.
|
||||
Node* ToInteger(Node* context, Node* input,
|
||||
ToIntegerTruncationMode mode = kNoTruncation);
|
||||
|
@ -70,6 +70,8 @@ enum ContextLookupFlags {
|
||||
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_BUFFER_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_buffer) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
|
||||
typed_array_construct_by_array_like) \
|
||||
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
|
||||
typed_array_construct_by_length) \
|
||||
V(TYPED_ARRAY_INITIALIZE_INDEX, JSFunction, typed_array_initialize) \
|
||||
|
@ -115,29 +115,6 @@ function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2, conservative) {
|
||||
}
|
||||
|
||||
macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
|
||||
function NAMEConstructByArrayLike(obj, arrayLike, length) {
|
||||
var l = ToPositiveInteger(length, kInvalidTypedArrayLength);
|
||||
|
||||
if (l > %_MaxSmi()) {
|
||||
throw %make_range_error(kInvalidTypedArrayLength);
|
||||
}
|
||||
var initialized = false;
|
||||
var byteLength = l * ELEMENT_SIZE;
|
||||
if (byteLength <= %_TypedArrayMaxSizeInHeap()) {
|
||||
%typed_array_initialize(obj, l, null, 0, byteLength, false);
|
||||
} else {
|
||||
initialized =
|
||||
%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l);
|
||||
}
|
||||
if (!initialized) {
|
||||
for (var i = 0; i < l; i++) {
|
||||
// It is crucial that we let any execptions from arrayLike[i]
|
||||
// propagate outside the function.
|
||||
obj[i] = arrayLike[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function NAMEConstructByIterable(obj, iterable, iteratorFn) {
|
||||
var list = new InternalArray();
|
||||
// Reading the Symbol.iterator property of iterable twice would be
|
||||
@ -155,7 +132,7 @@ function NAMEConstructByIterable(obj, iterable, iteratorFn) {
|
||||
for (var value of newIterable) {
|
||||
list.push(value);
|
||||
}
|
||||
NAMEConstructByArrayLike(obj, list, list.length);
|
||||
%typed_array_construct_by_array_like(obj, list, list.length, ELEMENT_SIZE);
|
||||
}
|
||||
|
||||
// ES#sec-typedarray-typedarray TypedArray ( typedArray )
|
||||
@ -165,7 +142,7 @@ function NAMEConstructByTypedArray(obj, typedArray) {
|
||||
var length = %_TypedArrayGetLength(typedArray);
|
||||
var byteLength = %_ArrayBufferViewGetByteLength(typedArray);
|
||||
var newByteLength = length * ELEMENT_SIZE;
|
||||
NAMEConstructByArrayLike(obj, typedArray, length);
|
||||
%typed_array_construct_by_array_like(obj, typedArray, length, ELEMENT_SIZE);
|
||||
var bufferConstructor = SpeciesConstructor(srcData, GlobalArrayBuffer);
|
||||
var prototype = bufferConstructor.prototype;
|
||||
// TODO(littledan): Use the right prototype based on bufferConstructor's realm
|
||||
@ -178,13 +155,14 @@ function NAMEConstructor(arg1, arg2, arg3) {
|
||||
if (!IS_UNDEFINED(new.target)) {
|
||||
if (IS_ARRAYBUFFER(arg1) || IS_SHAREDARRAYBUFFER(arg1)) {
|
||||
%typed_array_construct_by_array_buffer(
|
||||
this, arg1, arg2, arg3, ELEMENT_SIZE);
|
||||
this, arg1, arg2, arg3, ELEMENT_SIZE);
|
||||
} else if (IS_TYPEDARRAY(arg1)) {
|
||||
NAMEConstructByTypedArray(this, arg1);
|
||||
} else if (IS_RECEIVER(arg1)) {
|
||||
var iteratorFn = arg1[iteratorSymbol];
|
||||
if (IS_UNDEFINED(iteratorFn)) {
|
||||
NAMEConstructByArrayLike(this, arg1, arg1.length);
|
||||
%typed_array_construct_by_array_like(
|
||||
this, arg1, arg1.length, ELEMENT_SIZE);
|
||||
} else {
|
||||
NAMEConstructByIterable(this, arg1, iteratorFn);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/runtime/runtime-utils.h"
|
||||
|
||||
#include "src/arguments.h"
|
||||
#include "src/elements.h"
|
||||
#include "src/factory.h"
|
||||
#include "src/messages.h"
|
||||
#include "src/objects-inl.h"
|
||||
@ -41,6 +42,41 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Object* CopyElements(Isolate* isolate, Handle<JSTypedArray> holder,
|
||||
Handle<JSReceiver> source, size_t length) {
|
||||
ElementsAccessor* holder_accessor = holder->GetElementsAccessor();
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
LookupIterator get_it(isolate, source, i);
|
||||
Handle<Object> element;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element,
|
||||
Object::GetProperty(&get_it));
|
||||
// Convert the incoming value to a number for storing into typed arrays.
|
||||
if (!element->IsNumber() && !element->IsUndefined(isolate)) {
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, element,
|
||||
Object::ToNumber(element));
|
||||
}
|
||||
holder_accessor->Set(holder, i, *element);
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1);
|
||||
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
|
||||
|
||||
size_t length;
|
||||
CHECK(TryNumberToSize(*length_obj, &length));
|
||||
|
||||
return CopyElements(isolate, holder, source, length);
|
||||
}
|
||||
|
||||
void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
|
||||
ElementsKind* fixed_elements_kind,
|
||||
@ -76,29 +112,20 @@ const char* Runtime::ElementsKindToType(ElementsKind fixed_elements_kind) {
|
||||
}
|
||||
}
|
||||
|
||||
// Initializes a typed array from an array-like object.
|
||||
// If an array-like object happens to be a typed array of the same type,
|
||||
// initializes backing store using memove.
|
||||
//
|
||||
// Returns true if backing store was initialized or false otherwise.
|
||||
// Initializes a typed array from an array-like object, and its backing store as
|
||||
// well.
|
||||
RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK_EQ(4, args.length());
|
||||
DCHECK_EQ(3, args.length());
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
|
||||
CONVERT_SMI_ARG_CHECKED(arrayId, 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
|
||||
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
|
||||
CONVERT_ARG_HANDLE_CHECKED(JSReceiver, source, 1);
|
||||
CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 2);
|
||||
|
||||
CHECK(arrayId >= Runtime::ARRAY_ID_FIRST &&
|
||||
arrayId <= Runtime::ARRAY_ID_LAST);
|
||||
|
||||
ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
|
||||
size_t element_size = 1; // Bogus initialization.
|
||||
ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
|
||||
Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind,
|
||||
&element_size);
|
||||
|
||||
CHECK(holder->map()->elements_kind() == fixed_elements_kind);
|
||||
ElementsKind fixed_elements_kind = holder->map()->elements_kind();
|
||||
ExternalArrayType array_type =
|
||||
isolate->factory()->GetArrayTypeFromElementsKind(fixed_elements_kind);
|
||||
size_t element_size =
|
||||
isolate->factory()->GetExternalArrayElementSize(array_type);
|
||||
|
||||
Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
|
||||
size_t length = 0;
|
||||
@ -122,22 +149,6 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
holder->SetEmbedderField(i, Smi::kZero);
|
||||
}
|
||||
|
||||
// NOTE: not initializing backing store.
|
||||
// We assume that the caller of this function will initialize holder
|
||||
// with the loop
|
||||
// for(i = 0; i < length; i++) { holder[i] = source[i]; }
|
||||
// We assume that the caller of this function is always a typed array
|
||||
// constructor.
|
||||
// If source is a typed array, this loop will always run to completion,
|
||||
// so we are sure that the backing store will be initialized.
|
||||
// Otherwise, the indexing operation might throw, so the loop will not
|
||||
// run to completion and the typed array might remain partly initialized.
|
||||
// However we further assume that the caller of this function is a typed array
|
||||
// constructor, and the exception will propagate out of the constructor,
|
||||
// therefore uninitialized memory will not be accessible by a user program.
|
||||
//
|
||||
// TODO(dslomov): revise this once we support subclassing.
|
||||
|
||||
if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, byte_length,
|
||||
false)) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
@ -158,6 +169,9 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
static_cast<uint8_t*>(buffer->backing_store()));
|
||||
holder->set_elements(*elements);
|
||||
|
||||
// Initialize the backing store. We can use a special path for typed arrays of
|
||||
// the same type, but we need to make sure everything is properly observable
|
||||
// for other types.
|
||||
if (source->IsJSTypedArray()) {
|
||||
Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
|
||||
|
||||
@ -170,8 +184,7 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
|
||||
return isolate->heap()->true_value();
|
||||
}
|
||||
}
|
||||
|
||||
return isolate->heap()->false_value();
|
||||
return CopyElements(isolate, holder, source, length);
|
||||
}
|
||||
|
||||
|
||||
|
@ -618,7 +618,8 @@ namespace internal {
|
||||
#define FOR_EACH_INTRINSIC_TYPEDARRAY(F) \
|
||||
F(ArrayBufferGetByteLength, 1, 1) \
|
||||
F(ArrayBufferNeuter, 1, 1) \
|
||||
F(TypedArrayInitializeFromArrayLike, 4, 1) \
|
||||
F(TypedArrayCopyElements, 3, 1) \
|
||||
F(TypedArrayInitializeFromArrayLike, 3, 1) \
|
||||
F(ArrayBufferViewGetByteLength, 1, 1) \
|
||||
F(ArrayBufferViewGetByteOffset, 1, 1) \
|
||||
F(TypedArrayGetLength, 1, 1) \
|
||||
|
87
test/mjsunit/es6/typedarray-construct-by-array-like.js
Normal file
87
test/mjsunit/es6/typedarray-construct-by-array-like.js
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright 2017 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.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function TestConstructSmallObject(constr) {
|
||||
var myObject = { 0: 5, 1: 6, length: 2 };
|
||||
|
||||
arr = new constr(myObject);
|
||||
|
||||
assertEquals(2, arr.length);
|
||||
assertEquals(5, arr[0]);
|
||||
assertEquals(6, arr[1]);
|
||||
};
|
||||
|
||||
function TestConstructLargeObject(constr) {
|
||||
var myObject = {};
|
||||
const n = 128;
|
||||
for (var i = 0; i < n; i++) {
|
||||
myObject[i] = i;
|
||||
}
|
||||
myObject.length = n;
|
||||
|
||||
arr = new constr(myObject);
|
||||
|
||||
assertEquals(n, arr.length);
|
||||
for (var i = 0; i < n; i++) {
|
||||
assertEquals(i, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function TestConstructFromArray(constr) {
|
||||
var n = 64;
|
||||
var jsArray = [];
|
||||
for (var i = 0; i < n; i++) {
|
||||
jsArray[i] = i;
|
||||
}
|
||||
|
||||
var arr = new constr(jsArray);
|
||||
|
||||
assertEquals(n, arr.length);
|
||||
for (var i = 0; i < n; i++) {
|
||||
assertEquals(i, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function TestConstructFromTypedArray(constr) {
|
||||
var n = 64;
|
||||
var ta = new constr(n);
|
||||
for (var i = 0; i < ta.length; i++) {
|
||||
ta[i] = i;
|
||||
}
|
||||
|
||||
var arr = new constr(ta);
|
||||
|
||||
assertEquals(n, arr.length);
|
||||
for (var i = 0; i < n; i++) {
|
||||
assertEquals(i, arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function TestLengthIsMaxSmi(constr) {
|
||||
var myObject = { 0: 5, 1: 6, length: %_MaxSmi() + 1 };
|
||||
|
||||
assertThrows(function() {
|
||||
new constr(myObject);
|
||||
}, RangeError);
|
||||
}
|
||||
|
||||
Test(TestConstructSmallObject);
|
||||
Test(TestConstructLargeObject);
|
||||
Test(TestConstructFromArray);
|
||||
Test(TestConstructFromTypedArray);
|
||||
Test(TestLengthIsMaxSmi);
|
||||
|
||||
function Test(func) {
|
||||
func(Uint8Array);
|
||||
func(Int8Array);
|
||||
func(Uint16Array);
|
||||
func(Int16Array);
|
||||
func(Uint32Array);
|
||||
func(Int32Array);
|
||||
func(Float32Array);
|
||||
func(Float64Array);
|
||||
func(Uint8ClampedArray);
|
||||
}
|
@ -58,3 +58,24 @@
|
||||
new Uint8Array(buffer, -1);
|
||||
}, RangeError);
|
||||
})();
|
||||
|
||||
(function TestByArrayLikeObservableOrdering() {
|
||||
var expected = [
|
||||
'proxy.Symbol(Symbol.iterator)', 'proxy.length', 'proxy.0', 'proxy.1',
|
||||
'proxy.2'
|
||||
];
|
||||
var actual = [];
|
||||
|
||||
var a = [1, 2, 3];
|
||||
var proxy = new Proxy(a, {
|
||||
get: function(target, name) {
|
||||
actual.push("proxy." + name.toString());
|
||||
if (name === Symbol.iterator) return undefined;
|
||||
return target[name];
|
||||
}
|
||||
});
|
||||
var arr = new Uint8Array(proxy);
|
||||
|
||||
assertEquals(a.length, arr.length);
|
||||
assertEquals(expected, actual);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user