// 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 {
macro HandleSimpleArgumentsSlice(
    context: NativeContext, 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(ElementsKind::HOLEY_ELEMENTS, context);
  const result: JSArray =
      AllocateJSArray(ElementsKind::HOLEY_ELEMENTS, arrayMap, count, count);
  const newElements: FixedArray =
      Cast<FixedArray>(result.elements) otherwise Bailout;
  CopyElements(
      ElementsKind::PACKED_ELEMENTS, newElements, 0, sourceElements,
      Convert<intptr>(start), Convert<intptr>(count));
  return result;
}

macro HandleFastAliasedSloppyArgumentsSlice(
    context: NativeContext, 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 parameterMapLength: Smi = sloppyElements.length;

  // 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.arguments)
      otherwise Bailout;
  const unmappedElementsLength: Smi = unmappedElements.length;
  if (SmiAbove(end, unmappedElementsLength)) goto Bailout;

  const argumentsContext: Context = sloppyElements.context;

  const arrayMap: Map =
      LoadJSArrayElementsMap(ElementsKind::HOLEY_ELEMENTS, context);
  const result: JSArray =
      AllocateJSArray(ElementsKind::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.mapped_entries[current];
    const newElement = UnsafeCast<(JSAny | TheHole)>(
        e != TheHole ? argumentsContext.elements[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(
      ElementsKind::PACKED_ELEMENTS, resultElements, Convert<intptr>(indexOut),
      unmappedElements, Convert<intptr>(unmappedFrom),
      Convert<intptr>(restCount));
  return result;
}

macro HandleFastSlice(
    context: NativeContext, o: JSAny, 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);

  try {
    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: JSStrictArgumentsObject): {
        goto HandleSimpleArgumentsSlice(a);
      }
      case (a: JSSloppyArgumentsObject): {
        const map: Map = a.map;
        if (IsFastAliasedArgumentsMap(map)) {
          return HandleFastAliasedSloppyArgumentsSlice(context, a, start, count)
              otherwise Bailout;
        } else if (IsSloppyArgumentsMap(map)) {
          goto HandleSimpleArgumentsSlice(a);
        }
        goto Bailout;
      }
      case (JSAny): {
        goto Bailout;
      }
    }
  } label HandleSimpleArgumentsSlice(a: JSArgumentsObjectWithLength) {
    return HandleSimpleArgumentsSlice(context, a, start, count)
        otherwise Bailout;
  }
}

// https://tc39.github.io/ecma262/#sec-array.prototype.slice
transitioning javascript builtin
ArrayPrototypeSlice(
    js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny {
  // 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 (JSAny): {
      }
    }
  }

  // 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: JSAny = arguments[0];
  const relativeStart: Number = ToInteger_Inline(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: JSAny = arguments[1];
  const relativeEnd: Number = end == Undefined ? len : ToInteger_Inline(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: JSAny = 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;
}
}
