• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5namespace array {
6// Array.from( items [, mapfn [, thisArg ] ] )
7// ES #sec-array.from
8transitioning javascript builtin
9ArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(...arguments):
10    JSReceiver {
11  const c = HasBuiltinSubclassingFlag() ? receiver : GetArrayFunction();
12
13  // Use fast path if:
14  // * |items| is the only argument, and
15  // * the receiver is the Array function.
16  if (arguments.length == 1 && c == GetArrayFunction()) {
17    try {
18      return iterator::FastIterableToList(arguments[0]) otherwise Slow;
19    } label Slow {
20      // fall through
21    }
22  }
23
24  const items = arguments[0];
25  const mapfn = arguments[1];
26  const thisArg = arguments[2];
27
28  // 1. Let C be the this value.
29  // (Done above.)
30
31  let mapping: bool;
32  // 2. If mapfn is undefined, let mapping be false.
33  if (mapfn == Undefined) {
34    mapping = false;
35  } else {
36    // a. If IsCallable(mapfn) is false, throw a TypeError exception.
37    if (!Is<Callable>(mapfn)) deferred {
38        ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfn);
39      }
40    // b. Let mapping be true.
41    mapping = true;
42  }
43
44  // 4. Let usingIterator be ? GetMethod(items, @@iterator).
45  // 5. If usingIterator is not undefined, then
46  try {
47    const usingIterator = GetMethod(items, IteratorSymbolConstant())
48        otherwise IteratorIsUndefined, IteratorNotCallable;
49
50    let a: JSReceiver;
51    // a. If IsConstructor(C) is true, then
52    typeswitch (c) {
53      case (c: Constructor): {
54        // i. Let A be ? Construct(C).
55        a = Construct(c);
56      }
57      case (JSAny): {
58        // i. Let A be ? ArrayCreate(0).
59        a = ArrayCreate(0);
60      }
61    }
62
63    // c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator).
64    const iteratorRecord = iterator::GetIterator(items, usingIterator);
65
66    const fastIteratorResultMap = GetIteratorResultMap();
67
68    // d. Let k be 0.
69    let k: Smi = 0;
70    // e. Repeat,
71    while (true) {
72      // i. If k ≥ 2^53-1, then
73      //   1. Let error be ThrowCompletion(a newly created TypeError object).
74      //   2. Return ? IteratorClose(iteratorRecord, error).
75      // The spec requires that we throw an exception if index reaches 2^53-1,
76      // but an empty loop would take >100 days to do this many iterations. To
77      // actually run for that long would require an iterator that never set
78      // done to true and a target array which somehow never ran out of
79      // memory, e.g. a proxy that discarded the values. Ignoring this case
80      // just means we would repeatedly call CreateDataProperty with index =
81      // 2^53
82      dcheck(k < kMaxSafeInteger);
83
84      // ii. Let Pk be ! ToString(k).
85
86      // iii. Let next be ? IteratorStep(iteratorRecord).
87      let next: JSReceiver;
88      try {
89        next = iterator::IteratorStep(iteratorRecord, fastIteratorResultMap)
90            otherwise NextIsFalse;
91      }
92      // iv. If next is false, then
93      label NextIsFalse {
94        // 1. Perform ? Set(A, "length", k, true).
95        array::SetPropertyLength(a, k);
96        // 2. Return A.
97        return a;
98      }
99
100      // v. Let nextValue be ? IteratorValue(next).
101      const nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
102
103      let mappedValue: JSAny;
104      // vi. If mapping is true, then
105      if (mapping) {
106        // 1. Let mappedValue be Call(mapfn, thisArg, « nextValue, k »).
107        // 2. If mappedValue is an abrupt completion,
108        //    return ? IteratorClose(iteratorRecord, mappedValue).
109        // 3. Set mappedValue to mappedValue.[[Value]].
110        try {
111          mappedValue =
112              Call(context, UnsafeCast<Callable>(mapfn), thisArg, nextValue, k);
113        } catch (e, message) {
114          iterator::IteratorCloseOnException(iteratorRecord);
115          ReThrowWithMessage(context, e, message);
116        }
117      } else {
118        mappedValue = nextValue;
119      }
120      // viii. Let defineStatus be
121      //       CreateDataPropertyOrThrow(A, Pk, mappedValue).
122      // ix. If defineStatus is an abrupt completion,
123      //     return ? IteratorClose(iteratorRecord, defineStatus).
124      try {
125        FastCreateDataProperty(a, k, mappedValue);
126      } catch (e, message) deferred {
127        iterator::IteratorCloseOnException(iteratorRecord);
128        ReThrowWithMessage(context, e, message);
129      }
130      // x. Set k to k + 1.
131      k += 1;
132    }
133    unreachable;
134  } label IteratorIsUndefined {
135    // 6. NOTE: items is not an Iterable so assume it is an array-like object.
136    // 7. Let arrayLike be ! ToObject(items).
137    const arrayLike = ToObject_Inline(context, items);
138    // 8. Let len be ? LengthOfArrayLike(arrayLike).
139    const len = GetLengthProperty(arrayLike);
140
141    let a: JSReceiver;
142    // 9. If IsConstructor(C) is true, then
143    typeswitch (c) {
144      case (c: Constructor): {
145        // a. Let A be ? Construct(C, « len »).
146        a = Construct(c, len);
147      }
148      case (JSAny): {
149        // a. Let A be ? ArrayCreate(len).
150        a = ArrayCreate(len);
151      }
152    }
153
154    // 11. Let k be 0.
155    let k: Smi = 0;
156    // 12. Repeat, while k < len
157    while (k < len) {
158      // a. Let Pk be ! ToString(k).
159      // b. Let kValue be ? Get(arrayLike, Pk).
160      const kValue = GetProperty(arrayLike, k);
161      let mappedValue: JSAny;
162      // c. If mapping is true, then
163      if (mapping) {
164        // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
165        mappedValue =
166            Call(context, UnsafeCast<Callable>(mapfn), thisArg, kValue, k);
167      } else {
168        // d. Else, let mappedValue be kValue.
169        mappedValue = kValue;
170      }
171      // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
172      FastCreateDataProperty(a, k, mappedValue);
173      // f. Set k to k + 1.
174      k += 1;
175    }
176
177    // 13. Perform ? Set(A, "length", len, true).
178    array::SetPropertyLength(a, len);
179    // 14. Return A.
180    return a;
181  } label IteratorNotCallable(_value: JSAny) deferred {
182    ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable);
183  }
184}
185}
186