Commit a7c91c77 authored by Peter Marshall's avatar Peter Marshall Committed by Commit Bot

[typedarray] Port ConstructByTypedArray to CSA.

This is needed to easily port the constructor dispatcher to CSA.

Bug: v8:7102
Change-Id: I9672416495940ca12088a2980a9ecc61364aef9d
Reviewed-on: https://chromium-review.googlesource.com/785630Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#50671}
parent 633b70b1
......@@ -3129,6 +3129,14 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Builtins::kTypedArrayConstructByArrayLike, 4, false);
native_context()->set_typed_array_construct_by_array_like(
*construct_by_array_like);
// %typed_array_construct_by_typed_array
Handle<JSFunction> construct_by_typed_array = SimpleCreateFunction(
isolate,
factory->NewStringFromAsciiChecked("typedArrayConstructByTypedArray"),
Builtins::kTypedArrayConstructByTypedArray, 3, false);
native_context()->set_typed_array_construct_by_typed_array(
*construct_by_typed_array);
}
{ // -- D a t a V i e w
......
......@@ -1072,6 +1072,7 @@ namespace internal {
kElementSize) \
/* ES6 #sec-typedarray-length */ \
TFJ(TypedArrayConstructByLength, 3, kHolder, kLength, kElementSize) \
TFJ(TypedArrayConstructByTypedArray, 3, kHolder, kTypedArray, kElementSize) \
CPP(TypedArrayPrototypeBuffer) \
/* ES6 #sec-get-%typedarray%.prototype.bytelength */ \
TFJ(TypedArrayPrototypeByteLength, 0) \
......
......@@ -258,46 +258,6 @@ void PromiseBuiltinsAssembler::PromiseSetHandledHint(Node* promise) {
StoreObjectFieldNoWriteBarrier(promise, JSPromise::kFlagsOffset, new_flags);
}
Node* PromiseBuiltinsAssembler::SpeciesConstructor(Node* context, Node* object,
Node* default_constructor) {
Isolate* isolate = this->isolate();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(default_constructor);
// 2. Let C be ? Get(O, "constructor").
Node* const constructor =
GetProperty(context, object, isolate->factory()->constructor_string());
// 3. If C is undefined, return defaultConstructor.
Label out(this);
GotoIf(IsUndefined(constructor), &out);
// 4. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, constructor,
MessageTemplate::kConstructorNotReceiver);
// 5. Let S be ? Get(C, @@species).
Node* const species =
GetProperty(context, constructor, isolate->factory()->species_symbol());
// 6. If S is either undefined or null, return defaultConstructor.
GotoIf(IsNullOrUndefined(species), &out);
// 7. If IsConstructor(S) is true, return S.
Label throw_error(this);
GotoIf(TaggedIsSmi(species), &throw_error);
GotoIfNot(IsConstructorMap(LoadMap(species)), &throw_error);
var_result.Bind(species);
Goto(&out);
// 8. Throw a TypeError exception.
BIND(&throw_error);
ThrowTypeError(context, MessageTemplate::kSpeciesNotConstructor);
BIND(&out);
return var_result.value();
}
void PromiseBuiltinsAssembler::AppendPromiseCallback(int offset, Node* promise,
Node* value) {
Node* elements = LoadObjectField(promise, offset);
......
......@@ -111,9 +111,6 @@ class PromiseBuiltinsAssembler : public CodeStubAssembler {
protected:
void PromiseInit(Node* promise);
Node* SpeciesConstructor(Node* context, Node* object,
Node* default_constructor);
void PromiseSetHasHandler(Node* promise);
void PromiseSetHandledHint(Node* promise);
......
......@@ -36,6 +36,11 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
const char* method_name,
IterationKind iteration_kind);
void ConstructByArrayLike(TNode<Context> context, TNode<JSTypedArray> holder,
TNode<HeapObject> array_like,
TNode<Object> initial_length,
TNode<Smi> element_size);
void SetupTypedArray(TNode<JSTypedArray> holder, TNode<Smi> length,
TNode<Number> byte_offset, TNode<Number> byte_length);
void AttachBuffer(TNode<JSTypedArray> holder, TNode<JSArrayBuffer> buffer,
......@@ -543,6 +548,65 @@ TF_BUILTIN(TypedArrayConstructByArrayBuffer, TypedArrayBuiltinsAssembler) {
{ ThrowTypeError(context, MessageTemplate::kDetachedOperation, "Construct"); }
}
// ES#sec-typedarray-typedarray TypedArray ( typedArray )
TF_BUILTIN(TypedArrayConstructByTypedArray, TypedArrayBuiltinsAssembler) {
TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
TNode<JSTypedArray> typed_array = CAST(Parameter(Descriptor::kTypedArray));
TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
CSA_ASSERT(this, TaggedIsPositiveSmi(element_size));
TNode<JSFunction> const default_constructor = CAST(LoadContextElement(
LoadNativeContext(context), Context::ARRAY_BUFFER_FUN_INDEX));
Label checked_shared(this), construct(this), if_buffernotshared(this),
check_prototype(this), detached_error(this), done(this);
TVARIABLE(JSReceiver, buffer_constructor, default_constructor);
TNode<JSArrayBuffer> source_buffer = LoadObjectField<JSArrayBuffer>(
typed_array, JSArrayBufferView::kBufferOffset);
GotoIf(IsDetachedBuffer(source_buffer), &detached_error);
TNode<Smi> source_length =
CAST(LoadObjectField(typed_array, JSTypedArray::kLengthOffset));
// The spec requires that constructing a typed array using a SAB-backed typed
// array use the ArrayBuffer constructor, not the species constructor. See
// https://tc39.github.io/ecma262/#sec-typedarray-typedarray.
TNode<Uint32T> bitfield =
LoadObjectField<Uint32T>(source_buffer, JSArrayBuffer::kBitFieldOffset);
Branch(IsSetWord32<JSArrayBuffer::IsShared>(bitfield), &construct,
&if_buffernotshared);
BIND(&if_buffernotshared);
{
buffer_constructor =
CAST(SpeciesConstructor(context, source_buffer, default_constructor));
Goto(&construct);
}
BIND(&construct);
{
GotoIf(IsDetachedBuffer(source_buffer), &detached_error);
ConstructByArrayLike(context, holder, typed_array, source_length,
element_size);
Node* proto =
GetProperty(context, buffer_constructor, PrototypeStringConstant());
// TODO(petermarshall): Correct for realm as per 9.1.14 step 4.
TNode<JSArrayBuffer> buffer = LoadObjectField<JSArrayBuffer>(
holder, JSArrayBufferView::kBufferOffset);
CallRuntime(Runtime::kInternalSetPrototype, context, buffer, proto);
Goto(&done);
}
BIND(&detached_error);
{ ThrowTypeError(context, MessageTemplate::kDetachedOperation, "Construct"); }
BIND(&done);
Return(UndefinedConstant());
}
Node* TypedArrayBuiltinsAssembler::LoadDataPtr(Node* typed_array) {
CSA_ASSERT(this, IsJSTypedArray(typed_array));
Node* elements = LoadElements(typed_array);
......@@ -577,17 +641,13 @@ TNode<BoolT> TypedArrayBuiltinsAssembler::ByteLengthIsValid(
return is_valid;
}
TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
Node* holder = Parameter(Descriptor::kHolder);
Node* array_like = Parameter(Descriptor::kArrayLike);
Node* initial_length = Parameter(Descriptor::kLength);
Node* element_size = Parameter(Descriptor::kElementSize);
CSA_ASSERT(this, TaggedIsSmi(element_size));
Node* context = Parameter(Descriptor::kContext);
void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
TNode<Context> context, TNode<JSTypedArray> holder,
TNode<HeapObject> array_like, TNode<Object> initial_length,
TNode<Smi> element_size) {
Node* initialize = FalseConstant();
Label invalid_length(this), fill(this), fast_copy(this);
Label invalid_length(this), fill(this), fast_copy(this), done(this);
// The caller has looked up length on array_like, which is observable.
Node* length = ToSmiLength(initial_length, context, &invalid_length);
......@@ -595,7 +655,7 @@ TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
CallBuiltin(Builtins::kTypedArrayInitialize, context, holder, length,
element_size, initialize);
GotoIf(SmiNotEqual(length, SmiConstant(0)), &fill);
Return(UndefinedConstant());
Goto(&done);
BIND(&fill);
TNode<Int32T> holder_kind = LoadMapElementsKind(LoadMap(holder));
......@@ -605,7 +665,7 @@ TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
// Copy using the elements accessor.
CallRuntime(Runtime::kTypedArrayCopyElements, context, holder, array_like,
length);
Return(UndefinedConstant());
Goto(&done);
BIND(&fast_copy);
{
......@@ -632,7 +692,7 @@ TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
CallCFunction3(MachineType::AnyTagged(), MachineType::Pointer(),
MachineType::Pointer(), MachineType::UintPtr(), memcpy,
holder_data_ptr, source_data_ptr, byte_length_intptr);
Return(UndefinedConstant());
Goto(&done);
}
BIND(&invalid_length);
......@@ -642,6 +702,21 @@ TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
initial_length);
Unreachable();
}
BIND(&done);
}
TF_BUILTIN(TypedArrayConstructByArrayLike, TypedArrayBuiltinsAssembler) {
TNode<JSTypedArray> holder = CAST(Parameter(Descriptor::kHolder));
TNode<HeapObject> array_like = CAST(Parameter(Descriptor::kArrayLike));
TNode<Object> initial_length = CAST(Parameter(Descriptor::kLength));
TNode<Smi> element_size = CAST(Parameter(Descriptor::kElementSize));
CSA_ASSERT(this, TaggedIsSmi(element_size));
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
ConstructByArrayLike(context, holder, array_like, initial_length,
element_size);
Return(UndefinedConstant());
}
void TypedArrayBuiltinsAssembler::GenerateTypedArrayPrototypeGetter(
......
......@@ -9800,6 +9800,46 @@ Node* CodeStubAssembler::GetSuperConstructor(Node* active_function,
return result.value();
}
Node* CodeStubAssembler::SpeciesConstructor(Node* context, Node* object,
Node* default_constructor) {
Isolate* isolate = this->isolate();
VARIABLE(var_result, MachineRepresentation::kTagged);
var_result.Bind(default_constructor);
// 2. Let C be ? Get(O, "constructor").
Node* const constructor =
GetProperty(context, object, isolate->factory()->constructor_string());
// 3. If C is undefined, return defaultConstructor.
Label out(this);
GotoIf(IsUndefined(constructor), &out);
// 4. If Type(C) is not Object, throw a TypeError exception.
ThrowIfNotJSReceiver(context, constructor,
MessageTemplate::kConstructorNotReceiver);
// 5. Let S be ? Get(C, @@species).
Node* const species =
GetProperty(context, constructor, isolate->factory()->species_symbol());
// 6. If S is either undefined or null, return defaultConstructor.
GotoIf(IsNullOrUndefined(species), &out);
// 7. If IsConstructor(S) is true, return S.
Label throw_error(this);
GotoIf(TaggedIsSmi(species), &throw_error);
GotoIfNot(IsConstructorMap(LoadMap(species)), &throw_error);
var_result.Bind(species);
Goto(&out);
// 8. Throw a TypeError exception.
BIND(&throw_error);
ThrowTypeError(context, MessageTemplate::kSpeciesNotConstructor);
BIND(&out);
return var_result.value();
}
Node* CodeStubAssembler::InstanceOf(Node* object, Node* callable,
Node* context) {
VARIABLE(var_result, MachineRepresentation::kTagged);
......
......@@ -1842,6 +1842,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
Node* GetSuperConstructor(Node* value, Node* context);
Node* SpeciesConstructor(Node* context, Node* object,
Node* default_constructor);
Node* InstanceOf(Node* object, Node* callable, Node* context);
// Debug helpers
......
......@@ -83,9 +83,6 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
return ReduceCall(node);
case Runtime::kInlineGetSuperConstructor:
return ReduceGetSuperConstructor(node);
case Runtime::kInlineArrayBufferViewGetByteLength:
return ReduceArrayBufferViewField(
node, AccessBuilder::ForJSArrayBufferViewByteLength());
case Runtime::kInlineArrayBufferViewGetByteOffset:
return ReduceArrayBufferViewField(
node, AccessBuilder::ForJSArrayBufferViewByteOffset());
......
......@@ -69,6 +69,8 @@ enum ContextLookupFlags {
typed_array_construct_by_array_like) \
V(TYPED_ARRAY_CONSTRUCT_BY_LENGTH_INDEX, JSFunction, \
typed_array_construct_by_length) \
V(TYPED_ARRAY_CONSTRUCT_BY_TYPED_ARRAY_INDEX, JSFunction, \
typed_array_construct_by_typed_array) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
......
......@@ -15,10 +15,6 @@
var ArrayToString = utils.ImportNow("ArrayToString");
var GetIterator;
var GetMethod;
var GlobalArray = global.Array;
var GlobalArrayBuffer = global.ArrayBuffer;
var GlobalArrayBufferPrototype = GlobalArrayBuffer.prototype;
var GlobalObject = global.Object;
var InnerArrayJoin;
var InnerArraySort;
var InnerArrayToLocaleString;
......@@ -27,7 +23,6 @@ var MathMax = global.Math.max;
var MathMin = global.Math.min;
var iteratorSymbol = utils.ImportNow("iterator_symbol");
var speciesSymbol = utils.ImportNow("species_symbol");
var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol");
macro TYPED_ARRAYS(FUNCTION)
FUNCTION(Uint8Array, 1)
......@@ -159,34 +154,13 @@ function NAMEConstructByIterable(obj, iterable, iteratorFn) {
}
}
// ES#sec-typedarray-typedarray TypedArray ( typedArray )
function NAMEConstructByTypedArray(obj, typedArray) {
// TODO(littledan): Throw on detached typedArray
var srcData = %TypedArrayGetBuffer(typedArray);
var length = %_TypedArrayGetLength(typedArray);
var byteLength = %_ArrayBufferViewGetByteLength(typedArray);
var newByteLength = length * ELEMENT_SIZE;
%typed_array_construct_by_array_like(obj, typedArray, length, ELEMENT_SIZE);
// The spec requires that constructing a typed array using a SAB-backed typed
// array use the ArrayBuffer constructor, not the species constructor. See
// https://tc39.github.io/ecma262/#sec-typedarray-typedarray.
var bufferConstructor = IS_SHAREDARRAYBUFFER(srcData)
? GlobalArrayBuffer
: SpeciesConstructor(srcData, GlobalArrayBuffer);
var prototype = bufferConstructor.prototype;
// TODO(littledan): Use the right prototype based on bufferConstructor's realm
if (IS_RECEIVER(prototype) && prototype !== GlobalArrayBufferPrototype) {
%InternalSetPrototype(%TypedArrayGetBuffer(obj), prototype);
}
}
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);
} else if (IS_TYPEDARRAY(arg1)) {
NAMEConstructByTypedArray(this, arg1);
%typed_array_construct_by_typed_array(this, arg1, ELEMENT_SIZE);
} else if (IS_RECEIVER(arg1)) {
var iteratorFn = arg1[iteratorSymbol];
if (IS_UNDEFINED(iteratorFn)) {
......
......@@ -74,7 +74,6 @@ RUNTIME_FUNCTION(Runtime_TypedArrayCopyElements) {
return holder->accessor(); \
}
BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
BUFFER_VIEW_GETTER(TypedArray, Length, length)
......
......@@ -641,7 +641,6 @@ namespace internal {
F(ArrayBufferGetByteLength, 1, 1) \
F(ArrayBufferNeuter, 1, 1) \
F(TypedArrayCopyElements, 3, 1) \
F(ArrayBufferViewGetByteLength, 1, 1) \
F(ArrayBufferViewGetByteOffset, 1, 1) \
F(ArrayBufferViewWasNeutered, 1, 1) \
F(TypedArrayGetLength, 1, 1) \
......
......@@ -150,6 +150,25 @@ tests.push(function TestConstructFromTypedArray(constr) {
}
});
tests.push(function TestFromTypedArraySpecies(constr) {
var b = new ArrayBuffer(16);
var a1 = new constr(b);
var constructor_read = 0;
var cons = b.constructor;
Object.defineProperty(b, 'constructor', {
get: function() {
constructor_read++;
return cons;
}
});
var a2 = new constr(a1);
assertEquals(1, constructor_read);
});
tests.push(function TestLengthIsMaxSmi(constr) {
var myObject = { 0: 5, 1: 6, length: %_MaxSmi() + 1 };
......
......@@ -6,5 +6,4 @@
var a = new Uint8Array(1024*1024);
%ArrayBufferNeuter(a.buffer);
var b = new Uint8Array(a);
assertEquals(0, b.length);
assertThrows(() => new Uint8Array(a), TypeError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment