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
7ArrayReduceRightPreLoopEagerDeoptContinuation(
8    js-implicit context: NativeContext, receiver: JSAny)(
9    callback: JSAny, length: JSAny): JSAny {
10  // All continuation points in the optimized every implementation are
11  // after the ToObject(O) call that ensures we are dealing with a
12  // JSReceiver.
13  //
14  // Also, this great mass of casts is necessary because the signature
15  // of Torque javascript builtins requires JSAny type for all parameters
16  // other than {context}.
17  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
18  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
19  const numberLength = Cast<Number>(length) otherwise unreachable;
20  const initialK = numberLength - 1;
21
22  // Simulate starting the loop at {length - 1}, but ensuring that the
23  // accumulator is the hole. The continuation stub will search for the
24  // last non-hole element, rightly throwing an exception if not found.
25  return ArrayReduceRightLoopContinuation(
26      jsreceiver, callbackfn, TheHole, jsreceiver, initialK, numberLength);
27}
28
29transitioning javascript builtin
30ArrayReduceRightLoopEagerDeoptContinuation(
31    js-implicit context: NativeContext, receiver: JSAny)(
32    callback: JSAny, initialK: JSAny, length: JSAny,
33    accumulator: JSAny): JSAny {
34  // All continuation points in the optimized every implementation are
35  // after the ToObject(O) call that ensures we are dealing with a
36  // JSReceiver.
37  //
38  // Also, this great mass of casts is necessary because the signature
39  // of Torque javascript builtins requires JSAny type for all parameters
40  // other than {context}.
41  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
42  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
43  const numberK = Cast<Number>(initialK) otherwise unreachable;
44  const numberLength = Cast<Number>(length) otherwise unreachable;
45
46  return ArrayReduceRightLoopContinuation(
47      jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength);
48}
49
50transitioning javascript builtin
51ArrayReduceRightLoopLazyDeoptContinuation(
52    js-implicit context: NativeContext, receiver: JSAny)(
53    callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny {
54  // All continuation points in the optimized every implementation are
55  // after the ToObject(O) call that ensures we are dealing with a
56  // JSReceiver.
57  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
58  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
59  const numberK = Cast<Number>(initialK) otherwise unreachable;
60  const numberLength = Cast<Number>(length) otherwise unreachable;
61
62  // The accumulator is the result from the callback call which just occured.
63  const r = ArrayReduceRightLoopContinuation(
64      jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
65  return r;
66}
67
68transitioning builtin ArrayReduceRightLoopContinuation(
69    implicit context: Context)(
70    _receiver: JSReceiver, callbackfn: Callable,
71    initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number,
72    _length: Number): JSAny {
73  let accumulator = initialAccumulator;
74
75  // 8b and 9. Repeat, while k >= 0
76  for (let k: Number = initialK; k >= 0; k--) {
77    // 8b i and 9a. Let Pk be ! ToString(k).
78    // k is guaranteed to be a positive integer, hence ToString is
79    // side-effect free and HasProperty/GetProperty do the conversion inline.
80
81    // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk).
82    const present: Boolean = HasProperty_Inline(o, k);
83
84    // 8b iii and 9c. If kPresent is true, then
85    if (present == True) {
86      // 8b iii and 9c i. Let kValue be ? Get(O, Pk).
87      const value: JSAny = GetProperty(o, k);
88
89      typeswitch (accumulator) {
90        case (TheHole): {
91          // 8b iii 1.
92          accumulator = value;
93        }
94        case (accumulatorNotHole: JSAny): {
95          // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
96          //         <accumulator, kValue, k, O>).
97          accumulator = Call(
98              context, callbackfn, Undefined, accumulatorNotHole, value, k, o);
99        }
100      }
101    }
102
103    // 8b iv and 9d. Decrease k by 1. (done by the loop).
104  }
105
106  // 8c. if kPresent is false, throw a TypeError exception.
107  // If the accumulator is discovered with the sentinel hole value,
108  // this means kPresent is false.
109  typeswitch (accumulator) {
110    case (TheHole): {
111      ThrowTypeError(
112          MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight');
113    }
114    case (accumulator: JSAny): {
115      return accumulator;
116    }
117  }
118}
119
120transitioning macro FastArrayReduceRight(implicit context: Context)(
121    o: JSReceiver, len: Number, callbackfn: Callable,
122    initialAccumulator: JSAny|TheHole): JSAny
123    labels Bailout(Number, JSAny | TheHole) {
124  let accumulator = initialAccumulator;
125  const smiLen = Cast<Smi>(len) otherwise goto Bailout(len - 1, accumulator);
126  const fastO = Cast<FastJSArrayForRead>(o)
127      otherwise goto Bailout(len - 1, accumulator);
128  let fastOW = NewFastJSArrayForReadWitness(fastO);
129
130  // Build a fast loop over the array.
131  for (let k: Smi = smiLen - 1; k >= 0; k--) {
132    fastOW.Recheck() otherwise goto Bailout(k, accumulator);
133
134    // Ensure that we haven't walked beyond a possibly updated length.
135    if (k >= fastOW.Get().length) goto Bailout(k, accumulator);
136
137    const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
138    typeswitch (accumulator) {
139      case (TheHole): {
140        accumulator = value;
141      }
142      case (accumulatorNotHole: JSAny): {
143        accumulator = Call(
144            context, callbackfn, Undefined, accumulatorNotHole, value, k,
145            fastOW.Get());
146      }
147    }
148  }
149  typeswitch (accumulator) {
150    case (TheHole): {
151      ThrowTypeError(
152          MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight');
153    }
154    case (accumulator: JSAny): {
155      return accumulator;
156    }
157  }
158}
159
160// https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight
161transitioning javascript builtin
162ArrayReduceRight(
163    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
164  try {
165    RequireObjectCoercible(receiver, 'Array.prototype.reduceRight');
166
167    // 1. Let O be ? ToObject(this value).
168    const o: JSReceiver = ToObject_Inline(context, receiver);
169
170    // 2. Let len be ? ToLength(? Get(O, "length")).
171    const len: Number = GetLengthProperty(o);
172
173    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
174    if (arguments.length == 0) {
175      goto NoCallableError;
176    }
177    const callbackfn = Cast<Callable>(arguments[0]) otherwise NoCallableError;
178
179    // 4. If len is 0 and initialValue is not present, throw a TypeError
180    // exception. (This case is handled at the end of
181    // ArrayReduceRightLoopContinuation).
182
183    const initialValue: JSAny|TheHole =
184        arguments.length > 1 ? arguments[1] : TheHole;
185
186    try {
187      return FastArrayReduceRight(o, len, callbackfn, initialValue)
188          otherwise Bailout;
189    } label Bailout(value: Number, accumulator: JSAny|TheHole) {
190      return ArrayReduceRightLoopContinuation(
191          o, callbackfn, accumulator, o, value, len);
192    }
193  } label NoCallableError deferred {
194    ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]);
195  }
196}
197}
198