array-reverse.tq 6.42 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_reverse {
6
  macro LoadElement<ElementsAccessor: type, T: type>(
7 8
      elements: FixedArrayBase, index: Smi): T;

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

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

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

31
  macro StoreElement<ElementsAccessor: type, T: type>(
32 33
      implicit context:
          Context)(elements: FixedArrayBase, index: Smi, value: T);
34

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

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

48 49 50
  StoreElement<array::FastPackedDoubleElements, float64>(
      implicit context:
          Context)(elements: FixedArrayBase, index: Smi, value: float64) {
51
    const elems: FixedDoubleArray = UnsafeCast<FixedDoubleArray>(elements);
52
    StoreFixedDoubleArrayElementSmi(elems, index, value);
53 54 55 56 57
  }

  // 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.
58
  macro FastPackedArrayReverse<Accessor: type, T: type>(
59
      implicit context: Context)(elements: FixedArrayBase, length: Smi) {
60 61 62 63
    let lower: Smi = 0;
    let upper: Smi = length - 1;

    while (lower < upper) {
64 65
      const lowerValue: T = LoadElement<Accessor, T>(elements, lower);
      const upperValue: T = LoadElement<Accessor, T>(elements, upper);
66 67
      StoreElement<Accessor>(elements, lower, upperValue);
      StoreElement<Accessor>(elements, upper, lowerValue);
68 69 70 71 72
      ++lower;
      --upper;
    }
  }

73 74
  transitioning macro GenericArrayReverse(context: Context, receiver: Object):
      Object {
75 76 77 78
    // 1. Let O be ? ToObject(this value).
    const object: JSReceiver = ToObject_Inline(context, receiver);

    // 2. Let len be ? ToLength(? Get(O, "length")).
79
    const length: Number = GetLengthProperty(object);
80 81 82 83 84 85 86 87 88 89 90 91

    // 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) {
92 93
      let lowerValue: Object = Undefined;
      let upperValue: Object = Undefined;
94 95 96 97

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

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

      // f. Let upperExists be ? HasProperty(O, upperP).
107
      const upperExists: Boolean = HasProperty(object, upper);
108 109

      // g. If upperExists is true, then.
110
      if (upperExists == True) {
111
        // i. Let upperValue be ? Get(O, upperP).
112
        upperValue = GetProperty(object, upper);
113 114 115
      }

      // h. If lowerExists is true and upperExists is true, then
116
      if (lowerExists == True && upperExists == True) {
117
        // i. Perform ? Set(O, lowerP, upperValue, true).
118
        SetProperty(object, lower, upperValue);
119 120

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

        // ii. Perform ? DeletePropertyOrThrow(O, upperP).
127
        DeleteProperty(object, upper, kStrict);
128
      } else if (lowerExists == True && upperExists == False) {
129
        // i. Perform ? DeletePropertyOrThrow(O, lowerP).
130
        DeleteProperty(object, lower, kStrict);
131 132

        // ii. Perform ? Set(O, upperP, lowerValue, true).
133
        SetProperty(object, upper, lowerValue);
134 135 136 137 138 139 140 141 142 143 144
      }

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

    // 6. Return O.
    return object;
  }

145
  macro TryFastPackedArrayReverse(implicit context: Context)(receiver: Object)
146
      labels Slow {
147
    const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
148

149
    const kind: ElementsKind = array.map.elements_kind;
150
    if (kind == PACKED_SMI_ELEMENTS) {
151 152
      array::EnsureWriteableFastElements(array);
      FastPackedArrayReverse<array::FastPackedSmiElements, Smi>(
153
          array.elements, array.length);
154
    } else if (kind == PACKED_ELEMENTS) {
155 156
      array::EnsureWriteableFastElements(array);
      FastPackedArrayReverse<array::FastPackedObjectElements, Object>(
157
          array.elements, array.length);
158
    } else if (kind == PACKED_DOUBLE_ELEMENTS) {
159
      FastPackedArrayReverse<array::FastPackedDoubleElements, float64>(
160
          array.elements, array.length);
161 162 163 164 165 166
    } else {
      goto Slow;
    }
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.reverse
167
  transitioning javascript builtin ArrayPrototypeReverse(
168 169 170 171 172 173 174 175 176 177
      context: Context, receiver: Object, ...arguments): Object {
    try {
      TryFastPackedArrayReverse(receiver) otherwise Baseline;
      return receiver;
    }
    label Baseline {
      return GenericArrayReverse(context, receiver);
    }
  }
}