summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/array-foreach.tq
blob: 5b6e3926016c2c2b6f3455af2f1f0eeca2c8e514 (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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// 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_foreach {
  transitioning javascript builtin
  ArrayForEachLoopEagerDeoptContinuation(
      js-implicit context: Context, receiver: JSAny)(
      callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny): JSAny {
    // All continuation points in the optimized forEach implemntation are
    // after the ToObject(O) call that ensures we are dealing with a
    // JSReceiver.
    const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
    const callbackfn = Cast<Callable>(callback) otherwise unreachable;
    const numberK = Cast<Number>(initialK) otherwise unreachable;
    const numberLength = Cast<Number>(length) otherwise unreachable;

    return ArrayForEachLoopContinuation(
        jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
        numberLength, Undefined);
  }

  transitioning javascript builtin
  ArrayForEachLoopLazyDeoptContinuation(
      js-implicit context: Context, receiver: JSAny)(
      callback: JSAny, thisArg: JSAny, initialK: JSAny, length: JSAny,
      _result: JSAny): JSAny {
    // All continuation points in the optimized forEach implemntation are
    // after the ToObject(O) call that ensures we are dealing with a
    // JSReceiver.
    const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
    const callbackfn = Cast<Callable>(callback) otherwise unreachable;
    const numberK = Cast<Number>(initialK) otherwise unreachable;
    const numberLength = Cast<Number>(length) otherwise unreachable;

    return ArrayForEachLoopContinuation(
        jsreceiver, callbackfn, thisArg, Undefined, jsreceiver, numberK,
        numberLength, Undefined);
  }

  transitioning builtin ArrayForEachLoopContinuation(implicit context: Context)(
      _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
      _array: JSAny, o: JSReceiver, initialK: Number, len: Number,
      _to: JSAny): JSAny {
    // variables {array} and {to} are ignored.

    // 5. Let k be 0.
    // 6. Repeat, while k < len
    for (let k: Number = initialK; k < len; k = k + 1) {
      // 6a. Let Pk be ! ToString(k).
      // k is guaranteed to be a positive integer, hence ToString is
      // side-effect free and HasProperty/GetProperty do the conversion inline.

      // 6b. Let kPresent be ? HasProperty(O, Pk).
      const kPresent: Boolean = HasProperty_Inline(o, k);

      // 6c. If kPresent is true, then
      if (kPresent == True) {
        // 6c. i. Let kValue be ? Get(O, Pk).
        const kValue: JSAny = GetProperty(o, k);

        // 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
        Call(context, callbackfn, thisArg, kValue, k, o);
      }

      // 6d. Increase k by 1. (done by the loop).
    }
    return Undefined;
  }

  transitioning macro FastArrayForEach(implicit context: Context)(
      o: JSReceiver, len: Number, callbackfn: Callable, thisArg: JSAny): JSAny
      labels Bailout(Smi) {
    let k: Smi = 0;
    const smiLen = Cast<Smi>(len) otherwise goto Bailout(k);
    const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k);
    let fastOW = NewFastJSArrayWitness(fastO);

    // Build a fast loop over the smi array.
    for (; k < smiLen; k++) {
      fastOW.Recheck() otherwise goto Bailout(k);

      // Ensure that we haven't walked beyond a possibly updated length.
      if (k >= fastOW.Get().length) goto Bailout(k);
      const value: JSAny = fastOW.LoadElementNoHole(k)
          otherwise continue;
      Call(context, callbackfn, thisArg, value, k, fastOW.Get());
    }
    return Undefined;
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.foreach
  transitioning javascript builtin
  ArrayForEach(js-implicit context: Context, receiver: JSAny)(...arguments):
      JSAny {
    try {
      RequireObjectCoercible(receiver, 'Array.prototype.forEach');

      // 1. Let O be ? ToObject(this value).
      const o: JSReceiver = ToObject_Inline(context, receiver);

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

      // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
      if (arguments.length == 0) {
        goto TypeError;
      }
      const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;

      // 4. If thisArg is present, let T be thisArg; else let T be undefined.
      const thisArg: JSAny = arguments.length > 1 ? arguments[1] : Undefined;

      // Special cases.
      let k: Number = 0;
      try {
        return FastArrayForEach(o, len, callbackfn, thisArg)
            otherwise Bailout;
      }
      label Bailout(kValue: Smi) deferred {
        k = kValue;
      }

      return ArrayForEachLoopContinuation(
          o, callbackfn, thisArg, Undefined, o, k, len, Undefined);
    }
    label TypeError deferred {
      ThrowTypeError(kCalledNonCallable, arguments[0]);
    }
  }
}