array-reduce-right.tq 7.34 KB
Newer Older
1 2 3 4 5
// 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 {
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
transitioning javascript builtin
ArrayReduceRightPreLoopEagerDeoptContinuation(
    js-implicit context: NativeContext, receiver: JSAny)(
    callback: JSAny, length: JSAny): JSAny {
  // All continuation points in the optimized every 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 JSAny type for all parameters
  // other than {context}.
  const jsreceiver = Cast<JSReceiver>(receiver) otherwise unreachable;
  const callbackfn = Cast<Callable>(callback) otherwise unreachable;
  const numberLength = Cast<Number>(length) otherwise unreachable;
  const initialK = numberLength - 1;

  // Simulate starting the loop at {length - 1}, but ensuring that the
  // accumulator is the hole. The continuation stub will search for the
  // last non-hole element, rightly throwing an exception if not found.
  return ArrayReduceRightLoopContinuation(
      jsreceiver, callbackfn, TheHole, jsreceiver, initialK, numberLength);
}
28

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
transitioning javascript builtin
ArrayReduceRightLoopEagerDeoptContinuation(
    js-implicit context: NativeContext, receiver: JSAny)(
    callback: JSAny, initialK: JSAny, length: JSAny,
    accumulator: JSAny): JSAny {
  // All continuation points in the optimized every 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 JSAny 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 ArrayReduceRightLoopContinuation(
      jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength);
}
49

50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
transitioning javascript builtin
ArrayReduceRightLoopLazyDeoptContinuation(
    js-implicit context: NativeContext, receiver: JSAny)(
    callback: JSAny, initialK: JSAny, length: JSAny, result: JSAny): JSAny {
  // All continuation points in the optimized every 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;
  const numberK = Cast<Number>(initialK) otherwise unreachable;
  const numberLength = Cast<Number>(length) otherwise unreachable;

  // The accumulator is the result from the callback call which just occured.
  const r = ArrayReduceRightLoopContinuation(
      jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
  return r;
}
67

68 69 70 71 72 73
transitioning builtin ArrayReduceRightLoopContinuation(
    implicit context: Context)(
    _receiver: JSReceiver, callbackfn: Callable,
    initialAccumulator: JSAny|TheHole, o: JSReceiver, initialK: Number,
    _length: Number): JSAny {
  let accumulator = initialAccumulator;
74

75 76 77 78 79
  // 8b and 9. Repeat, while k >= 0
  for (let k: Number = initialK; k >= 0; k--) {
    // 8b i and 9a. 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.
80

81 82
    // 8b ii and 9b. Set kPresent to ? HasProperty(O, Pk).
    const present: Boolean = HasProperty_Inline(o, k);
83

84 85 86 87
    // 8b iii and 9c. If kPresent is true, then
    if (present == True) {
      // 8b iii and 9c i. Let kValue be ? Get(O, Pk).
      const value: JSAny = GetProperty(o, k);
88

89 90
      typeswitch (accumulator) {
        case (TheHole): {
91
          // 8b iii 1.
92 93 94
          accumulator = value;
        }
        case (accumulatorNotHole: JSAny): {
95 96
          // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
          //         <accumulator, kValue, k, O>).
97
          accumulator = Call(
98
              context, callbackfn, Undefined, accumulatorNotHole, value, k, o);
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

    // 8b iv and 9d. Decrease k by 1. (done by the loop).
  }

  // 8c. if kPresent is false, throw a TypeError exception.
  // If the accumulator is discovered with the sentinel hole value,
  // this means kPresent is false.
  typeswitch (accumulator) {
    case (TheHole): {
      ThrowTypeError(
          MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight');
    }
    case (accumulator: JSAny): {
      return accumulator;
    }
  }
}

transitioning macro FastArrayReduceRight(implicit context: Context)(
    o: JSReceiver, len: Number, callbackfn: Callable,
    initialAccumulator: JSAny|TheHole): JSAny
    labels Bailout(Number, JSAny | TheHole) {
  let accumulator = initialAccumulator;
  const smiLen = Cast<Smi>(len) otherwise goto Bailout(len - 1, accumulator);
  const fastO = Cast<FastJSArrayForRead>(o)
      otherwise goto Bailout(len - 1, accumulator);
  let fastOW = NewFastJSArrayForReadWitness(fastO);

  // Build a fast loop over the array.
  for (let k: Smi = smiLen - 1; k >= 0; k--) {
    fastOW.Recheck() otherwise goto Bailout(k, accumulator);

    // Ensure that we haven't walked beyond a possibly updated length.
    if (k >= fastOW.Get().length) goto Bailout(k, accumulator);

    const value: JSAny = fastOW.LoadElementNoHole(k) otherwise continue;
138 139
    typeswitch (accumulator) {
      case (TheHole): {
140
        accumulator = value;
141
      }
142 143 144 145
      case (accumulatorNotHole: JSAny): {
        accumulator = Call(
            context, callbackfn, Undefined, accumulatorNotHole, value, k,
            fastOW.Get());
146
      }
147 148
    }
  }
149 150 151 152 153 154 155 156 157 158
  typeswitch (accumulator) {
    case (TheHole): {
      ThrowTypeError(
          MessageTemplate::kReduceNoInitial, 'Array.prototype.reduceRight');
    }
    case (accumulator: JSAny): {
      return accumulator;
    }
  }
}
159

160 161 162 163 164 165
// https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight
transitioning javascript builtin
ArrayReduceRight(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
  try {
    RequireObjectCoercible(receiver, 'Array.prototype.reduceRight');
166

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

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

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

179 180 181
    // 4. If len is 0 and initialValue is not present, throw a TypeError
    // exception. (This case is handled at the end of
    // ArrayReduceRightLoopContinuation).
182

183 184
    const initialValue: JSAny|TheHole =
        arguments.length > 1 ? arguments[1] : TheHole;
185

186 187 188 189 190 191
    try {
      return FastArrayReduceRight(o, len, callbackfn, initialValue)
          otherwise Bailout;
    } label Bailout(value: Number, accumulator: JSAny|TheHole) {
      return ArrayReduceRightLoopContinuation(
          o, callbackfn, accumulator, o, value, len);
192
    }
193 194
  } label NoCallableError deferred {
    ThrowTypeError(MessageTemplate::kCalledNonCallable, arguments[0]);
195 196
  }
}
197
}