1// Copyright 2018 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 {
6extern builtin ArrayUnshift(Context, JSFunction, JSAny, int32): JSAny;
7
8transitioning macro GenericArrayUnshift(
9    context: Context, receiver: JSAny, arguments: Arguments): Number {
10  // 1. Let O be ? ToObject(this value).
11  const object: JSReceiver = ToObject_Inline(context, receiver);
12
13  // 2. Let len be ? ToLength(? Get(O, "length")).
14  const length: Number = GetLengthProperty(object);
15
16  // 3. Let argCount be the number of actual arguments.
17  const argCount: Smi = Convert<Smi>(arguments.length);
18
19  // 4. If argCount > 0, then.
20  if (argCount > 0) {
21    // a. If len + argCount > 2**53 - 1, throw a TypeError exception.
22    if (length + argCount > kMaxSafeInteger) {
23      ThrowTypeError(MessageTemplate::kInvalidArrayLength);
24    }
25
26    // b. Let k be len.
27    let k: Number = length;
28
29    // c. Repeat, while k > 0.
30    while (k > 0) {
31      // i. Let from be ! ToString(k - 1).
32      const from: Number = k - 1;
33
34      // ii. Let to be ! ToString(k + argCount - 1).
35      const to: Number = k + argCount - 1;
36
37      // iii. Let fromPresent be ? HasProperty(O, from).
38      const fromPresent: Boolean = HasProperty(object, from);
39
40      // iv. If fromPresent is true, then
41      if (fromPresent == True) {
42        // 1. Let fromValue be ? Get(O, from).
43        const fromValue: JSAny = GetProperty(object, from);
44
45        // 2. Perform ? Set(O, to, fromValue, true).
46        SetProperty(object, to, fromValue);
47      } else {
48        // 1. Perform ? DeletePropertyOrThrow(O, to).
49        DeleteProperty(object, to, LanguageMode::kStrict);
50      }
51
52      // vi. Decrease k by 1.
53      --k;
54    }
55
56    // d. Let j be 0.
57    let j: Smi = 0;
58
59    // e. Let items be a List whose elements are, in left to right order,
60    //    the arguments that were passed to this function invocation.
61    // f. Repeat, while items is not empty
62    while (j < argCount) {
63      // ii .Perform ? Set(O, ! ToString(j), E, true).
64      SetProperty(object, j, arguments[Convert<intptr>(j)]);
65
66      // iii. Increase j by 1.
67      ++j;
68    }
69  }
70
71  // 5. Perform ? Set(O, "length", len + argCount, true).
72  const newLength: Number = length + argCount;
73  SetProperty(object, kLengthString, newLength);
74
75  // 6. Return length + argCount.
76  return newLength;
77}
78
79// https://tc39.github.io/ecma262/#sec-array.prototype.unshift
80transitioning javascript builtin ArrayPrototypeUnshift(
81    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
82  try {
83    const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
84    array::EnsureWriteableFastElements(array);
85
86    const map: Map = array.map;
87    if (!IsExtensibleMap(map)) goto Slow;
88    EnsureArrayLengthWritable(map) otherwise Slow;
89
90    tail ArrayUnshift(
91        context, LoadTargetFromFrame(), Undefined,
92        Convert<int32>(arguments.actual_count));
93  } label Slow {
94    return GenericArrayUnshift(context, receiver, arguments);
95  }
96}
97}
98