diff options
Diffstat (limited to 'deps/v8/src/builtins/builtins-iterator-gen.cc')
-rw-r--r-- | deps/v8/src/builtins/builtins-iterator-gen.cc | 141 |
1 files changed, 93 insertions, 48 deletions
diff --git a/deps/v8/src/builtins/builtins-iterator-gen.cc b/deps/v8/src/builtins/builtins-iterator-gen.cc index 1e16a6b1de..802ed2edb2 100644 --- a/deps/v8/src/builtins/builtins-iterator-gen.cc +++ b/deps/v8/src/builtins/builtins-iterator-gen.cc @@ -5,6 +5,10 @@ #include "src/builtins/builtins-iterator-gen.h" #include "src/builtins/growable-fixed-array-gen.h" +#include "src/builtins/builtins-string-gen.h" +#include "src/builtins/builtins-utils-gen.h" +#include "src/builtins/builtins.h" +#include "src/code-stub-assembler.h" #include "src/heap/factory-inl.h" namespace v8 { @@ -38,8 +42,7 @@ IteratorRecord IteratorBuiltinsAssembler::GetIterator(Node* context, BIND(&if_not_callable); { - Node* ret = CallRuntime(Runtime::kThrowTypeError, context, - SmiConstant(MessageTemplate::kNotIterable), object); + Node* ret = CallRuntime(Runtime::kThrowIteratorError, context, object); GotoIfException(ret, if_exception, exception); Unreachable(); } @@ -197,62 +200,104 @@ void IteratorBuiltinsAssembler::IteratorCloseOnException( TNode<JSArray> IteratorBuiltinsAssembler::IterableToList( TNode<Context> context, TNode<Object> iterable, TNode<Object> iterator_fn) { - Label fast_path(this), slow_path(this), done(this); + // 1. Let iteratorRecord be ? GetIterator(items, method). + IteratorRecord iterator_record = 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), done(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(IteratorStep(context, iterator_record, &done)); + // b. If next is not false, then + // i. Let nextValue be ? IteratorValue(next). + TNode<Object> next_value = CAST(IteratorValue(context, next)); + // ii. Append nextValue to the end of the List values. + values.Push(next_value); + Goto(&loop_start); + } - TVARIABLE(JSArray, created_list); + BIND(&done); + return values.ToJSArray(context); +} - Branch(IsFastJSArrayWithNoCustomIteration(iterable, context), &fast_path, - &slow_path); +TF_BUILTIN(IterableToList, IteratorBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<Object> iterable = CAST(Parameter(Descriptor::kIterable)); + TNode<Object> iterator_fn = CAST(Parameter(Descriptor::kIteratorFn)); - // This is a fast-path for ignoring the iterator. - BIND(&fast_path); - { - TNode<JSArray> input_array = CAST(iterable); - created_list = CAST(CloneFastJSArray(context, input_array)); - Goto(&done); - } + Return(IterableToList(context, iterable, iterator_fn)); +} - BIND(&slow_path); - { - // 1. Let iteratorRecord be ? GetIterator(items, method). - IteratorRecord iterator_record = - GetIterator(context, iterable, iterator_fn); +// This builtin always returns a new JSArray and is thus safe to use even in the +// presence of code that may call back into user-JS. This builtin will take the +// fast path if the iterable is a fast array and the Array prototype and the +// Symbol.iterator is untouched. The fast path skips the iterator and copies the +// backing store to the new array. Note that if the array has holes, the holes +// will be copied to the new array, which is inconsistent with the behavior of +// an actual iteration, where holes should be replaced with undefined (if the +// prototype has no elements). To maintain the correct behavior for holey +// arrays, use the builtins IterableToList or IterableToListWithSymbolLookup. +TF_BUILTIN(IterableToListMayPreserveHoles, IteratorBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<Object> iterable = CAST(Parameter(Descriptor::kIterable)); + TNode<Object> iterator_fn = CAST(Parameter(Descriptor::kIteratorFn)); - // 2. Let values be a new empty List. - GrowableFixedArray values(state()); + Label slow_path(this); - 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(IteratorStep(context, iterator_record, &loop_end)); - // b. If next is not false, then - // i. Let nextValue be ? IteratorValue(next). - TNode<Object> next_value = CAST(IteratorValue(context, next)); - // ii. Append nextValue to the end of the List values. - values.Push(next_value); - Goto(&loop_start); - } - BIND(&loop_end); + GotoIfNot(IsFastJSArrayWithNoCustomIteration(iterable, context), &slow_path); - created_list = values.ToJSArray(context); - Goto(&done); - } + // The fast path will copy holes to the new array. + TailCallBuiltin(Builtins::kCloneFastJSArray, context, iterable); - BIND(&done); - return created_list.value(); + BIND(&slow_path); + TailCallBuiltin(Builtins::kIterableToList, context, iterable, iterator_fn); } -TNode<JSArray> IteratorBuiltinsAssembler::IterableToList( - TNode<Context> context, TNode<Object> iterable) { - TNode<Object> method = GetIteratorMethod(context, iterable); - return IterableToList(context, iterable, method); +// This builtin loads the property Symbol.iterator as the iterator, and has a +// fast path for fast arrays and another one for strings. These fast paths will +// only be taken if Symbol.iterator and the Iterator prototype are not modified +// in a way that changes the original iteration behavior. +// * In case of fast holey arrays, holes will be converted to undefined to +// reflect iteration semantics. Note that replacement by undefined is only +// correct when the NoElements protector is valid. +TF_BUILTIN(IterableToListWithSymbolLookup, IteratorBuiltinsAssembler) { + TNode<Context> context = CAST(Parameter(Descriptor::kContext)); + TNode<Object> iterable = CAST(Parameter(Descriptor::kIterable)); + + Label slow_path(this), check_string(this); + + GotoIfForceSlowPath(&slow_path); + + GotoIfNot(IsFastJSArrayWithNoCustomIteration(iterable, context), + &check_string); + + // Fast path for fast JSArray. + TailCallBuiltin(Builtins::kCloneFastJSArrayFillingHoles, context, iterable); + + BIND(&check_string); + { + StringBuiltinsAssembler string_assembler(state()); + GotoIfNot(string_assembler.IsStringPrimitiveWithNoCustomIteration(iterable, + context), + &slow_path); + + // Fast path for strings. + TailCallBuiltin(Builtins::kStringToList, context, iterable); + } + + BIND(&slow_path); + { + TNode<Object> iterator_fn = GetIteratorMethod(context, iterable); + TailCallBuiltin(Builtins::kIterableToList, context, iterable, iterator_fn); + } } } // namespace internal |