// 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_slice {
  macro HandleSimpleArgumentsSlice(
      context: Context, args: JSArgumentsObjectWithLength, start: Smi,
      count: Smi): JSArray
      labels Bailout {
    // If the resulting array doesn't fit in new space, use the slow path.
    if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout;

    const end: Smi = start + count;
    const sourceElements: FixedArray =
        Cast<FixedArray>(args.elements) otherwise Bailout;
    if (SmiAbove(end, sourceElements.length)) goto Bailout;

    const arrayMap: Map = LoadJSArrayElementsMap(HOLEY_ELEMENTS, context);
    const result: JSArray =
        AllocateJSArray(HOLEY_ELEMENTS, arrayMap, count, count);
    const newElements: FixedArray =
        Cast<FixedArray>(result.elements) otherwise Bailout;
    CopyElements(
        PACKED_ELEMENTS, newElements, 0, sourceElements, Convert<intptr>(start),
        Convert<intptr>(count));
    return result;
  }

  macro HandleFastAliasedSloppyArgumentsSlice(
      context: Context, args: JSArgumentsObjectWithLength, start: Smi,
      count: Smi): JSArray
      labels Bailout {
    // If the resulting array doesn't fit in new space, use the slow path.
    if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout;

    const sloppyElements: SloppyArgumentsElements =
        Cast<SloppyArgumentsElements>(args.elements) otherwise Bailout;
    const sloppyElementsLength: Smi = sloppyElements.length;
    const parameterMapLength: Smi =
        sloppyElementsLength - kSloppyArgumentsParameterMapStart;

    // Check to make sure that the extraction will not access outside the
    // defined arguments
    const end: Smi = start + count;
    const unmappedElements: FixedArray =
        Cast<FixedArray>(sloppyElements.objects[kSloppyArgumentsArgumentsIndex])
        otherwise Bailout;
    const unmappedElementsLength: Smi = unmappedElements.length;
    if (SmiAbove(end, unmappedElementsLength)) goto Bailout;

    const argumentsContext: Context = UnsafeCast<Context>(
        sloppyElements.objects[kSloppyArgumentsContextIndex]);

    const arrayMap: Map = LoadJSArrayElementsMap(HOLEY_ELEMENTS, context);
    const result: JSArray =
        AllocateJSArray(HOLEY_ELEMENTS, arrayMap, count, count);

    let indexOut: Smi = 0;
    const resultElements: FixedArray = UnsafeCast<FixedArray>(result.elements);
    const to: Smi = SmiMin(parameterMapLength, end);

    // Fill in the part of the result that map to context-mapped parameters.
    for (let current: Smi = start; current < to; ++current) {
      const e: Object =
          sloppyElements.objects[current + kSloppyArgumentsParameterMapStart];
      const newElement: Object = e != TheHole ?
          argumentsContext[UnsafeCast<Smi>(e)] :
          unmappedElements.objects[current];
      // It is safe to skip the write barrier here because resultElements was
      // allocated together with result in a folded allocation.
      // TODO(tebbi): The verification of this fails at the moment due to
      // missing load elimination.
      StoreFixedArrayElement(
          resultElements, indexOut++, newElement, UNSAFE_SKIP_WRITE_BARRIER);
    }

    // Fill in the rest of the result that contains the unmapped parameters
    // above the formal parameters.
    const unmappedFrom: Smi = SmiMin(SmiMax(parameterMapLength, start), end);
    const restCount: Smi = end - unmappedFrom;
    CopyElements(
        PACKED_ELEMENTS, resultElements, Convert<intptr>(indexOut),
        unmappedElements, Convert<intptr>(unmappedFrom),
        Convert<intptr>(restCount));
    return result;
  }

  macro HandleFastSlice(
      context: Context, o: Object, startNumber: Number,
      countNumber: Number): JSArray
      labels Bailout {
    const start: Smi = Cast<Smi>(startNumber) otherwise Bailout;
    const count: Smi = Cast<Smi>(countNumber) otherwise Bailout;
    assert(start >= 0);

    typeswitch (o) {
      case (a: FastJSArrayForCopy): {
        // It's possible to modify the array length from a valueOf
        // callback between the original array length read and this
        // point. That can change the length of the array backing store,
        // in the worst case, making it smaller than the region that needs
        // to be copied out. Therefore, re-check the length before calling
        // the appropriate fast path. See regress-785804.js
        if (SmiAbove(start + count, a.length)) goto Bailout;
        return ExtractFastJSArray(context, a, start, count);
      }
      case (a: JSArgumentsObjectWithLength): {
        const map: Map = a.map;
        if (IsFastAliasedArgumentsMap(map)) {
          return HandleFastAliasedSloppyArgumentsSlice(context, a, start, count)
              otherwise Bailout;
        } else if (IsStrictArgumentsMap(map) || IsSloppyArgumentsMap(map)) {
          return HandleSimpleArgumentsSlice(context, a, start, count)
              otherwise Bailout;
        }
      }
      case (Object): {
      }
    }
    goto Bailout;
  }

  // https://tc39.github.io/ecma262/#sec-array.prototype.slice
  transitioning javascript builtin
  ArrayPrototypeSlice(js-implicit context: Context, receiver: Object)(
      ...arguments): Object {
    // Handle array cloning case if the receiver is a fast array.
    if (arguments.length == 0) {
      typeswitch (receiver) {
        case (a: FastJSArrayForCopy): {
          return CloneFastJSArray(context, a);
        }
        case (Object): {
        }
      }
    }

    // 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. Let relativeStart be ? ToInteger(start).
    const start: Object = arguments[0];
    const relativeStart: Number = ToInteger_Inline(context, start);

    // 4. If relativeStart < 0, let k be max((len + relativeStart), 0);
    //    else let k be min(relativeStart, len).
    let k: Number = relativeStart < 0 ? Max((len + relativeStart), 0) :
                                        Min(relativeStart, len);

    // 5. If end is undefined, let relativeEnd be len;
    //    else let relativeEnd be ? ToInteger(end).
    const end: Object = arguments[1];
    const relativeEnd: Number =
        end == Undefined ? len : ToInteger_Inline(context, end);

    // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0);
    //    else let final be min(relativeEnd, len).
    const final: Number =
        relativeEnd < 0 ? Max((len + relativeEnd), 0) : Min(relativeEnd, len);

    // 7. Let count be max(final - k, 0).
    const count: Number = Max(final - k, 0);

    assert(0 <= k);
    assert(k <= len);
    assert(0 <= final);
    assert(final <= len);
    assert(0 <= count);
    assert(count <= len);

    try {
      return HandleFastSlice(context, o, k, count) otherwise Slow;
    }
    label Slow {}

    // 8. Let A be ? ArraySpeciesCreate(O, count).
    const a: JSReceiver = ArraySpeciesCreate(context, o, count);

    // 9. Let n be 0.
    let n: Number = 0;

    // 10. Repeat, while k < final
    while (k < final) {
      // a. Let Pk be ! ToString(k).
      const pK: Number = k;

      // b. Let kPresent be ? HasProperty(O, Pk).
      const fromPresent: Boolean = HasProperty(o, pK);

      // c. If kPresent is true, then
      if (fromPresent == True) {
        // i. Let kValue be ? Get(O, Pk).
        const kValue: Object = GetProperty(o, pK);

        // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue).
        FastCreateDataProperty(a, n, kValue);
      }

      // d. Increase k by 1.
      k++;

      // e. Increase n by 1.
      n++;
    }

    // 11. Perform ? Set(A, "length", n, true).
    SetProperty(a, kLengthString, n);

    // 12. Return A.
    return a;
  }
}
