11cb0ef41Sopenharmony_ci// Copyright 2019 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_cinamespace array {
61cb0ef41Sopenharmony_ci// Array.from( items [, mapfn [, thisArg ] ] )
71cb0ef41Sopenharmony_ci// ES #sec-array.from
81cb0ef41Sopenharmony_citransitioning javascript builtin
91cb0ef41Sopenharmony_ciArrayFrom(js-implicit context: NativeContext, receiver: JSAny)(...arguments):
101cb0ef41Sopenharmony_ci    JSReceiver {
111cb0ef41Sopenharmony_ci  const c = HasBuiltinSubclassingFlag() ? receiver : GetArrayFunction();
121cb0ef41Sopenharmony_ci
131cb0ef41Sopenharmony_ci  // Use fast path if:
141cb0ef41Sopenharmony_ci  // * |items| is the only argument, and
151cb0ef41Sopenharmony_ci  // * the receiver is the Array function.
161cb0ef41Sopenharmony_ci  if (arguments.length == 1 && c == GetArrayFunction()) {
171cb0ef41Sopenharmony_ci    try {
181cb0ef41Sopenharmony_ci      return iterator::FastIterableToList(arguments[0]) otherwise Slow;
191cb0ef41Sopenharmony_ci    } label Slow {
201cb0ef41Sopenharmony_ci      // fall through
211cb0ef41Sopenharmony_ci    }
221cb0ef41Sopenharmony_ci  }
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci  const items = arguments[0];
251cb0ef41Sopenharmony_ci  const mapfn = arguments[1];
261cb0ef41Sopenharmony_ci  const thisArg = arguments[2];
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci  // 1. Let C be the this value.
291cb0ef41Sopenharmony_ci  // (Done above.)
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci  let mapping: bool;
321cb0ef41Sopenharmony_ci  // 2. If mapfn is undefined, let mapping be false.
331cb0ef41Sopenharmony_ci  if (mapfn == Undefined) {
341cb0ef41Sopenharmony_ci    mapping = false;
351cb0ef41Sopenharmony_ci  } else {
361cb0ef41Sopenharmony_ci    // a. If IsCallable(mapfn) is false, throw a TypeError exception.
371cb0ef41Sopenharmony_ci    if (!Is<Callable>(mapfn)) deferred {
381cb0ef41Sopenharmony_ci        ThrowTypeError(MessageTemplate::kCalledNonCallable, mapfn);
391cb0ef41Sopenharmony_ci      }
401cb0ef41Sopenharmony_ci    // b. Let mapping be true.
411cb0ef41Sopenharmony_ci    mapping = true;
421cb0ef41Sopenharmony_ci  }
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ci  // 4. Let usingIterator be ? GetMethod(items, @@iterator).
451cb0ef41Sopenharmony_ci  // 5. If usingIterator is not undefined, then
461cb0ef41Sopenharmony_ci  try {
471cb0ef41Sopenharmony_ci    const usingIterator = GetMethod(items, IteratorSymbolConstant())
481cb0ef41Sopenharmony_ci        otherwise IteratorIsUndefined, IteratorNotCallable;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci    let a: JSReceiver;
511cb0ef41Sopenharmony_ci    // a. If IsConstructor(C) is true, then
521cb0ef41Sopenharmony_ci    typeswitch (c) {
531cb0ef41Sopenharmony_ci      case (c: Constructor): {
541cb0ef41Sopenharmony_ci        // i. Let A be ? Construct(C).
551cb0ef41Sopenharmony_ci        a = Construct(c);
561cb0ef41Sopenharmony_ci      }
571cb0ef41Sopenharmony_ci      case (JSAny): {
581cb0ef41Sopenharmony_ci        // i. Let A be ? ArrayCreate(0).
591cb0ef41Sopenharmony_ci        a = ArrayCreate(0);
601cb0ef41Sopenharmony_ci      }
611cb0ef41Sopenharmony_ci    }
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci    // c. Let iteratorRecord be ? GetIterator(items, sync, usingIterator).
641cb0ef41Sopenharmony_ci    const iteratorRecord = iterator::GetIterator(items, usingIterator);
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci    const fastIteratorResultMap = GetIteratorResultMap();
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci    // d. Let k be 0.
691cb0ef41Sopenharmony_ci    let k: Smi = 0;
701cb0ef41Sopenharmony_ci    // e. Repeat,
711cb0ef41Sopenharmony_ci    while (true) {
721cb0ef41Sopenharmony_ci      // i. If k ≥ 2^53-1, then
731cb0ef41Sopenharmony_ci      //   1. Let error be ThrowCompletion(a newly created TypeError object).
741cb0ef41Sopenharmony_ci      //   2. Return ? IteratorClose(iteratorRecord, error).
751cb0ef41Sopenharmony_ci      // The spec requires that we throw an exception if index reaches 2^53-1,
761cb0ef41Sopenharmony_ci      // but an empty loop would take >100 days to do this many iterations. To
771cb0ef41Sopenharmony_ci      // actually run for that long would require an iterator that never set
781cb0ef41Sopenharmony_ci      // done to true and a target array which somehow never ran out of
791cb0ef41Sopenharmony_ci      // memory, e.g. a proxy that discarded the values. Ignoring this case
801cb0ef41Sopenharmony_ci      // just means we would repeatedly call CreateDataProperty with index =
811cb0ef41Sopenharmony_ci      // 2^53
821cb0ef41Sopenharmony_ci      dcheck(k < kMaxSafeInteger);
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ci      // ii. Let Pk be ! ToString(k).
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci      // iii. Let next be ? IteratorStep(iteratorRecord).
871cb0ef41Sopenharmony_ci      let next: JSReceiver;
881cb0ef41Sopenharmony_ci      try {
891cb0ef41Sopenharmony_ci        next = iterator::IteratorStep(iteratorRecord, fastIteratorResultMap)
901cb0ef41Sopenharmony_ci            otherwise NextIsFalse;
911cb0ef41Sopenharmony_ci      }
921cb0ef41Sopenharmony_ci      // iv. If next is false, then
931cb0ef41Sopenharmony_ci      label NextIsFalse {
941cb0ef41Sopenharmony_ci        // 1. Perform ? Set(A, "length", k, true).
951cb0ef41Sopenharmony_ci        array::SetPropertyLength(a, k);
961cb0ef41Sopenharmony_ci        // 2. Return A.
971cb0ef41Sopenharmony_ci        return a;
981cb0ef41Sopenharmony_ci      }
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci      // v. Let nextValue be ? IteratorValue(next).
1011cb0ef41Sopenharmony_ci      const nextValue = iterator::IteratorValue(next, fastIteratorResultMap);
1021cb0ef41Sopenharmony_ci
1031cb0ef41Sopenharmony_ci      let mappedValue: JSAny;
1041cb0ef41Sopenharmony_ci      // vi. If mapping is true, then
1051cb0ef41Sopenharmony_ci      if (mapping) {
1061cb0ef41Sopenharmony_ci        // 1. Let mappedValue be Call(mapfn, thisArg, « nextValue, k »).
1071cb0ef41Sopenharmony_ci        // 2. If mappedValue is an abrupt completion,
1081cb0ef41Sopenharmony_ci        //    return ? IteratorClose(iteratorRecord, mappedValue).
1091cb0ef41Sopenharmony_ci        // 3. Set mappedValue to mappedValue.[[Value]].
1101cb0ef41Sopenharmony_ci        try {
1111cb0ef41Sopenharmony_ci          mappedValue =
1121cb0ef41Sopenharmony_ci              Call(context, UnsafeCast<Callable>(mapfn), thisArg, nextValue, k);
1131cb0ef41Sopenharmony_ci        } catch (e, message) {
1141cb0ef41Sopenharmony_ci          iterator::IteratorCloseOnException(iteratorRecord);
1151cb0ef41Sopenharmony_ci          ReThrowWithMessage(context, e, message);
1161cb0ef41Sopenharmony_ci        }
1171cb0ef41Sopenharmony_ci      } else {
1181cb0ef41Sopenharmony_ci        mappedValue = nextValue;
1191cb0ef41Sopenharmony_ci      }
1201cb0ef41Sopenharmony_ci      // viii. Let defineStatus be
1211cb0ef41Sopenharmony_ci      //       CreateDataPropertyOrThrow(A, Pk, mappedValue).
1221cb0ef41Sopenharmony_ci      // ix. If defineStatus is an abrupt completion,
1231cb0ef41Sopenharmony_ci      //     return ? IteratorClose(iteratorRecord, defineStatus).
1241cb0ef41Sopenharmony_ci      try {
1251cb0ef41Sopenharmony_ci        FastCreateDataProperty(a, k, mappedValue);
1261cb0ef41Sopenharmony_ci      } catch (e, message) deferred {
1271cb0ef41Sopenharmony_ci        iterator::IteratorCloseOnException(iteratorRecord);
1281cb0ef41Sopenharmony_ci        ReThrowWithMessage(context, e, message);
1291cb0ef41Sopenharmony_ci      }
1301cb0ef41Sopenharmony_ci      // x. Set k to k + 1.
1311cb0ef41Sopenharmony_ci      k += 1;
1321cb0ef41Sopenharmony_ci    }
1331cb0ef41Sopenharmony_ci    unreachable;
1341cb0ef41Sopenharmony_ci  } label IteratorIsUndefined {
1351cb0ef41Sopenharmony_ci    // 6. NOTE: items is not an Iterable so assume it is an array-like object.
1361cb0ef41Sopenharmony_ci    // 7. Let arrayLike be ! ToObject(items).
1371cb0ef41Sopenharmony_ci    const arrayLike = ToObject_Inline(context, items);
1381cb0ef41Sopenharmony_ci    // 8. Let len be ? LengthOfArrayLike(arrayLike).
1391cb0ef41Sopenharmony_ci    const len = GetLengthProperty(arrayLike);
1401cb0ef41Sopenharmony_ci
1411cb0ef41Sopenharmony_ci    let a: JSReceiver;
1421cb0ef41Sopenharmony_ci    // 9. If IsConstructor(C) is true, then
1431cb0ef41Sopenharmony_ci    typeswitch (c) {
1441cb0ef41Sopenharmony_ci      case (c: Constructor): {
1451cb0ef41Sopenharmony_ci        // a. Let A be ? Construct(C, « len »).
1461cb0ef41Sopenharmony_ci        a = Construct(c, len);
1471cb0ef41Sopenharmony_ci      }
1481cb0ef41Sopenharmony_ci      case (JSAny): {
1491cb0ef41Sopenharmony_ci        // a. Let A be ? ArrayCreate(len).
1501cb0ef41Sopenharmony_ci        a = ArrayCreate(len);
1511cb0ef41Sopenharmony_ci      }
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci    // 11. Let k be 0.
1551cb0ef41Sopenharmony_ci    let k: Smi = 0;
1561cb0ef41Sopenharmony_ci    // 12. Repeat, while k < len
1571cb0ef41Sopenharmony_ci    while (k < len) {
1581cb0ef41Sopenharmony_ci      // a. Let Pk be ! ToString(k).
1591cb0ef41Sopenharmony_ci      // b. Let kValue be ? Get(arrayLike, Pk).
1601cb0ef41Sopenharmony_ci      const kValue = GetProperty(arrayLike, k);
1611cb0ef41Sopenharmony_ci      let mappedValue: JSAny;
1621cb0ef41Sopenharmony_ci      // c. If mapping is true, then
1631cb0ef41Sopenharmony_ci      if (mapping) {
1641cb0ef41Sopenharmony_ci        // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »).
1651cb0ef41Sopenharmony_ci        mappedValue =
1661cb0ef41Sopenharmony_ci            Call(context, UnsafeCast<Callable>(mapfn), thisArg, kValue, k);
1671cb0ef41Sopenharmony_ci      } else {
1681cb0ef41Sopenharmony_ci        // d. Else, let mappedValue be kValue.
1691cb0ef41Sopenharmony_ci        mappedValue = kValue;
1701cb0ef41Sopenharmony_ci      }
1711cb0ef41Sopenharmony_ci      // e. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
1721cb0ef41Sopenharmony_ci      FastCreateDataProperty(a, k, mappedValue);
1731cb0ef41Sopenharmony_ci      // f. Set k to k + 1.
1741cb0ef41Sopenharmony_ci      k += 1;
1751cb0ef41Sopenharmony_ci    }
1761cb0ef41Sopenharmony_ci
1771cb0ef41Sopenharmony_ci    // 13. Perform ? Set(A, "length", len, true).
1781cb0ef41Sopenharmony_ci    array::SetPropertyLength(a, len);
1791cb0ef41Sopenharmony_ci    // 14. Return A.
1801cb0ef41Sopenharmony_ci    return a;
1811cb0ef41Sopenharmony_ci  } label IteratorNotCallable(_value: JSAny) deferred {
1821cb0ef41Sopenharmony_ci    ThrowTypeError(MessageTemplate::kIteratorSymbolNonCallable);
1831cb0ef41Sopenharmony_ci  }
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci}
186