array-reduce-right.tq 7.83 KB
Newer Older
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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196
// 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 {
  transitioning javascript builtin
  ArrayReduceRightPreLoopEagerDeoptContinuation(implicit context: Context)(
      receiver: Object, callback: Object, length: Object): Object {
    // 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 Object 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 ArrayReduceRightLoopContinuation(
        jsreceiver, callbackfn, Hole, jsreceiver, 0, numberLength);
  }

  transitioning javascript builtin
  ArrayReduceRightLoopEagerDeoptContinuation(implicit context: Context)(
      receiver: Object, callback: Object, initialK: Object, length: Object,
      accumulator: Object): Object {
    // 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 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 ArrayReduceRightLoopContinuation(
        jsreceiver, callbackfn, accumulator, jsreceiver, numberK, numberLength);
  }

  transitioning javascript builtin
  ArrayReduceRightLoopLazyDeoptContinuation(implicit context: Context)(
      receiver: Object, callback: Object, initialK: Object, length: Object,
      result: Object): Object {
    // 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;
    let 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.
    let r = ArrayReduceRightLoopContinuation(
        jsreceiver, callbackfn, result, jsreceiver, numberK, numberLength);
    return r;
  }

  transitioning builtin ArrayReduceRightLoopContinuation(implicit context:
                                                             Context)(
      receiver: JSReceiver, callbackfn: Callable, initialAccumulator: Object,
      o: JSReceiver, initialK: Number, length: Number): Object {
    let accumulator = initialAccumulator;

    // 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.

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

      // 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: Object = GetProperty(o, k);

        if (accumulator == Hole) {
          // 8b iii 1.
          accumulator = value;
        } else {
          // 9c. ii. Set accumulator to ? Call(callbackfn, undefined,
          //         <accumulator, kValue, k, O>).
          accumulator =
              Call(context, callbackfn, Undefined, accumulator, value, k, o);
        }
      }

      // 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.
    if (accumulator == Hole) {
      ThrowTypeError(context, kReduceNoInitial, 'Array.prototype.reduceRight');
    }
    return accumulator;
  }

  transitioning macro
  ReduceRightVisitAllElements<FixedArrayType: type>(implicit context: Context)(
      o: FastJSArray, len: Smi, callbackfn: Callable,
      initialAccumulator: Object): Object
      labels Bailout(Number, Object) {
    let fastO = FastJSArrayWitness{o};
    let accumulator = initialAccumulator;

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

      const value: Object = LoadElementNoHole<FixedArrayType>(fastO.Get(), k)
          otherwise continue;
      if (accumulator == Hole) {
        accumulator = value;
      } else {
        accumulator = Call(
            context, callbackfn, Undefined, accumulator, value, k, fastO.Get());
      }
    }
    if (accumulator == Hole) {
      ThrowTypeError(context, kReduceNoInitial, 'Array.prototype.reduceRight');
    }
    return accumulator;
  }

  transitioning macro FastArrayReduceRight(implicit context: Context)(
      o: JSReceiver, len: Number, callbackfn: Callable,
      accumulator: Object): Object
      labels Bailout(Number, Object) {
    const k = len - 1;
    const smiLen = Cast<Smi>(len) otherwise goto Bailout(k, accumulator);
    let fastO = Cast<FastJSArray>(o) otherwise goto Bailout(k, accumulator);
    const elementsKind: ElementsKind = fastO.map.elements_kind;
    if (IsElementsKindGreaterThan(elementsKind, HOLEY_ELEMENTS)) {
      return ReduceRightVisitAllElements<FixedDoubleArray>(
          fastO, smiLen, callbackfn, accumulator) otherwise Bailout;
    } else {
      return ReduceRightVisitAllElements<FixedArray>(
          fastO, smiLen, callbackfn, accumulator) otherwise Bailout;
    }
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.reduceRight
  transitioning javascript builtin
  ArrayReduceRight(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 NoCallableError;
      }
      const callbackfn = Cast<Callable>(arguments[0]) otherwise NoCallableError;

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

      const initialValue: Object = arguments.length > 1 ? arguments[1] : Hole;

      try {
        return FastArrayReduceRight(o, len, callbackfn, initialValue)
            otherwise Bailout;
      }
      label Bailout(value: Number, accumulator: Object) {
        return ArrayReduceRightLoopContinuation(
            o, callbackfn, accumulator, o, value, len);
      }
    }
    label NoCallableError deferred {
      ThrowTypeError(context, kCalledNonCallable, arguments[0]);
    }
    label NullOrUndefinedError deferred {
      ThrowTypeError(
          context, kCalledOnNullOrUndefined, 'Array.prototype.reduceRight');
    }
  }
}