[Torque] port Array.from to torque
Bug: v8:9891 Change-Id: I320b5de731f1d3c03eb1b85de412e1f67196b049 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1985187 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#65654}
This commit is contained in:
parent
97f6ac945e
commit
53dfeb886d
1
BUILD.gn
1
BUILD.gn
@ -953,6 +953,7 @@ torque_files = [
|
|||||||
"src/builtins/array-find.tq",
|
"src/builtins/array-find.tq",
|
||||||
"src/builtins/array-findindex.tq",
|
"src/builtins/array-findindex.tq",
|
||||||
"src/builtins/array-foreach.tq",
|
"src/builtins/array-foreach.tq",
|
||||||
|
"src/builtins/array-from.tq",
|
||||||
"src/builtins/array-isarray.tq",
|
"src/builtins/array-isarray.tq",
|
||||||
"src/builtins/array-join.tq",
|
"src/builtins/array-join.tq",
|
||||||
"src/builtins/array-lastindexof.tq",
|
"src/builtins/array-lastindexof.tq",
|
||||||
|
184
src/builtins/array-from.tq
Normal file
184
src/builtins/array-from.tq
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
// Copyright 2019 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.
|
||||||
|
|
||||||
|
namespace array {
|
||||||
|
// Array.from( items [, mapfn [, thisArg ] ] )
|
||||||
|
// ES #sec-array.from
|
||||||
|
transitioning javascript builtin
|
||||||
|
ArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(...arguments):
|
||||||
|
JSReceiver {
|
||||||
|
// Use fast path if:
|
||||||
|
// * |items| is the only argument, and
|
||||||
|
// * the receiver is the Array function.
|
||||||
|
if (arguments.length == 1 && receiver == GetArrayFunction()) {
|
||||||
|
try {
|
||||||
|
return iterator::FastIterableToList(arguments[0]) otherwise Slow;
|
||||||
|
}
|
||||||
|
label Slow {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = arguments[0];
|
||||||
|
const mapfn = arguments[1];
|
||||||
|
const thisArg = arguments[2];
|
||||||
|
|
||||||
|
// 1. Let C be the this value.
|
||||||
|
const c = receiver;
|
||||||
|
|
||||||
|
let mapping: bool;
|
||||||
|
// 2. If mapfn is undefined, let mapping be false.
|
||||||
|
if (mapfn == Undefined) {
|
||||||
|
mapping = false;
|
||||||
|
} else {
|
||||||
|
// a. If IsCallable(mapfn) is false, throw a TypeError exception.
|
||||||
|
if (!TaggedIsCallable(mapfn)) deferred {
|
||||||
|
ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfn);
|
||||||
|
}
|
||||||
|
// b. Let mapping be true.
|
||||||
|
mapping = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Let usingIterator be ? GetMethod(items, @@iterator).
|
||||||
|
// 5. If usingIterator is not undefined, then
|
||||||
|
try {
|
||||||
|
const usingIterator = GetMethod(items, IteratorSymbolConstant())
|
||||||
|
otherwise IteratorIsUndefined, IteratorNotCallable;
|
||||||
|
|
||||||
|
let a: JSReceiver;
|
||||||
|
// a. If IsConstructor(C) is true, then
|
||||||
|
typeswitch (c) {
|
||||||
|
case (c: Constructor): {
|
||||||
|
// i. Let A be ? Construct(C).
|
||||||
|
a = Construct(c);
|
||||||
|
}
|
||||||
|
case (JSAny): {
|
||||||
|
// i. Let A be ? ArrayCreate(0).
|
||||||
|
a = ArrayCreate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator).
|
||||||
|
const iteratorRecord = iterator::GetIterator(items, usingIterator);
|
||||||
|
|
||||||
|
const fastIteratorResultMap = GetIteratorResultMap();
|
||||||
|
|
||||||
|
// d. Let k be 0.
|
||||||
|
let k: Smi = 0;
|
||||||
|
// e. Repeat,
|
||||||
|
while (true) {
|
||||||
|
// i. If k ≥ 2^53-1, then
|
||||||
|
// 1. Let error be ThrowCompletion(a newly created TypeError object).
|
||||||
|
// 2. Return ? IteratorClose(iteratorRecord, error).
|
||||||
|
// The spec requires that we throw an exception if index reaches 2^53-1,
|
||||||
|
// but an empty loop would take >100 days to do this many iterations. To
|
||||||
|
// actually run for that long would require an iterator that never set
|
||||||
|
// done to true and a target array which somehow never ran out of
|
||||||
|
// memory, e.g. a proxy that discarded the values. Ignoring this case
|
||||||
|
// just means we would repeatedly call CreateDataProperty with index =
|
||||||
|
// 2^53
|
||||||
|
assert(k < kMaxSafeInteger);
|
||||||
|
|
||||||
|
// ii. Let Pk be ! ToString(k).
|
||||||
|
|
||||||
|
// iii. Let next be ? IteratorStep(iteratorRecord).
|
||||||
|
let next: JSReceiver;
|
||||||
|
try {
|
||||||
|
next = iterator::IteratorStep(iteratorRecord, fastIteratorResultMap)
|
||||||
|
otherwise NextIsFalse;
|
||||||
|
}
|
||||||
|
// iv. If next is false, then
|
||||||
|
label NextIsFalse {
|
||||||
|
// 1. Perform ? Set(A, "length", k, true).
|
||||||
|
array::SetPropertyLength(a, k);
|
||||||
|
// 2. Return A.
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// v. Let nextValue be ? IteratorValue(next).
|
||||||
|
const nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
|
||||||
|
|
||||||
|
let mappedValue: JSAny;
|
||||||
|
// vi. If mapping is true, then
|
||||||
|
if (mapping) {
|
||||||
|
// 1. Let mappedValue be Call(mapfn, thisArg, « nextValue, k »).
|
||||||
|
// 2. If mappedValue is an abrupt completion,
|
||||||
|
// return ? IteratorClose(iteratorRecord, mappedValue).
|
||||||
|
// 3. Set mappedValue to mappedValue.[[Value]].
|
||||||
|
try {
|
||||||
|
mappedValue = Call(
|
||||||
|
context, UnsafeCast<Callable>(mapfn), thisArg, nextValue, k);
|
||||||
|
} catch (e) {
|
||||||
|
iterator::IteratorCloseOnException(iteratorRecord, e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mappedValue = nextValue;
|
||||||
|
}
|
||||||
|
// viii. Let defineStatus be
|
||||||
|
// CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||||
|
// ix. If defineStatus is an abrupt completion,
|
||||||
|
// return ? IteratorClose(iteratorRecord, defineStatus).
|
||||||
|
try {
|
||||||
|
FastCreateDataProperty(a, k, mappedValue);
|
||||||
|
} catch (e) deferred {
|
||||||
|
iterator::IteratorCloseOnException(iteratorRecord, e);
|
||||||
|
}
|
||||||
|
// x. Set k to k + 1.
|
||||||
|
k += 1;
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
label IteratorIsUndefined {
|
||||||
|
// 6. NOTE: items is not an Iterable so assume it is an array-like object.
|
||||||
|
// 7. Let arrayLike be ! ToObject(items).
|
||||||
|
const arrayLike = ToObject_Inline(context, items);
|
||||||
|
// 8. Let len be ? LengthOfArrayLike(arrayLike).
|
||||||
|
const len = GetLengthProperty(arrayLike);
|
||||||
|
|
||||||
|
let a: JSReceiver;
|
||||||
|
// 9. If IsConstructor(C) is true, then
|
||||||
|
typeswitch (c) {
|
||||||
|
case (c: Constructor): {
|
||||||
|
// a. Let A be ? Construct(C, « len »).
|
||||||
|
a = Construct(c, len);
|
||||||
|
}
|
||||||
|
case (JSAny): {
|
||||||
|
// a. Let A be ? ArrayCreate(len).
|
||||||
|
a = ArrayCreate(len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 11. Let k be 0.
|
||||||
|
let k: Smi = 0;
|
||||||
|
// 12. Repeat, while k < len
|
||||||
|
while (k < len) {
|
||||||
|
// a. Let Pk be ! ToString(k).
|
||||||
|
// b. Let kValue be ? Get(arrayLike, Pk).
|
||||||
|
const kValue = GetProperty(arrayLike, k);
|
||||||
|
let mappedValue: JSAny;
|
||||||
|
// c. If mapping is true, then
|
||||||
|
if (mapping) {
|
||||||
|
// i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
|
||||||
|
mappedValue =
|
||||||
|
Call(context, UnsafeCast<Callable>(mapfn), thisArg, kValue, k);
|
||||||
|
} else {
|
||||||
|
// d. Else, let mappedValue be kValue.
|
||||||
|
mappedValue = kValue;
|
||||||
|
}
|
||||||
|
// e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
|
||||||
|
FastCreateDataProperty(a, k, mappedValue);
|
||||||
|
// f. Set k to k + 1.
|
||||||
|
k += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 13. Perform ? Set(A, "length", len, true).
|
||||||
|
array::SetPropertyLength(a, len);
|
||||||
|
// 14. Return A.
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
label IteratorNotCallable(_value: JSAny) deferred {
|
||||||
|
ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -231,6 +231,7 @@ const kBigIntMaxLength: constexpr intptr generates 'BigInt::kMaxLength';
|
|||||||
extern enum MessageTemplate {
|
extern enum MessageTemplate {
|
||||||
kInvalidArrayBufferLength,
|
kInvalidArrayBufferLength,
|
||||||
kInvalidArrayLength,
|
kInvalidArrayLength,
|
||||||
|
kInvalidIndex,
|
||||||
kNotConstructor,
|
kNotConstructor,
|
||||||
kCalledNonCallable,
|
kCalledNonCallable,
|
||||||
kCalledOnNullOrUndefined,
|
kCalledOnNullOrUndefined,
|
||||||
@ -465,6 +466,7 @@ extern macro BuildAppendJSArray(
|
|||||||
extern macro EnsureArrayPushable(implicit context: Context)(Map): ElementsKind
|
extern macro EnsureArrayPushable(implicit context: Context)(Map): ElementsKind
|
||||||
labels Bailout;
|
labels Bailout;
|
||||||
// TODO: Reduce duplication once varargs are supported in macros.
|
// TODO: Reduce duplication once varargs are supported in macros.
|
||||||
|
extern macro Construct(implicit context: Context)(Constructor): JSReceiver;
|
||||||
extern macro Construct(implicit context: Context)(
|
extern macro Construct(implicit context: Context)(
|
||||||
Constructor, JSAny): JSReceiver;
|
Constructor, JSAny): JSReceiver;
|
||||||
extern macro Construct(implicit context: Context)(
|
extern macro Construct(implicit context: Context)(
|
||||||
@ -951,6 +953,10 @@ macro GetObjectFunction(implicit context: Context)(): JSFunction {
|
|||||||
return UnsafeCast<JSFunction>(
|
return UnsafeCast<JSFunction>(
|
||||||
LoadNativeContext(context)[NativeContextSlot::OBJECT_FUNCTION_INDEX]);
|
LoadNativeContext(context)[NativeContextSlot::OBJECT_FUNCTION_INDEX]);
|
||||||
}
|
}
|
||||||
|
macro GetArrayFunction(implicit context: Context)(): JSFunction {
|
||||||
|
return UnsafeCast<JSFunction>(
|
||||||
|
LoadNativeContext(context)[NativeContextSlot::ARRAY_FUNCTION_INDEX]);
|
||||||
|
}
|
||||||
macro GetArrayBufferFunction(implicit context: Context)(): Constructor {
|
macro GetArrayBufferFunction(implicit context: Context)(): Constructor {
|
||||||
return UnsafeCast<Constructor>(
|
return UnsafeCast<Constructor>(
|
||||||
LoadNativeContext(context)[NativeContextSlot::ARRAY_BUFFER_FUN_INDEX]);
|
LoadNativeContext(context)[NativeContextSlot::ARRAY_BUFFER_FUN_INDEX]);
|
||||||
|
@ -543,219 +543,6 @@ class ArrayPopulatorAssembler : public CodeStubAssembler {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ES #sec-array.from
|
|
||||||
TF_BUILTIN(ArrayFrom, ArrayPopulatorAssembler) {
|
|
||||||
TNode<Context> context = CAST(Parameter(Descriptor::kContext));
|
|
||||||
TNode<Int32T> argc =
|
|
||||||
UncheckedCast<Int32T>(Parameter(Descriptor::kJSActualArgumentsCount));
|
|
||||||
|
|
||||||
CodeStubArguments args(this, argc);
|
|
||||||
TNode<Object> items = args.GetOptionalArgumentValue(0);
|
|
||||||
TNode<Object> receiver = args.GetReceiver();
|
|
||||||
|
|
||||||
Label fast_iterate(this), normal_iterate(this);
|
|
||||||
|
|
||||||
// Use fast path if:
|
|
||||||
// * |items| is the only argument, and
|
|
||||||
// * the receiver is the Array function.
|
|
||||||
GotoIfNot(Word32Equal(argc, Int32Constant(1)), &normal_iterate);
|
|
||||||
TNode<Object> array_function = LoadContextElement(
|
|
||||||
LoadNativeContext(context), Context::ARRAY_FUNCTION_INDEX);
|
|
||||||
Branch(TaggedEqual(array_function, receiver), &fast_iterate, &normal_iterate);
|
|
||||||
|
|
||||||
BIND(&fast_iterate);
|
|
||||||
{
|
|
||||||
IteratorBuiltinsAssembler iterator_assembler(state());
|
|
||||||
TVARIABLE(Object, var_fast_result);
|
|
||||||
iterator_assembler.FastIterableToList(context, items, &var_fast_result,
|
|
||||||
&normal_iterate);
|
|
||||||
args.PopAndReturn(var_fast_result.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(&normal_iterate);
|
|
||||||
TNode<Object> map_function = args.GetOptionalArgumentValue(1);
|
|
||||||
|
|
||||||
// If map_function is not undefined, then ensure it's callable else throw.
|
|
||||||
{
|
|
||||||
Label no_error(this), error(this);
|
|
||||||
GotoIf(IsUndefined(map_function), &no_error);
|
|
||||||
GotoIf(TaggedIsSmi(map_function), &error);
|
|
||||||
Branch(IsCallable(CAST(map_function)), &no_error, &error);
|
|
||||||
|
|
||||||
BIND(&error);
|
|
||||||
ThrowTypeError(context, MessageTemplate::kCalledNonCallable, map_function);
|
|
||||||
|
|
||||||
BIND(&no_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
Label iterable(this), not_iterable(this), finished(this), if_exception(this);
|
|
||||||
|
|
||||||
TNode<Object> this_arg = args.GetOptionalArgumentValue(2);
|
|
||||||
// The spec doesn't require ToObject to be called directly on the iterable
|
|
||||||
// branch, but it's part of GetMethod that is in the spec.
|
|
||||||
TNode<JSReceiver> array_like = ToObject_Inline(context, items);
|
|
||||||
|
|
||||||
TVARIABLE(Object, array);
|
|
||||||
TVARIABLE(Number, length);
|
|
||||||
|
|
||||||
// Determine whether items[Symbol.iterator] is defined:
|
|
||||||
IteratorBuiltinsAssembler iterator_assembler(state());
|
|
||||||
TNode<Object> iterator_method =
|
|
||||||
iterator_assembler.GetIteratorMethod(context, array_like);
|
|
||||||
Branch(IsNullOrUndefined(iterator_method), ¬_iterable, &iterable);
|
|
||||||
|
|
||||||
BIND(&iterable);
|
|
||||||
{
|
|
||||||
TVARIABLE(Number, index, SmiConstant(0));
|
|
||||||
TVARIABLE(Object, var_exception);
|
|
||||||
Label loop(this, &index), loop_done(this),
|
|
||||||
on_exception(this, Label::kDeferred),
|
|
||||||
index_overflow(this, Label::kDeferred);
|
|
||||||
|
|
||||||
// Check that the method is callable.
|
|
||||||
{
|
|
||||||
Label get_method_not_callable(this, Label::kDeferred), next(this);
|
|
||||||
GotoIf(TaggedIsSmi(iterator_method), &get_method_not_callable);
|
|
||||||
GotoIfNot(IsCallable(CAST(iterator_method)), &get_method_not_callable);
|
|
||||||
Goto(&next);
|
|
||||||
|
|
||||||
BIND(&get_method_not_callable);
|
|
||||||
ThrowTypeError(context, MessageTemplate::kCalledNonCallable,
|
|
||||||
iterator_method);
|
|
||||||
|
|
||||||
BIND(&next);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the output array with empty length.
|
|
||||||
array = ConstructArrayLike(context, receiver);
|
|
||||||
|
|
||||||
// Actually get the iterator and throw if the iterator method does not yield
|
|
||||||
// one.
|
|
||||||
IteratorRecord iterator_record =
|
|
||||||
iterator_assembler.GetIterator(context, items, iterator_method);
|
|
||||||
|
|
||||||
TNode<NativeContext> native_context = LoadNativeContext(context);
|
|
||||||
TNode<Map> fast_iterator_result_map = CAST(
|
|
||||||
LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX));
|
|
||||||
|
|
||||||
Goto(&loop);
|
|
||||||
|
|
||||||
BIND(&loop);
|
|
||||||
{
|
|
||||||
// Loop while iterator is not done.
|
|
||||||
TNode<JSReceiver> next = iterator_assembler.IteratorStep(
|
|
||||||
context, iterator_record, &loop_done, fast_iterator_result_map);
|
|
||||||
TVARIABLE(Object, value,
|
|
||||||
iterator_assembler.IteratorValue(context, next,
|
|
||||||
fast_iterator_result_map));
|
|
||||||
|
|
||||||
// If a map_function is supplied then call it (using this_arg as
|
|
||||||
// receiver), on the value returned from the iterator. Exceptions are
|
|
||||||
// caught so the iterator can be closed.
|
|
||||||
{
|
|
||||||
Label next(this);
|
|
||||||
GotoIf(IsUndefined(map_function), &next);
|
|
||||||
|
|
||||||
CSA_ASSERT(this, IsCallable(CAST(map_function)));
|
|
||||||
TNode<Object> v =
|
|
||||||
CallJS(CodeFactory::Call(isolate()), context, map_function,
|
|
||||||
this_arg, value.value(), index.value());
|
|
||||||
GotoIfException(v, &on_exception, &var_exception);
|
|
||||||
value = v;
|
|
||||||
Goto(&next);
|
|
||||||
BIND(&next);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the result in the output object (catching any exceptions so the
|
|
||||||
// iterator can be closed).
|
|
||||||
TNode<Object> define_status =
|
|
||||||
CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
|
|
||||||
index.value(), value.value());
|
|
||||||
GotoIfException(define_status, &on_exception, &var_exception);
|
|
||||||
|
|
||||||
index = NumberInc(index.value());
|
|
||||||
|
|
||||||
// The spec requires that we throw an exception if index reaches 2^53-1,
|
|
||||||
// but an empty loop would take >100 days to do this many iterations. To
|
|
||||||
// actually run for that long would require an iterator that never set
|
|
||||||
// done to true and a target array which somehow never ran out of memory,
|
|
||||||
// e.g. a proxy that discarded the values. Ignoring this case just means
|
|
||||||
// we would repeatedly call CreateDataProperty with index = 2^53.
|
|
||||||
CSA_ASSERT_BRANCH(this, [&](Label* ok, Label* not_ok) {
|
|
||||||
BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
|
|
||||||
NumberConstant(kMaxSafeInteger), ok,
|
|
||||||
not_ok);
|
|
||||||
});
|
|
||||||
Goto(&loop);
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(&loop_done);
|
|
||||||
{
|
|
||||||
length = index;
|
|
||||||
Goto(&finished);
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(&on_exception);
|
|
||||||
{
|
|
||||||
// Close the iterator, rethrowing either the passed exception or
|
|
||||||
// exceptions thrown during the close.
|
|
||||||
iterator_assembler.IteratorCloseOnException(context, iterator_record,
|
|
||||||
var_exception.value());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(¬_iterable);
|
|
||||||
{
|
|
||||||
// Treat array_like as an array and try to get its length.
|
|
||||||
length = ToLength_Inline(
|
|
||||||
context, GetProperty(context, array_like, factory()->length_string()));
|
|
||||||
|
|
||||||
// Construct an array using the receiver as constructor with the same length
|
|
||||||
// as the input array.
|
|
||||||
array = ConstructArrayLike(context, receiver, length.value());
|
|
||||||
|
|
||||||
TVARIABLE(Number, index, SmiConstant(0));
|
|
||||||
|
|
||||||
GotoIf(TaggedEqual(length.value(), SmiConstant(0)), &finished);
|
|
||||||
|
|
||||||
// Loop from 0 to length-1.
|
|
||||||
{
|
|
||||||
Label loop(this, &index);
|
|
||||||
Goto(&loop);
|
|
||||||
BIND(&loop);
|
|
||||||
TVARIABLE(Object, value);
|
|
||||||
|
|
||||||
value = GetProperty(context, array_like, index.value());
|
|
||||||
|
|
||||||
// If a map_function is supplied then call it (using this_arg as
|
|
||||||
// receiver), on the value retrieved from the array.
|
|
||||||
{
|
|
||||||
Label next(this);
|
|
||||||
GotoIf(IsUndefined(map_function), &next);
|
|
||||||
|
|
||||||
CSA_ASSERT(this, IsCallable(CAST(map_function)));
|
|
||||||
value = CallJS(CodeFactory::Call(isolate()), context, map_function,
|
|
||||||
this_arg, value.value(), index.value());
|
|
||||||
Goto(&next);
|
|
||||||
BIND(&next);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the result in the output object.
|
|
||||||
CallRuntime(Runtime::kCreateDataProperty, context, array.value(),
|
|
||||||
index.value(), value.value());
|
|
||||||
index = NumberInc(index.value());
|
|
||||||
BranchIfNumberRelationalComparison(Operation::kLessThan, index.value(),
|
|
||||||
length.value(), &loop, &finished);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BIND(&finished);
|
|
||||||
|
|
||||||
// Finally set the length on the output and return it.
|
|
||||||
SetPropertyLength(context, array.value(), length.value());
|
|
||||||
args.PopAndReturn(array.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
|
TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinsAssembler) {
|
||||||
TNode<IntPtrT> argc =
|
TNode<IntPtrT> argc =
|
||||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||||
|
@ -304,8 +304,6 @@ namespace internal {
|
|||||||
CPP(ArrayConcat) \
|
CPP(ArrayConcat) \
|
||||||
/* ES6 #sec-array.prototype.fill */ \
|
/* ES6 #sec-array.prototype.fill */ \
|
||||||
CPP(ArrayPrototypeFill) \
|
CPP(ArrayPrototypeFill) \
|
||||||
/* ES6 #sec-array.from */ \
|
|
||||||
TFJ(ArrayFrom, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
|
||||||
/* ES7 #sec-array.prototype.includes */ \
|
/* ES7 #sec-array.prototype.includes */ \
|
||||||
TFS(ArrayIncludesSmiOrObject, kElements, kSearchElement, kLength, \
|
TFS(ArrayIncludesSmiOrObject, kElements, kSearchElement, kLength, \
|
||||||
kFromIndex) \
|
kFromIndex) \
|
||||||
|
@ -368,7 +368,7 @@ TF_BUILTIN(IterableToListMayPreserveHoles, IteratorBuiltinsAssembler) {
|
|||||||
|
|
||||||
void IteratorBuiltinsAssembler::FastIterableToList(
|
void IteratorBuiltinsAssembler::FastIterableToList(
|
||||||
TNode<Context> context, TNode<Object> iterable,
|
TNode<Context> context, TNode<Object> iterable,
|
||||||
TVariable<Object>* var_result, Label* slow) {
|
TVariable<JSArray>* var_result, Label* slow) {
|
||||||
Label done(this), check_string(this), check_map(this), check_set(this);
|
Label done(this), check_string(this), check_map(this), check_set(this);
|
||||||
|
|
||||||
GotoIfNot(
|
GotoIfNot(
|
||||||
@ -377,8 +377,8 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
|||||||
&check_string);
|
&check_string);
|
||||||
|
|
||||||
// Fast path for fast JSArray.
|
// Fast path for fast JSArray.
|
||||||
*var_result =
|
*var_result = CAST(
|
||||||
CallBuiltin(Builtins::kCloneFastJSArrayFillingHoles, context, iterable);
|
CallBuiltin(Builtins::kCloneFastJSArrayFillingHoles, context, iterable));
|
||||||
Goto(&done);
|
Goto(&done);
|
||||||
|
|
||||||
BIND(&check_string);
|
BIND(&check_string);
|
||||||
@ -394,7 +394,7 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
|||||||
GotoIf(
|
GotoIf(
|
||||||
IntPtrGreaterThan(length, IntPtrConstant(JSArray::kMaxFastArrayLength)),
|
IntPtrGreaterThan(length, IntPtrConstant(JSArray::kMaxFastArrayLength)),
|
||||||
slow);
|
slow);
|
||||||
*var_result = CallBuiltin(Builtins::kStringToList, context, iterable);
|
*var_result = CAST(CallBuiltin(Builtins::kStringToList, context, iterable));
|
||||||
Goto(&done);
|
Goto(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -405,7 +405,8 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
|||||||
state(), iterable, context, &map_fast_call, &check_set);
|
state(), iterable, context, &map_fast_call, &check_set);
|
||||||
|
|
||||||
BIND(&map_fast_call);
|
BIND(&map_fast_call);
|
||||||
*var_result = CallBuiltin(Builtins::kMapIteratorToList, context, iterable);
|
*var_result =
|
||||||
|
CAST(CallBuiltin(Builtins::kMapIteratorToList, context, iterable));
|
||||||
Goto(&done);
|
Goto(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,13 +418,20 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
|||||||
|
|
||||||
BIND(&set_fast_call);
|
BIND(&set_fast_call);
|
||||||
*var_result =
|
*var_result =
|
||||||
CallBuiltin(Builtins::kSetOrSetIteratorToList, context, iterable);
|
CAST(CallBuiltin(Builtins::kSetOrSetIteratorToList, context, iterable));
|
||||||
Goto(&done);
|
Goto(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
BIND(&done);
|
BIND(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<JSArray> IteratorBuiltinsAssembler::FastIterableToList(
|
||||||
|
TNode<Context> context, TNode<Object> iterable, Label* slow) {
|
||||||
|
TVARIABLE(JSArray, var_fast_result);
|
||||||
|
FastIterableToList(context, iterable, &var_fast_result, slow);
|
||||||
|
return var_fast_result.value();
|
||||||
|
}
|
||||||
|
|
||||||
// This builtin loads the property Symbol.iterator as the iterator, and has fast
|
// This builtin loads the property Symbol.iterator as the iterator, and has fast
|
||||||
// paths for fast arrays, for primitive strings, for sets and set iterators, and
|
// paths for fast arrays, for primitive strings, for sets and set iterators, and
|
||||||
// for map iterators. These fast paths will only be taken if Symbol.iterator and
|
// for map iterators. These fast paths will only be taken if Symbol.iterator and
|
||||||
@ -443,7 +451,7 @@ TF_BUILTIN(IterableToListWithSymbolLookup, IteratorBuiltinsAssembler) {
|
|||||||
|
|
||||||
GotoIfForceSlowPath(&slow_path);
|
GotoIfForceSlowPath(&slow_path);
|
||||||
|
|
||||||
TVARIABLE(Object, var_result);
|
TVARIABLE(JSArray, var_result);
|
||||||
FastIterableToList(context, iterable, &var_result, &slow_path);
|
FastIterableToList(context, iterable, &var_result, &slow_path);
|
||||||
Return(var_result.value());
|
Return(var_result.value());
|
||||||
|
|
||||||
|
@ -79,7 +79,9 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
|
|||||||
TNode<Object> iterable);
|
TNode<Object> iterable);
|
||||||
|
|
||||||
void FastIterableToList(TNode<Context> context, TNode<Object> iterable,
|
void FastIterableToList(TNode<Context> context, TNode<Object> iterable,
|
||||||
TVariable<Object>* var_result, Label* slow);
|
TVariable<JSArray>* var_result, Label* slow);
|
||||||
|
TNode<JSArray> FastIterableToList(TNode<Context> context,
|
||||||
|
TNode<Object> iterable, Label* slow);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
@ -15,10 +15,15 @@ namespace iterator {
|
|||||||
next: JSAny;
|
next: JSAny;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern macro IteratorBuiltinsAssembler::FastIterableToList(
|
||||||
|
implicit context: Context)(JSAny): JSArray labels Slow;
|
||||||
|
|
||||||
extern macro IteratorBuiltinsAssembler::GetIteratorMethod(
|
extern macro IteratorBuiltinsAssembler::GetIteratorMethod(
|
||||||
implicit context: Context)(JSAny): JSAny;
|
implicit context: Context)(JSAny): JSAny;
|
||||||
extern macro IteratorBuiltinsAssembler::GetIterator(
|
extern macro IteratorBuiltinsAssembler::GetIterator(
|
||||||
implicit context: Context)(JSAny): IteratorRecord;
|
implicit context: Context)(JSAny): IteratorRecord;
|
||||||
|
extern macro IteratorBuiltinsAssembler::GetIterator(
|
||||||
|
implicit context: Context)(JSAny, JSAny): IteratorRecord;
|
||||||
|
|
||||||
extern macro IteratorBuiltinsAssembler::IteratorStep(
|
extern macro IteratorBuiltinsAssembler::IteratorStep(
|
||||||
implicit context: Context)(IteratorRecord): JSReceiver
|
implicit context: Context)(IteratorRecord): JSReceiver
|
||||||
|
@ -27,6 +27,7 @@ extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
|
|||||||
ARRAY_BUFFER_FUN_INDEX,
|
ARRAY_BUFFER_FUN_INDEX,
|
||||||
ARRAY_BUFFER_NOINIT_FUN_INDEX,
|
ARRAY_BUFFER_NOINIT_FUN_INDEX,
|
||||||
ARRAY_BUFFER_MAP_INDEX,
|
ARRAY_BUFFER_MAP_INDEX,
|
||||||
|
ARRAY_FUNCTION_INDEX,
|
||||||
ARRAY_JOIN_STACK_INDEX,
|
ARRAY_JOIN_STACK_INDEX,
|
||||||
OBJECT_FUNCTION_INDEX,
|
OBJECT_FUNCTION_INDEX,
|
||||||
ITERATOR_RESULT_MAP_INDEX,
|
ITERATOR_RESULT_MAP_INDEX,
|
||||||
|
Loading…
Reference in New Issue
Block a user