blob: 7b82f2bda33caf5ddd2dd9669e22b75a4db45219 [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 {
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;
}
}