array-reduce.tq 7.17 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
transitioning javascript builtin
ArrayReducePreLoopEagerDeoptContinuation(
    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;

  // Simulate starting the loop at 0, but ensuring that the accumulator is
  // the hole. The continuation stub will search for the initial non-hole
  // element, rightly throwing an exception if not found.
  return ArrayReduceLoopContinuation(
      jsreceiver, callbackfn, TheHole, jsreceiver, 0, numberLength);
}
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
transitioning javascript builtin
ArrayReduceLoopEagerDeoptContinuation(
    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 ArrayReduceLoopContinuation(
      jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength);
}
48

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
transitioning javascript builtin
ArrayReduceLoopLazyDeoptContinuation(
    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 = ArrayReduceLoopContinuation(
      jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
  return r;
}
66

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

73 74 75 76 77
  // 8b and 9. Repeat, while k < len
  for (let k: Number = initialK; k < length; 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.
78

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

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

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

    // 8b iv and 9d. Increase 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.reduce');
    }
    case (accumulator: JSAny): {
      return accumulator;
    }
  }
}

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

  // Build a fast loop over the array.
  for (let k: Smi = 0; k < len; 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;
137 138
    typeswitch (accumulator) {
      case (TheHole): {
139
        accumulator = value;
140
      }
141 142 143 144
      case (accumulatorNotHole: JSAny): {
        accumulator = Call(
            context, callbackfn, Undefined, accumulatorNotHole, value, k,
            fastOW.Get());
145
      }
146 147
    }
  }
148 149 150 151 152 153 154 155 156 157
  typeswitch (accumulator) {
    case (TheHole): {
      ThrowTypeError(
          MessageTemplate::kReduceNoInitial, 'Array.prototype.reduce');
    }
    case (accumulator: JSAny): {
      return accumulator;
    }
  }
}
158

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

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

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

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

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

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

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