blob: c3a6ac75cb0ec7b874638238209c246a0b4e50bf [file] [log] [blame]
// 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;
}
}