[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-findindex.tq",
|
||||
"src/builtins/array-foreach.tq",
|
||||
"src/builtins/array-from.tq",
|
||||
"src/builtins/array-isarray.tq",
|
||||
"src/builtins/array-join.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 {
|
||||
kInvalidArrayBufferLength,
|
||||
kInvalidArrayLength,
|
||||
kInvalidIndex,
|
||||
kNotConstructor,
|
||||
kCalledNonCallable,
|
||||
kCalledOnNullOrUndefined,
|
||||
@ -465,6 +466,7 @@ extern macro BuildAppendJSArray(
|
||||
extern macro EnsureArrayPushable(implicit context: Context)(Map): ElementsKind
|
||||
labels Bailout;
|
||||
// TODO: Reduce duplication once varargs are supported in macros.
|
||||
extern macro Construct(implicit context: Context)(Constructor): JSReceiver;
|
||||
extern macro Construct(implicit context: Context)(
|
||||
Constructor, JSAny): JSReceiver;
|
||||
extern macro Construct(implicit context: Context)(
|
||||
@ -951,6 +953,10 @@ macro GetObjectFunction(implicit context: Context)(): JSFunction {
|
||||
return UnsafeCast<JSFunction>(
|
||||
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 {
|
||||
return UnsafeCast<Constructor>(
|
||||
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) {
|
||||
TNode<IntPtrT> argc =
|
||||
ChangeInt32ToIntPtr(Parameter(Descriptor::kJSActualArgumentsCount));
|
||||
|
@ -304,8 +304,6 @@ namespace internal {
|
||||
CPP(ArrayConcat) \
|
||||
/* ES6 #sec-array.prototype.fill */ \
|
||||
CPP(ArrayPrototypeFill) \
|
||||
/* ES6 #sec-array.from */ \
|
||||
TFJ(ArrayFrom, SharedFunctionInfo::kDontAdaptArgumentsSentinel) \
|
||||
/* ES7 #sec-array.prototype.includes */ \
|
||||
TFS(ArrayIncludesSmiOrObject, kElements, kSearchElement, kLength, \
|
||||
kFromIndex) \
|
||||
|
@ -368,7 +368,7 @@ TF_BUILTIN(IterableToListMayPreserveHoles, IteratorBuiltinsAssembler) {
|
||||
|
||||
void IteratorBuiltinsAssembler::FastIterableToList(
|
||||
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);
|
||||
|
||||
GotoIfNot(
|
||||
@ -377,8 +377,8 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
||||
&check_string);
|
||||
|
||||
// Fast path for fast JSArray.
|
||||
*var_result =
|
||||
CallBuiltin(Builtins::kCloneFastJSArrayFillingHoles, context, iterable);
|
||||
*var_result = CAST(
|
||||
CallBuiltin(Builtins::kCloneFastJSArrayFillingHoles, context, iterable));
|
||||
Goto(&done);
|
||||
|
||||
BIND(&check_string);
|
||||
@ -394,7 +394,7 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
||||
GotoIf(
|
||||
IntPtrGreaterThan(length, IntPtrConstant(JSArray::kMaxFastArrayLength)),
|
||||
slow);
|
||||
*var_result = CallBuiltin(Builtins::kStringToList, context, iterable);
|
||||
*var_result = CAST(CallBuiltin(Builtins::kStringToList, context, iterable));
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
@ -405,7 +405,8 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
||||
state(), iterable, context, &map_fast_call, &check_set);
|
||||
|
||||
BIND(&map_fast_call);
|
||||
*var_result = CallBuiltin(Builtins::kMapIteratorToList, context, iterable);
|
||||
*var_result =
|
||||
CAST(CallBuiltin(Builtins::kMapIteratorToList, context, iterable));
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
@ -417,13 +418,20 @@ void IteratorBuiltinsAssembler::FastIterableToList(
|
||||
|
||||
BIND(&set_fast_call);
|
||||
*var_result =
|
||||
CallBuiltin(Builtins::kSetOrSetIteratorToList, context, iterable);
|
||||
CAST(CallBuiltin(Builtins::kSetOrSetIteratorToList, context, iterable));
|
||||
Goto(&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
|
||||
// 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
|
||||
@ -443,7 +451,7 @@ TF_BUILTIN(IterableToListWithSymbolLookup, IteratorBuiltinsAssembler) {
|
||||
|
||||
GotoIfForceSlowPath(&slow_path);
|
||||
|
||||
TVARIABLE(Object, var_result);
|
||||
TVARIABLE(JSArray, var_result);
|
||||
FastIterableToList(context, iterable, &var_result, &slow_path);
|
||||
Return(var_result.value());
|
||||
|
||||
|
@ -79,7 +79,9 @@ class IteratorBuiltinsAssembler : public CodeStubAssembler {
|
||||
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
|
||||
|
@ -15,10 +15,15 @@ namespace iterator {
|
||||
next: JSAny;
|
||||
}
|
||||
|
||||
extern macro IteratorBuiltinsAssembler::FastIterableToList(
|
||||
implicit context: Context)(JSAny): JSArray labels Slow;
|
||||
|
||||
extern macro IteratorBuiltinsAssembler::GetIteratorMethod(
|
||||
implicit context: Context)(JSAny): JSAny;
|
||||
extern macro IteratorBuiltinsAssembler::GetIterator(
|
||||
implicit context: Context)(JSAny): IteratorRecord;
|
||||
extern macro IteratorBuiltinsAssembler::GetIterator(
|
||||
implicit context: Context)(JSAny, JSAny): IteratorRecord;
|
||||
|
||||
extern macro IteratorBuiltinsAssembler::IteratorStep(
|
||||
implicit context: Context)(IteratorRecord): JSReceiver
|
||||
|
@ -27,6 +27,7 @@ extern enum NativeContextSlot extends intptr constexpr 'Context::Field' {
|
||||
ARRAY_BUFFER_FUN_INDEX,
|
||||
ARRAY_BUFFER_NOINIT_FUN_INDEX,
|
||||
ARRAY_BUFFER_MAP_INDEX,
|
||||
ARRAY_FUNCTION_INDEX,
|
||||
ARRAY_JOIN_STACK_INDEX,
|
||||
OBJECT_FUNCTION_INDEX,
|
||||
ITERATOR_RESULT_MAP_INDEX,
|
||||
|
Loading…
Reference in New Issue
Block a user