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