• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
6transitioning javascript builtin
7ArrayFilterLoopEagerDeoptContinuation(
8    js-implicit context: NativeContext, receiver: JSAny)(
9    callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
10    length: JSAny, initialTo: JSAny): JSAny {
11  // All continuation points in the optimized filter implementation are
12  // after the ToObject(O) call that ensures we are dealing with a
13  // JSReceiver.
14  //
15  // Also, this great mass of casts is necessary because the signature
16  // of Torque javascript builtins requires JSAny type for all parameters
17  // other than {context}.
18  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
19  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
20  const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
21  const numberK = Cast<Number>(initialK) otherwise unreachable;
22  const numberTo = Cast<Number>(initialTo) otherwise unreachable;
23  const numberLength = Cast<Number>(length) otherwise unreachable;
24
25  return ArrayFilterLoopContinuation(
26      jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
27      numberLength, numberTo);
28}
29
30transitioning javascript builtin
31ArrayFilterLoopLazyDeoptContinuation(
32    js-implicit context: NativeContext, receiver: JSAny)(
33    callback: JSAny, thisArg: JSAny, array: JSAny, initialK: JSAny,
34    length: JSAny, valueK: JSAny, initialTo: JSAny, result: JSAny): JSAny {
35  // All continuation points in the optimized filter implementation are
36  // after the ToObject(O) call that ensures we are dealing with a
37  // JSReceiver.
38  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
39  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
40  const outputArray = Cast<JSReceiver>(array) otherwise unreachable;
41  let numberK = Cast<Number>(initialK) otherwise unreachable;
42  let numberTo = Cast<Number>(initialTo) otherwise unreachable;
43  const numberLength = Cast<Number>(length) otherwise unreachable;
44
45  // This custom lazy deopt point is right after the callback. filter() needs
46  // to pick up at the next step, which is setting the callback
47  // result in the output array. After incrementing k and to, we can glide
48  // into the loop continuation builtin.
49  if (ToBoolean(result)) {
50    FastCreateDataProperty(outputArray, numberTo, valueK);
51    numberTo = numberTo + 1;
52  }
53
54  numberK = numberK + 1;
55
56  return ArrayFilterLoopContinuation(
57      jsreceiver, callbackfn, thisArg, outputArray, jsreceiver, numberK,
58      numberLength, numberTo);
59}
60
61transitioning builtin ArrayFilterLoopContinuation(implicit context: Context)(
62    _receiver: JSReceiver, callbackfn: Callable, thisArg: JSAny,
63    array: JSReceiver, o: JSReceiver, initialK: Number, length: Number,
64    initialTo: Number): JSAny {
65  let to: Number = initialTo;
66  // 5. Let k be 0.
67  // 6. Repeat, while k < len
68  for (let k: Number = initialK; k < length; k++) {
69    // 6a. Let Pk be ! ToString(k).
70    // k is guaranteed to be a positive integer, hence ToString is
71    // side-effect free and HasProperty/GetProperty do the conversion inline.
72
73    // 6b. Let kPresent be ? HasProperty(O, Pk).
74    const kPresent: Boolean = HasProperty_Inline(o, k);
75
76    // 6c. If kPresent is true, then
77    if (kPresent == True) {
78      // 6c. i. Let kValue be ? Get(O, Pk).
79      const kValue: JSAny = GetProperty(o, k);
80
81      // 6c. ii. Perform ? Call(callbackfn, T, <kValue, k, O>).
82      const result: JSAny = Call(context, callbackfn, thisArg, kValue, k, o);
83
84      // iii. If selected is true, then...
85      if (ToBoolean(result)) {
86        // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue).
87        FastCreateDataProperty(array, to, kValue);
88        // 2. Increase to by 1.
89        to = to + 1;
90      }
91    }
92
93    // 6d. Increase k by 1. (done by the loop).
94  }
95  return array;
96}
97
98transitioning macro FastArrayFilter(implicit context: Context)(
99    fastO: FastJSArray, len: Smi, callbackfn: Callable, thisArg: JSAny,
100    output: FastJSArray): void labels
101Bailout(Number, Number) {
102  let k: Smi = 0;
103  let to: Smi = 0;
104  let fastOW = NewFastJSArrayWitness(fastO);
105  let fastOutputW = NewFastJSArrayWitness(output);
106
107  fastOutputW.EnsureArrayPushable() otherwise goto Bailout(k, to);
108
109  // Build a fast loop over the array.
110  for (; k < len; k++) {
111    fastOW.Recheck() otherwise goto Bailout(k, to);
112
113    // Ensure that we haven't walked beyond a possibly updated length.
114    if (k >= fastOW.Get().length) goto Bailout(k, to);
115    const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
116    const result: JSAny =
117        Call(context, callbackfn, thisArg, value, k, fastOW.Get());
118    if (ToBoolean(result)) {
119      try {
120        // Since the call to {callbackfn} is observable, we can't
121        // use the Bailout label until we've successfully stored.
122        // Hence the {SlowStore} label.
123        fastOutputW.Recheck() otherwise SlowStore;
124        if (fastOutputW.Get().length != to) goto SlowStore;
125        fastOutputW.Push(value) otherwise SlowStore;
126      } label SlowStore {
127        FastCreateDataProperty(fastOutputW.stable, to, value);
128      }
129      to = to + 1;
130    }
131  }
132}
133
134// This method creates a 0-length array with the ElementsKind of the
135// receiver if possible, otherwise, bails out. It makes sense for the
136// caller to know that the slow case needs to be invoked.
137macro FastFilterSpeciesCreate(implicit context: Context)(receiver: JSReceiver):
138    JSReceiver labels Slow {
139  const len: Smi = 0;
140  if (IsArraySpeciesProtectorCellInvalid()) goto Slow;
141  const o = Cast<FastJSArray>(receiver) otherwise Slow;
142  const newMap: Map =
143      LoadJSArrayElementsMap(o.map.elements_kind, LoadNativeContext(context));
144  return AllocateJSArray(ElementsKind::PACKED_SMI_ELEMENTS, newMap, len, len);
145}
146
147// https://tc39.github.io/ecma262/#sec-array.prototype.filter
148transitioning javascript builtin
149ArrayFilter(
150    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
151  try {
152    RequireObjectCoercible(receiver, 'Array.prototype.filter');
153
154    // 1. Let O be ? ToObject(this value).
155    const o: JSReceiver = ToObject_Inline(context, receiver);
156
157    // 2. Let len be ? ToLength(? Get(O, "length")).
158    const len: Number = GetLengthProperty(o);
159
160    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
161    if (arguments.length == 0) {
162      goto TypeError;
163    }
164    const callbackfn = Cast<Callable>(arguments[0]) otherwise TypeError;
165
166    // 4. If thisArg is present, let T be thisArg; else let T be undefined.
167    const thisArg: JSAny = arguments[1];
168    let output: JSReceiver;
169
170    // Special cases.
171    let k: Number = 0;
172    let to: Number = 0;
173    try {
174      output = FastFilterSpeciesCreate(o) otherwise SlowSpeciesCreate;
175
176      try {
177        const smiLen: Smi = Cast<Smi>(len) otherwise goto Bailout(k, to);
178        const fastOutput =
179            Cast<FastJSArray>(output) otherwise goto Bailout(k, to);
180        const fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k, to);
181
182        FastArrayFilter(fastO, smiLen, callbackfn, thisArg, fastOutput)
183            otherwise Bailout;
184        return output;
185      } label Bailout(kValue: Number, toValue: Number) deferred {
186        k = kValue;
187        to = toValue;
188      }
189    } label SlowSpeciesCreate {
190      output = ArraySpeciesCreate(context, receiver, 0);
191    }
192
193    return ArrayFilterLoopContinuation(
194        o, callbackfn, thisArg, output, o, k, len, to);
195  } label TypeError deferred {
196    ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]);
197  }
198}
199}
200