summaryrefslogtreecommitdiff
path: root/deps/v8/src/builtins/array-findindex.tq
blob: 00d8378dfa69798d61ebe0e5b0f0d675d7fa7b0c (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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// 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_findindex {
  transitioning javascript builtin
  ArrayFindIndexLoopEagerDeoptContinuation(implicit context: Context)(
      receiver: Object, callback: Object, thisArg: Object, initialK: Object,
      length: Object): Object {
    // All continuation points in the optimized findIndex implementation are
    // after the ToObject(O) call that ensures we are dealing with a
    // JSReceiver.
    //
    // Also, this great mass of casts is necessary because the signature
    // of Torque javascript builtins requires Object type for all parameters
    // other than {context}.
    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 ArrayFindIndexLoopContinuation(
        jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength);
  }

  transitioning javascript builtin
  ArrayFindIndexLoopLazyDeoptContinuation(implicit context: Context)(
      receiver: Object, callback: Object, thisArg: Object, initialK: Object,
      length: Object, result: Object): Object {
    // This deopt continuation point is never actually called, it just
    // exists to make stack traces correct from a ThrowTypeError if the
    // callback was found to be non-callable.
    unreachable;
  }

  // Continuation that is called after a lazy deoptimization from TF that
  // happens right after the callback and it's returned value must be handled
  // before iteration continues.
  transitioning javascript builtin
  ArrayFindIndexLoopAfterCallbackLazyDeoptContinuation(implicit context:
                                                           Context)(
      receiver: Object, callback: Object, thisArg: Object, initialK: Object,
      length: Object, foundValue: Object, isFound: Object): Object {
    // All continuation points in the optimized findIndex implementation 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;
    let numberK = Cast<Number>(initialK) otherwise unreachable;
    const numberLength = Cast<Number>(length) otherwise unreachable;

    // This custom lazy deopt point is right after the callback. find() needs
    // to pick up at the next step, which is returning the element if the
    // callback value is truthy.  Otherwise, continue the search by calling the
    // continuation.

    if (ToBoolean(isFound)) {
      return foundValue;
    }

    return ArrayFindIndexLoopContinuation(
        jsreceiver, callbackfn, thisArg, jsreceiver, numberK, numberLength);
  }

  transitioning builtin ArrayFindIndexLoopContinuation(implicit context:
                                                           Context)(
      receiver: JSReceiver, callbackfn: Callable, thisArg: Object,
      o: JSReceiver, initialK: Number, length: Number): Number {
    // 5. Let k be 0.
    // 6. Repeat, while k < len
    for (let k: Number = initialK; k < length; k++) {
      // 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. i. Let kValue be ? Get(O, Pk).
      const value: Object = GetProperty(o, k);

      // 6c. Let testResult be ToBoolean(? Call(predicate, T, <<kValue, k,
      // O>>)).
      const testResult: Object =
          Call(context, callbackfn, thisArg, value, k, o);

      // 6d. If testResult is true, return k.
      if (ToBoolean(testResult)) {
        return k;
      }

      // 6e. Increase k by 1. (done by the loop).
    }
    return Convert<Smi>(-1);
  }

  transitioning macro FastArrayFindIndex(implicit context: Context)(
      o: JSReceiver, len: Number, callbackfn: Callable, thisArg: Object): Number
      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: Object = fastOW.LoadElementOrUndefined(k);
      const testResult: Object =
          Call(context, callbackfn, thisArg, value, k, fastOW.Get());
      if (ToBoolean(testResult)) {
        return k;
      }
    }
    return -1;
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.findIndex
  transitioning javascript builtin
  ArrayPrototypeFindIndex(implicit context:
                              Context)(receiver: Object, ...arguments): Object {
    try {
      if (IsNullOrUndefined(receiver)) {
        goto NullOrUndefinedError;
      }

      // 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 NotCallableError;
      }
      const callbackfn =
          Cast<Callable>(arguments[0]) otherwise NotCallableError;

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

      // Special cases.
      try {
        return FastArrayFindIndex(o, len, callbackfn, thisArg)
            otherwise Bailout;
      }
      label Bailout(k: Smi) deferred {
        return ArrayFindIndexLoopContinuation(
            o, callbackfn, thisArg, o, k, len);
      }
    }
    label NotCallableError deferred {
      ThrowTypeError(kCalledNonCallable, arguments[0]);
    }
    label NullOrUndefinedError deferred {
      ThrowTypeError(kCalledOnNullOrUndefined, 'Array.prototype.findIndex');
    }
  }
}