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

[typedarray] Port ConstructByIterable by CSA.

This is the last piece of the TypedArray constructors that was still
written in JS.

Bug: v8:7102
Change-Id: I7c4dc867b09408caa4eec2873ea7185b6c61a525
Reviewed-on: https://chromium-review.googlesource.com/888751
Commit-Queue: Peter Marshall <petermarshall@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarSathya Gunasekaran <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51122}
parent cdecc375
......@@ -3087,14 +3087,6 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
}
TYPED_ARRAYS(INSTALL_TYPED_ARRAY)
#undef INSTALL_TYPED_ARRAY
// %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
......
......@@ -1064,8 +1064,6 @@ namespace internal {
TFS(TypedArrayInitialize, kHolder, kLength, kElementSize, kInitialize) \
TFS(TypedArrayInitializeWithBuffer, kHolder, kLength, kBuffer, kElementSize, \
kByteOffset) \
TFJ(TypedArrayConstructByArrayLike, 4, kHolder, kArrayLike, kLength, \
kElementSize) \
TFJ(TypedArrayConstructor, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
TFJ(TypedArrayConstructor_ConstructStub, \
SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
......
......@@ -16,6 +16,14 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
Label* if_exception,
Variable* exception) {
Node* method = GetProperty(context, object, factory()->iterator_symbol());
return GetIterator(context, object, method, if_exception, exception);
}
IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context,
Node* object,
Node* method,
Label* if_exception,
Variable* exception) {
GotoIfException(method, if_exception, exception);
Callable callable = CodeFactory::Call(isolate());
......
......@@ -22,6 +22,9 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
IteratorRecord GetIterator(Node* context, Node* object,
Label* if_exception = nullptr,
Variable* exception = nullptr);
IteratorRecord GetIterator(Node* context, Node* object, Node* method,
Label* if_exception = nullptr,
Variable* exception = nullptr);
// https://tc39.github.io/ecma262/#sec-iteratorstep
// Returns `false` if the iterator is done, otherwise returns an
......
......@@ -3,8 +3,10 @@
// found in the LICENSE file.
#include "src/builtins/builtins-constructor-gen.h"
#include "src/builtins/builtins-iterator-gen.h"
#include "src/builtins/builtins-utils-gen.h"
#include "src/builtins/builtins.h"
#include "src/builtins/growable-fixed-array-gen.h"
#include "src/code-stub-assembler.h"
#include "src/handles-inl.h"
......@@ -51,6 +53,9 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
TNode<HeapObject> array_like,
TNode<Object> initial_length,
TNode<Smi> element_size);
void ConstructByIterable(TNode<Context> context, TNode<JSTypedArray> holder,
TNode<JSReceiver> iterable,
TNode<Object> iterator_fn, TNode<Smi> element_size);
void SetupTypedArray(TNode<JSTypedArray> holder, TNode<Smi> length,
TNode<Number> byte_offset, TNode<Number> byte_length);
......@@ -745,17 +750,75 @@ void TypedArrayBuiltinsAssembler::ConstructByArrayLike(
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));
void TypedArrayBuiltinsAssembler::ConstructByIterable(
TNode<Context> context, TNode<JSTypedArray> holder,
TNode<JSReceiver> iterable, TNode<Object> iterator_fn,
TNode<Smi> element_size) {
CSA_ASSERT(this, IsCallable(iterator_fn));
Label fast_path(this), slow_path(this), done(this);
TVARIABLE(JSReceiver, array_like);
TVARIABLE(Object, initial_length);
// This is a fast-path for ignoring the iterator.
// TODO(petermarshall): Port to CSA.
Node* elided =
CallRuntime(Runtime::kIterableToListCanBeElided, context, iterable);
CSA_ASSERT(this, IsBoolean(elided));
Branch(IsTrue(elided), &fast_path, &slow_path);
BIND(&fast_path);
{
TNode<JSArray> js_array_iterable = CAST(iterable);
// This .length access is unobservable, because it being observable would
// mean that iteration has side effects, and we wouldn't reach this path.
array_like = js_array_iterable;
initial_length = LoadJSArrayLength(js_array_iterable);
Goto(&done);
}
BIND(&slow_path);
{
IteratorBuiltinsAssembler iterator_assembler(state());
// 1. Let iteratorRecord be ? GetIterator(items, method).
IteratorRecord iterator_record =
iterator_assembler.GetIterator(context, iterable, iterator_fn);
// 2. Let values be a new empty List.
GrowableFixedArray values(state());
Variable* vars[] = {values.var_array(), values.var_length(),
values.var_capacity()};
Label loop_start(this, 3, vars), loop_end(this);
Goto(&loop_start);
// 3. Let next be true.
// 4. Repeat, while next is not false
BIND(&loop_start);
{
// a. Set next to ? IteratorStep(iteratorRecord).
TNode<Object> next = CAST(
iterator_assembler.IteratorStep(context, iterator_record, &loop_end));
// b. If next is not false, then
// i. Let nextValue be ? IteratorValue(next).
TNode<Object> next_value =
CAST(iterator_assembler.IteratorValue(context, next));
// ii. Append nextValue to the end of the List values.
values.Push(next_value);
Goto(&loop_start);
}
BIND(&loop_end);
// 5. Return values.
TNode<JSArray> js_array_values = values.ToJSArray(context);
array_like = js_array_values;
initial_length = LoadJSArrayLength(js_array_values);
Goto(&done);
}
BIND(&done);
ConstructByArrayLike(context, holder, array_like, initial_length,
element_size);
Return(UndefinedConstant());
}
TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
......@@ -771,8 +834,7 @@ TF_BUILTIN(TypedArrayConstructor, TypedArrayBuiltinsAssembler) {
TF_BUILTIN(TypedArrayConstructor_ConstructStub, TypedArrayBuiltinsAssembler) {
Label if_arg1isbuffer(this), if_arg1istypedarray(this),
if_arg1isreceiver(this), if_iteratorundefined(this),
if_arg1isnumber(this), done(this);
if_arg1isreceiver(this), if_arg1isnumber(this), done(this);
TNode<Object> new_target = CAST(Parameter(BuiltinDescriptor::kNewTarget));
CSA_ASSERT(this, IsNotUndefined(new_target));
......@@ -811,18 +873,15 @@ TF_BUILTIN(TypedArrayConstructor_ConstructStub, TypedArrayBuiltinsAssembler) {
BIND(&if_arg1isreceiver);
{
Label if_iteratorundefined(this), if_iteratornotcallable(this);
// Get iterator symbol
TNode<Object> iteratorFn = CAST(
GetProperty(context, arg1, isolate()->factory()->iterator_symbol()));
GotoIf(IsUndefined(iteratorFn), &if_iteratorundefined);
// Call ConstructByIterable.
// TODO(petermarshall): Port ConstructByIterable to CSA.
Node* construct_iterable =
LoadContextElement(LoadNativeContext(context),
Context::TYPED_ARRAY_CONSTRUCT_BY_ITERABLE_INDEX);
CallJS(CodeFactory::Call(isolate()), context, construct_iterable,
UndefinedConstant(), holder, arg1, iteratorFn, element_size);
TNode<Object> iteratorFn =
CAST(GetMethod(context, arg1, isolate()->factory()->iterator_symbol(),
&if_iteratorundefined));
GotoIf(TaggedIsSmi(iteratorFn), &if_iteratornotcallable);
GotoIfNot(IsCallable(iteratorFn), &if_iteratornotcallable);
ConstructByIterable(context, holder, CAST(arg1), iteratorFn, element_size);
Goto(&done);
BIND(&if_iteratorundefined);
......@@ -835,6 +894,9 @@ TF_BUILTIN(TypedArrayConstructor_ConstructStub, TypedArrayBuiltinsAssembler) {
element_size);
Goto(&done);
}
BIND(&if_iteratornotcallable);
{ ThrowTypeError(context, MessageTemplate::kIteratorSymbolNonCallable); }
}
// First arg was a number or fell through and will be treated as a number.
......
......@@ -63,10 +63,6 @@ enum ContextLookupFlags {
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(TYPED_ARRAY_CONSTRUCT_BY_ARRAY_LIKE_INDEX, JSFunction, \
typed_array_construct_by_array_like) \
V(TYPED_ARRAY_CONSTRUCT_BY_ITERABLE_INDEX, JSFunction, \
typed_array_construct_by_iterable) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_POW_INDEX, JSFunction, math_pow) \
V(NEW_PROMISE_CAPABILITY_INDEX, JSFunction, new_promise_capability) \
......
......@@ -118,33 +118,6 @@ function TypedArraySpeciesCreate(exemplar, arg0, arg1, arg2) {
return TypedArrayCreate(constructor, arg0, arg1, arg2);
}
function TypedArrayConstructByIterable(obj, iterable, iteratorFn, elementSize) {
if (%IterableToListCanBeElided(iterable)) {
// This .length access is unobservable, because it being observable would
// mean that iteration has side effects, and we wouldn't reach this path.
%typed_array_construct_by_array_like(
obj, iterable, iterable.length, elementSize);
} else {
var list = new InternalArray();
// Reading the Symbol.iterator property of iterable twice would be
// observable with getters, so instead, we call the function which
// was already looked up, and wrap it in another iterable. The
// __proto__ of the new iterable is set to null to avoid any chance
// of modifications to Object.prototype being observable here.
var iterator = %_Call(iteratorFn, iterable);
var newIterable = {
__proto__: null
};
// TODO(littledan): Computed properties don't work yet in nosnap.
// Rephrase when they do.
newIterable[iteratorSymbol] = function() { return iterator; }
for (var value of newIterable) {
list.push(value);
}
%typed_array_construct_by_array_like(obj, list, list.length, elementSize);
}
}
// The following functions cannot be made efficient on sparse arrays while
// preserving the semantics, since the calls to the receiver function can add
// or delete elements from the array.
......@@ -307,8 +280,4 @@ function TypedArrayConstructor() {
%AddNamedProperty(GlobalTypedArray.prototype, "toString", ArrayToString,
DONT_ENUM);
%InstallToContext([
"typed_array_construct_by_iterable", TypedArrayConstructByIterable
]);
})
......@@ -340,6 +340,7 @@ class ErrorUtils : public AllStatic {
T(InvalidRegExpExecResult, \
"RegExp exec method returned something other than an Object or null") \
T(IteratorResultNotAnObject, "Iterator result % is not an object") \
T(IteratorSymbolNonCallable, "Found non-callable @@iterator") \
T(IteratorValueNotAnObject, "Iterator value % is not an entry object") \
T(LanguageID, "Language ID should be string or object.") \
T(MethodCalledOnWrongObject, \
......
......@@ -367,7 +367,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(18),
B(LdaConstant), U8(15),
B(Star), R(19),
......
......@@ -124,7 +124,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(19),
B(LdaConstant), U8(12),
B(Star), R(20),
......@@ -378,7 +378,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(19),
B(LdaConstant), U8(12),
B(Star), R(20),
......@@ -654,7 +654,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(19),
B(LdaConstant), U8(12),
B(Star), R(20),
......@@ -886,7 +886,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(17),
B(LdaConstant), U8(10),
B(Star), R(18),
......
......@@ -86,7 +86,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -220,7 +220,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(13),
B(LdaConstant), U8(8),
B(Star), R(14),
......@@ -366,7 +366,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(12),
B(LdaConstant), U8(8),
B(Star), R(13),
......@@ -502,7 +502,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(11),
B(LdaConstant), U8(10),
B(Star), R(12),
......
......@@ -90,7 +90,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(14),
B(LdaConstant), U8(7),
B(Star), R(15),
......@@ -261,7 +261,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(14),
B(LdaConstant), U8(11),
B(Star), R(15),
......@@ -408,7 +408,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(12),
B(LdaConstant), U8(9),
B(Star), R(13),
......@@ -503,7 +503,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(6),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(74),
B(LdaSmi), I8(75),
B(Star), R(18),
B(LdaConstant), U8(4),
B(Star), R(19),
......@@ -559,7 +559,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(17),
B(LdaConstant), U8(9),
B(Star), R(18),
......@@ -713,7 +713,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(16),
B(LdaConstant), U8(10),
B(Star), R(17),
......@@ -882,7 +882,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(15),
B(LdaConstant), U8(13),
B(Star), R(16),
......@@ -1037,7 +1037,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(21),
B(LdaConstant), U8(7),
B(Star), R(22),
......@@ -1253,7 +1253,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(20),
B(LdaConstant), U8(8),
B(Star), R(21),
......
......@@ -204,7 +204,7 @@ bytecodes: [
B(TestTypeOf), U8(6),
B(JumpIfFalse), U8(4),
B(Jump), U8(18),
B(Wide), B(LdaSmi), I16(144),
B(Wide), B(LdaSmi), I16(145),
B(Star), R(14),
B(LdaConstant), U8(14),
B(Star), R(15),
......
......@@ -231,7 +231,7 @@ bytecodes: [
B(JumpIfUndefined), U8(6),
B(Ldar), R(3),
B(JumpIfNotNull), U8(16),
B(LdaSmi), I8(74),
B(LdaSmi), I8(75),
B(Star), R(4),
B(LdaConstant), U8(1),
B(Star), R(5),
......
......@@ -120,6 +120,31 @@ tests.push(function TestConstructFromArrayNoIteratorWithGetter(constr) {
assertArrayEquals([1, 2, 22], ta);
});
tests.push(function TestConstructFromArrayNullIterator(constr) {
var arr = [1, 2, 3];
arr[Symbol.iterator] = null;
var ta = new Uint8Array(arr);
assertArrayEquals([1, 2, 3], ta);
});
tests.push(function TestConstructFromArrayUndefinedIterator(constr) {
var arr = [1, 2, 3];
arr[Symbol.iterator] = undefined;
var ta = new Uint8Array(arr);
assertArrayEquals([1, 2, 3], ta);
});
tests.push(function TestConstructFromArrayNonCallableIterator(constr) {
var arr = [1, 2, 3];
arr[Symbol.iterator] = 1;
assertThrows(() => new Uint8Array(arr), TypeError);
});
tests.push(function TestConstructFromArray(constr) {
var n = 64;
var jsArray = [];
......
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