array-lastindexof.tq 4.8 KB
Newer Older
1 2 3 4
// 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.

5
namespace array {
6 7 8 9 10 11 12 13 14 15 16 17
macro LoadWithHoleCheck<Elements : type extends FixedArrayBase>(
    elements: FixedArrayBase, index: Smi): JSAny
    labels IfHole;

LoadWithHoleCheck<FixedArray>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi): JSAny
    labels IfHole {
  const elements: FixedArray = UnsafeCast<FixedArray>(elements);
  const element: Object = elements.objects[index];
  if (element == TheHole) goto IfHole;
  return UnsafeCast<JSAny>(element);
}
18

19 20 21 22 23 24 25
LoadWithHoleCheck<FixedDoubleArray>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi): JSAny
    labels IfHole {
  const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
  const element: float64 = elements.floats[index].Value() otherwise IfHole;
  return AllocateHeapNumberWithValue(element);
}
26

27 28 29 30 31 32 33 34 35 36 37 38
macro FastArrayLastIndexOf<Elements : type extends FixedArrayBase>(
    context: Context, array: JSArray, from: Smi, searchElement: JSAny): Smi {
  const elements: FixedArrayBase = array.elements;
  let k: Smi = from;

  // Bug(898785): Due to side-effects in the evaluation of `fromIndex`
  // the {from} can be out-of-bounds here, so we need to clamp {k} to
  // the {elements} length. We might be reading holes / hole NaNs still
  // due to that, but those will be ignored below.
  if (k >= elements.length) {
    k = elements.length - 1;
  }
39

40 41 42 43
  while (k >= 0) {
    try {
      const element: JSAny = LoadWithHoleCheck<Elements>(elements, k)
          otherwise Hole;
44

45 46 47 48 49 50
      const same: Boolean = StrictEqual(searchElement, element);
      if (same == True) {
        assert(Is<FastJSArray>(array));
        return k;
      }
    } label Hole {}  // Do nothing for holes.
51

52
    --k;
53 54
  }

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
  assert(Is<FastJSArray>(array));
  return -1;
}

transitioning macro
GetFromIndex(context: Context, length: Number, arguments: Arguments): Number {
  // 4. If fromIndex is present, let n be ? ToInteger(fromIndex);
  //    else let n be len - 1.
  const n: Number =
      arguments.length < 2 ? length - 1 : ToInteger_Inline(arguments[1]);

  // 5. If n >= 0, then.
  let k: Number = SmiConstant(0);
  if (n >= 0) {
    // a. If n is -0, let k be +0; else let k be min(n, len - 1).
    // If n was -0 it got truncated to 0.0, so taking the minimum is fine.
    k = Min(n, length - 1);
  } else {
    // a. Let k be len + n.
    k = length + n;
75
  }
76 77
  return k;
}
78

79 80 81 82 83 84 85 86 87 88 89 90
macro TryFastArrayLastIndexOf(
    context: Context, receiver: JSReceiver, searchElement: JSAny,
    from: Number): JSAny
    labels Slow {
  const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
  const length: Smi = array.length;
  if (length == 0) return SmiConstant(-1);

  const fromSmi: Smi = Cast<Smi>(from) otherwise Slow;
  const kind: ElementsKind = array.map.elements_kind;
  if (IsFastSmiOrTaggedElementsKind(kind)) {
    return FastArrayLastIndexOf<FixedArray>(
91
        context, array, fromSmi, searchElement);
92
  }
93 94 95 96
  assert(IsDoubleElementsKind(kind));
  return FastArrayLastIndexOf<FixedDoubleArray>(
      context, array, fromSmi, searchElement);
}
97

98 99 100 101
transitioning macro GenericArrayLastIndexOf(
    context: Context, object: JSReceiver, searchElement: JSAny,
    from: Number): JSAny {
  let k: Number = from;
102

103 104 105 106
  // 7. Repeat, while k >= 0.
  while (k >= 0) {
    // a. Let kPresent be ? HasProperty(O, ! ToString(k)).
    const kPresent: Boolean = HasProperty(object, k);
107

108 109 110 111
    // b. If kPresent is true, then.
    if (kPresent == True) {
      // i. Let elementK be ? Get(O, ! ToString(k)).
      const element: JSAny = GetProperty(object, k);
112

113 114 115
      // ii. Let same be the result of performing Strict Equality Comparison
      //     searchElement === elementK.
      const same: Boolean = StrictEqual(searchElement, element);
116

117 118
      // iii. If same is true, return k.
      if (same == True) return k;
119 120
    }

121 122
    // c. Decrease k by 1.
    --k;
123 124
  }

125 126 127
  // 8. Return -1.
  return SmiConstant(-1);
}
128

129 130 131 132 133
// https://tc39.github.io/ecma262/#sec-array.prototype.lastIndexOf
transitioning javascript builtin ArrayPrototypeLastIndexOf(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
  // 1. Let O be ? ToObject(this value).
  const object: JSReceiver = ToObject_Inline(context, receiver);
134

135 136
  // 2. Let len be ? ToLength(? Get(O, "length")).
  const length: Number = GetLengthProperty(object);
137

138 139
  // 3. If len is 0, return -1.
  if (length == SmiConstant(0)) return SmiConstant(-1);
140

141 142
  // Step 4 - 6.
  const from: Number = GetFromIndex(context, length, arguments);
143

144 145 146 147 148 149 150
  const searchElement: JSAny = arguments[0];

  try {
    return TryFastArrayLastIndexOf(context, object, searchElement, from)
        otherwise Baseline;
  } label Baseline {
    return GenericArrayLastIndexOf(context, object, searchElement, from);
151 152
  }
}
153
}