summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/array-unshift.tq
blob: e685d520cd963a968078f8d593e98a8ffb6b972f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// Copyright 2018 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

namespace array_unshift {
  extern builtin ArrayUnshift(Context, JSFunction, Object, int32);

  macro TryFastArrayUnshift(
      context: Context, receiver: Object, arguments: Arguments): never
      labels Slow {
    const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
    array::EnsureWriteableFastElements(array);

    const map: Map = array.map;
    if (!IsExtensibleMap(map)) goto Slow;
    EnsureArrayLengthWritable(map) otherwise Slow;

    tail ArrayUnshift(
        context, LoadTargetFromFrame(), Undefined,
        Convert<int32>(arguments.length));
  }

  transitioning macro GenericArrayUnshift(
      context: Context, receiver: Object, arguments: Arguments): Number {
    // 1. Let O be ? ToObject(this value).
    const object: JSReceiver = ToObject_Inline(context, receiver);

    // 2. Let len be ? ToLength(? Get(O, "length")).
    const length: Number = GetLengthProperty(object);

    // 3. Let argCount be the number of actual arguments.
    const argCount: Smi = Convert<Smi>(arguments.length);

    // 4. If argCount > 0, then.
    if (argCount > 0) {
      // a. If len + argCount > 2**53 - 1, throw a TypeError exception.
      if (length + argCount > kMaxSafeInteger) {
        ThrowTypeError(kInvalidArrayLength);
      }

      // b. Let k be len.
      let k: Number = length;

      // c. Repeat, while k > 0.
      while (k > 0) {
        // i. Let from be ! ToString(k - 1).
        const from: Number = k - 1;

        // ii. Let to be ! ToString(k + argCount - 1).
        const to: Number = k + argCount - 1;

        // iii. Let fromPresent be ? HasProperty(O, from).
        const fromPresent: Boolean = HasProperty(object, from);

        // iv. If fromPresent is true, then
        if (fromPresent == True) {
          // 1. Let fromValue be ? Get(O, from).
          const fromValue: Object = GetProperty(object, from);

          // 2. Perform ? Set(O, to, fromValue, true).
          SetProperty(object, to, fromValue);
        } else {
          // 1. Perform ? DeletePropertyOrThrow(O, to).
          DeleteProperty(object, to, kStrict);
        }

        // vi. Decrease k by 1.
        --k;
      }

      // d. Let j be 0.
      let j: Smi = 0;

      // e. Let items be a List whose elements are, in left to right order,
      //    the arguments that were passed to this function invocation.
      // f. Repeat, while items is not empty
      while (j < argCount) {
        // ii .Perform ? Set(O, ! ToString(j), E, true).
        SetProperty(object, j, arguments[Convert<intptr>(j)]);

        // iii. Increase j by 1.
        ++j;
      }
    }

    // 5. Perform ? Set(O, "length", len + argCount, true).
    const newLength: Number = length + argCount;
    SetProperty(object, kLengthString, newLength);

    // 6. Return length + argCount.
    return newLength;
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.unshift
  transitioning javascript builtin ArrayPrototypeUnshift(
      js-implicit context: Context, receiver: Object)(...arguments): Object {
    try {
      TryFastArrayUnshift(context, receiver, arguments) otherwise Baseline;
    }
    label Baseline {
      return GenericArrayUnshift(context, receiver, arguments);
    }
  }
}