array-reverse.tq 6.21 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
macro LoadElement<ElementsAccessor : type extends ElementsKind, T: type>(
    elements: FixedArrayBase, index: Smi): T;
8

9 10 11 12 13
LoadElement<array::FastPackedSmiElements, Smi>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi): Smi {
  const elements: FixedArray = UnsafeCast<FixedArray>(elements);
  return UnsafeCast<Smi>(elements.objects[index]);
}
14

15 16 17 18 19
LoadElement<array::FastPackedObjectElements, JSAny>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi): JSAny {
  const elements: FixedArray = UnsafeCast<FixedArray>(elements);
  return UnsafeCast<JSAny>(elements.objects[index]);
}
20

21 22 23 24 25 26 27
LoadElement<array::FastPackedDoubleElements, float64>(
    implicit context: Context)(elements: FixedArrayBase, index: Smi): float64 {
  const elements: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
  // This macro is only used for PACKED_DOUBLE, loading the hole should
  // be impossible.
  return elements.floats[index].Value() otherwise unreachable;
}
28

29 30
macro StoreElement<ElementsAccessor : type extends ElementsKind, T: type>(
    implicit context: Context)(elements: FixedArrayBase, index: Smi, value: T);
31

32 33 34
StoreElement<array::FastPackedSmiElements, Smi>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi, value: Smi) {
  const elems: FixedArray = UnsafeCast<FixedArray>(elements);
35
  StoreFixedArrayElement(elems, index, value);
36
}
37

38 39 40 41 42 43 44 45 46 47
StoreElement<array::FastPackedObjectElements, JSAny>(implicit context: Context)(
    elements: FixedArrayBase, index: Smi, value: JSAny) {
  const elements: FixedArray = UnsafeCast<FixedArray>(elements);
  elements.objects[index] = value;
}

StoreElement<array::FastPackedDoubleElements, float64>(
    implicit context: Context)(
    elements: FixedArrayBase, index: Smi, value: float64) {
  const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
48
  StoreFixedDoubleArrayElement(elems, index, value);
49
}
50

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
// Fast-path for all PACKED_* elements kinds. These do not need to check
// whether a property is present, so we can simply swap them using fast
// FixedArray loads/stores.
macro FastPackedArrayReverse<Accessor: type, T: type>(
    implicit context: Context)(elements: FixedArrayBase, length: Smi) {
  let lower: Smi = 0;
  let upper: Smi = length - 1;

  while (lower < upper) {
    const lowerValue: T = LoadElement<Accessor, T>(elements, lower);
    const upperValue: T = LoadElement<Accessor, T>(elements, upper);
    StoreElement<Accessor>(elements, lower, upperValue);
    StoreElement<Accessor>(elements, upper, lowerValue);
    ++lower;
    --upper;
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
transitioning macro GenericArrayReverse(
    context: Context, receiver: JSAny): JSAny {
  // 1. Let O be ? ToObject(this value).
  const object: JSReceiver = ToObject_Inline(context, receiver);

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

  // 3. Let middle be floor(len / 2).
  // 4. Let lower be 0.
  // 5. Repeat, while lower != middle.
  //   a. Let upper be len - lower - 1.

  // Instead of calculating the middle value, we simply initialize upper
  // with len - 1 and decrement it after each iteration.
  let lower: Number = 0;
  let upper: Number = length - 1;

  while (lower < upper) {
    let lowerValue: JSAny = Undefined;
    let upperValue: JSAny = Undefined;

    // b. Let upperP be ! ToString(upper).
    // c. Let lowerP be ! ToString(lower).
    // d. Let lowerExists be ? HasProperty(O, lowerP).
    const lowerExists: Boolean = HasProperty(object, lower);

    // e. If lowerExists is true, then.
    if (lowerExists == True) {
      // i. Let lowerValue be ? Get(O, lowerP).
      lowerValue = GetProperty(object, lower);
100 101
    }

102 103 104 105 106 107 108
    // f. Let upperExists be ? HasProperty(O, upperP).
    const upperExists: Boolean = HasProperty(object, upper);

    // g. If upperExists is true, then.
    if (upperExists == True) {
      // i. Let upperValue be ? Get(O, upperP).
      upperValue = GetProperty(object, upper);
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
    // h. If lowerExists is true and upperExists is true, then
    if (lowerExists == True && upperExists == True) {
      // i. Perform ? Set(O, lowerP, upperValue, true).
      SetProperty(object, lower, upperValue);

      // ii. Perform ? Set(O, upperP, lowerValue, true).
      SetProperty(object, upper, lowerValue);
    } else if (lowerExists == False && upperExists == True) {
      // i. Perform ? Set(O, lowerP, upperValue, true).
      SetProperty(object, lower, upperValue);

      // ii. Perform ? DeletePropertyOrThrow(O, upperP).
      DeleteProperty(object, upper, LanguageMode::kStrict);
    } else if (lowerExists == True && upperExists == False) {
      // i. Perform ? DeletePropertyOrThrow(O, lowerP).
      DeleteProperty(object, lower, LanguageMode::kStrict);

      // ii. Perform ? Set(O, upperP, lowerValue, true).
      SetProperty(object, upper, lowerValue);
    }

    // l. Increase lower by 1.
    ++lower;
    --upper;
135 136
  }

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
  // 6. Return O.
  return object;
}

macro TryFastPackedArrayReverse(implicit context: Context)(receiver: JSAny)
    labels Slow {
  const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;

  const kind: ElementsKind = array.map.elements_kind;
  if (kind == ElementsKind::PACKED_SMI_ELEMENTS) {
    array::EnsureWriteableFastElements(array);
    FastPackedArrayReverse<array::FastPackedSmiElements, Smi>(
        array.elements, array.length);
  } else if (kind == ElementsKind::PACKED_ELEMENTS) {
    array::EnsureWriteableFastElements(array);
    FastPackedArrayReverse<array::FastPackedObjectElements, JSAny>(
        array.elements, array.length);
  } else if (kind == ElementsKind::PACKED_DOUBLE_ELEMENTS) {
    FastPackedArrayReverse<array::FastPackedDoubleElements, float64>(
        array.elements, array.length);
  } else {
    goto Slow;
159
  }
160
}
161

162 163 164 165 166 167 168 169
// https://tc39.github.io/ecma262/#sec-array.prototype.reverse
transitioning javascript builtin ArrayPrototypeReverse(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
  try {
    TryFastPackedArrayReverse(receiver) otherwise Baseline;
    return receiver;
  } label Baseline {
    return GenericArrayReverse(context, receiver);
170 171
  }
}
172
}