[builtins] Implement Array.prototype.slice in Torque
In the process: - add volatile types for FastJSArray and remove the length_fast accessor from JSArray with the application of more rigorous typing. - add micro benchmarks for testing all the interesting slice cases Also update a few assorted places in .tq code to make them more idiomatic. Change-Id: I76ec2bb25b65a869180af1f7288419dc1f0a9c37 Reviewed-on: https://chromium-review.googlesource.com/c/1281603 Commit-Queue: Daniel Clifford <danno@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/master@{#56806}
This commit is contained in:
parent
2d8adf3db2
commit
41ba3d3eb0
1
BUILD.gn
1
BUILD.gn
@ -917,6 +917,7 @@ torque_files = [
|
|||||||
"src/builtins/array-join.tq",
|
"src/builtins/array-join.tq",
|
||||||
"src/builtins/array-lastindexof.tq",
|
"src/builtins/array-lastindexof.tq",
|
||||||
"src/builtins/array-reverse.tq",
|
"src/builtins/array-reverse.tq",
|
||||||
|
"src/builtins/array-slice.tq",
|
||||||
"src/builtins/array-splice.tq",
|
"src/builtins/array-splice.tq",
|
||||||
"src/builtins/array-unshift.tq",
|
"src/builtins/array-unshift.tq",
|
||||||
"src/builtins/typed-array.tq",
|
"src/builtins/typed-array.tq",
|
||||||
|
83
benchmarks/micro/slice-perf.js
Normal file
83
benchmarks/micro/slice-perf.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
const kIterations = 1000000;
|
||||||
|
const kIterationShort = 10000;
|
||||||
|
const kArraySize = 64;
|
||||||
|
|
||||||
|
let smi_array = [];
|
||||||
|
for (let i = 0; i < kArraySize; ++i) smi_array[i] = Math.floor(Math.random() * 100);
|
||||||
|
|
||||||
|
let start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
smi_array.slice(0);
|
||||||
|
}
|
||||||
|
let stop = performance.now();
|
||||||
|
print("smi_array copy: " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
smi_array.slice(x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("smi_array: " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
let double_array = [];
|
||||||
|
for (let i = 0; i < kArraySize; ++i) double_array[i] = Math.random() * 100;
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
double_array.slice(x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("double_array: " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
let object_array = [];
|
||||||
|
for (let i = 0; i < kArraySize; ++i) object_array[i] = new Object();
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
object_array.slice(x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("object_array: " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
let dictionary_array = [];
|
||||||
|
for (let i = 0; i < kArraySize; ++i) dictionary_array[i] = new Object();
|
||||||
|
dictionary_array[100000] = new Object();
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterationShort; ++x) {
|
||||||
|
dictionary_array.slice(x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("dictionary: " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
let arguments_array;
|
||||||
|
function sloppy() {
|
||||||
|
arguments_array = arguments;
|
||||||
|
}
|
||||||
|
sloppy.apply(null, smi_array);
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
let r = Array.prototype.slice.call(arguments_array, x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("arguments_array (sloppy): " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
function sloppy2 (a) {
|
||||||
|
arguments_array = arguments;
|
||||||
|
}
|
||||||
|
sloppy2.apply(null, smi_array);
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterations; ++x) {
|
||||||
|
Array.prototype.slice.call(arguments_array, x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("arguments_array (fast aliased): " + (Math.floor((stop - start)*10)/10) + " ms");
|
||||||
|
|
||||||
|
delete arguments_array[5];
|
||||||
|
start = performance.now();
|
||||||
|
for (let x = 0; x < kIterationShort; ++x) {
|
||||||
|
Array.prototype.slice.call(arguments_array, x % kArraySize);
|
||||||
|
}
|
||||||
|
stop = performance.now();
|
||||||
|
print("arguments_array (slow aliased): " + (Math.floor((stop - start)*10)/10) + " ms");
|
@ -1739,8 +1739,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
|||||||
Builtins::kArrayPrototypeShift, 0, false);
|
Builtins::kArrayPrototypeShift, 0, false);
|
||||||
SimpleInstallFunction(isolate_, proto, "unshift",
|
SimpleInstallFunction(isolate_, proto, "unshift",
|
||||||
Builtins::kArrayPrototypeUnshift, 1, false);
|
Builtins::kArrayPrototypeUnshift, 1, false);
|
||||||
SimpleInstallFunction(isolate_, proto, "slice",
|
SimpleInstallFunction(isolate_, proto, "slice", Builtins::kArraySlice, 2,
|
||||||
Builtins::kArrayPrototypeSlice, 2, false);
|
false);
|
||||||
SimpleInstallFunction(isolate_, proto, "sort",
|
SimpleInstallFunction(isolate_, proto, "sort",
|
||||||
Builtins::kArrayPrototypeSort, 1, false);
|
Builtins::kArrayPrototypeSort, 1, false);
|
||||||
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice, 2,
|
SimpleInstallFunction(isolate_, proto, "splice", Builtins::kArraySplice, 2,
|
||||||
|
@ -75,10 +75,8 @@ module array {
|
|||||||
context: Context, receiver: JSReceiver, searchElement: Object,
|
context: Context, receiver: JSReceiver, searchElement: Object,
|
||||||
from: Number): Object
|
from: Number): Object
|
||||||
labels Slow {
|
labels Slow {
|
||||||
EnsureFastJSArray(context, receiver) otherwise Slow;
|
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||||
const array: JSArray = UnsafeCast<JSArray>(receiver);
|
const length: Smi = array.length;
|
||||||
|
|
||||||
const length: Smi = array.length_fast;
|
|
||||||
if (length == 0) return SmiConstant(-1);
|
if (length == 0) return SmiConstant(-1);
|
||||||
|
|
||||||
const fromSmi: Smi = Cast<Smi>(from) otherwise Slow;
|
const fromSmi: Smi = Cast<Smi>(from) otherwise Slow;
|
||||||
|
@ -143,21 +143,22 @@ module array {
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro TryFastPackedArrayReverse(receiver: Object) labels Slow {
|
macro TryFastPackedArrayReverse(implicit context: Context)(receiver: Object)
|
||||||
const array: JSArray = Cast<JSArray>(receiver) otherwise Slow;
|
labels Slow {
|
||||||
|
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||||
|
|
||||||
const kind: ElementsKind = array.map.elements_kind;
|
const kind: ElementsKind = array.map.elements_kind;
|
||||||
if (kind == PACKED_SMI_ELEMENTS) {
|
if (kind == PACKED_SMI_ELEMENTS) {
|
||||||
EnsureWriteableFastElements(array);
|
EnsureWriteableFastElements(array);
|
||||||
FastPackedArrayReverse<FastPackedSmiElements, Smi>(
|
FastPackedArrayReverse<FastPackedSmiElements, Smi>(
|
||||||
array.elements, array.length_fast);
|
array.elements, array.length);
|
||||||
} else if (kind == PACKED_ELEMENTS) {
|
} else if (kind == PACKED_ELEMENTS) {
|
||||||
EnsureWriteableFastElements(array);
|
EnsureWriteableFastElements(array);
|
||||||
FastPackedArrayReverse<FastPackedObjectElements, Object>(
|
FastPackedArrayReverse<FastPackedObjectElements, Object>(
|
||||||
array.elements, array.length_fast);
|
array.elements, array.length);
|
||||||
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
|
} else if (kind == PACKED_DOUBLE_ELEMENTS) {
|
||||||
FastPackedArrayReverse<FastPackedDoubleElements, float64>(
|
FastPackedArrayReverse<FastPackedDoubleElements, float64>(
|
||||||
array.elements, array.length_fast);
|
array.elements, array.length);
|
||||||
} else {
|
} else {
|
||||||
goto Slow;
|
goto Slow;
|
||||||
}
|
}
|
||||||
|
208
src/builtins/array-slice.tq
Normal file
208
src/builtins/array-slice.tq
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
|
module array {
|
||||||
|
macro HandleSimpleArgumentsSlice(
|
||||||
|
context: Context, args: JSArgumentsObjectWithLength, start: Smi,
|
||||||
|
count: Smi): JSArray
|
||||||
|
labels 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, Convert<intptr>(0), sourceElements,
|
||||||
|
Convert<intptr>(start), Convert<intptr>(count));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro HandleFastAliasedSloppyArgumentsSlice(
|
||||||
|
context: Context, args: JSArgumentsObjectWithLength, start: Smi,
|
||||||
|
count: Smi): JSArray
|
||||||
|
labels 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[kSloppyArgumentsArgumentsIndex])
|
||||||
|
otherwise Bailout;
|
||||||
|
const unmappedElementsLength: Smi = unmappedElements.length;
|
||||||
|
if (SmiAbove(end, unmappedElementsLength)) goto Bailout;
|
||||||
|
|
||||||
|
const argumentsContext: Context =
|
||||||
|
UnsafeCast<Context>(sloppyElements[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[current + kSloppyArgumentsParameterMapStart];
|
||||||
|
const newElement: Object = e != Hole ?
|
||||||
|
argumentsContext[UnsafeCast<Smi>(e)] :
|
||||||
|
unmappedElements[current];
|
||||||
|
StoreFixedArrayElementSmi(
|
||||||
|
resultElements, indexOut++, newElement, 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);
|
||||||
|
|
||||||
|
// If the resulting array doesn't fit in new space, use the slow path.
|
||||||
|
if (count >= kMaxNewSpaceFixedArrayElements) goto Bailout;
|
||||||
|
|
||||||
|
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 nativeContext: NativeContext = LoadNativeContext(context);
|
||||||
|
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
|
||||||
|
javascript builtin ArraySlice(
|
||||||
|
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).
|
||||||
|
let 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).
|
||||||
|
CreateDataProperty(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;
|
||||||
|
}
|
||||||
|
}
|
@ -9,8 +9,7 @@ module array {
|
|||||||
context: Context, receiver: Object, arguments: constexpr Arguments):
|
context: Context, receiver: Object, arguments: constexpr Arguments):
|
||||||
never
|
never
|
||||||
labels Slow {
|
labels Slow {
|
||||||
EnsureFastJSArray(context, receiver) otherwise Slow;
|
const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||||
const array: JSArray = UnsafeCast<JSArray>(receiver);
|
|
||||||
EnsureWriteableFastElements(array);
|
EnsureWriteableFastElements(array);
|
||||||
|
|
||||||
const map: Map = array.map;
|
const map: Map = array.map;
|
||||||
|
@ -24,7 +24,7 @@ module array {
|
|||||||
// extract FixedArrays and don't have to worry about FixedDoubleArrays.
|
// extract FixedArrays and don't have to worry about FixedDoubleArrays.
|
||||||
assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind));
|
assert(IsFastSmiOrTaggedElementsKind(array.map.elements_kind));
|
||||||
|
|
||||||
const length: Smi = array.length_fast;
|
const length: Smi = Cast<Smi>(array.length) otherwise unreachable;
|
||||||
array.elements =
|
array.elements =
|
||||||
ExtractFixedArray(elements, 0, length, length, kFixedArrays);
|
ExtractFixedArray(elements, 0, length, length, kFixedArrays);
|
||||||
assert(array.elements.map != kCOWMap);
|
assert(array.elements.map != kCOWMap);
|
||||||
|
@ -40,6 +40,10 @@ type JSArgumentsObjectWithLength extends JSObject
|
|||||||
generates 'TNode<JSArgumentsObjectWithLength>';
|
generates 'TNode<JSArgumentsObjectWithLength>';
|
||||||
type JSArray extends JSArgumentsObjectWithLength
|
type JSArray extends JSArgumentsObjectWithLength
|
||||||
generates 'TNode<JSArray>';
|
generates 'TNode<JSArray>';
|
||||||
|
type FastJSArray extends JSArray
|
||||||
|
generates 'TNode<JSArray>';
|
||||||
|
type FastJSArrayForCopy extends FastJSArray
|
||||||
|
generates 'TNode<JSArray>';
|
||||||
type JSFunction extends JSObject generates 'TNode<JSFunction>';
|
type JSFunction extends JSObject generates 'TNode<JSFunction>';
|
||||||
type JSBoundFunction extends JSObject generates 'TNode<JSBoundFunction>';
|
type JSBoundFunction extends JSObject generates 'TNode<JSBoundFunction>';
|
||||||
type Callable = JSFunction|JSBoundFunction|JSProxy;
|
type Callable = JSFunction|JSBoundFunction|JSProxy;
|
||||||
@ -52,20 +56,14 @@ type FixedTypedArrayBase extends FixedArrayBase
|
|||||||
generates 'TNode<FixedTypedArrayBase>';
|
generates 'TNode<FixedTypedArrayBase>';
|
||||||
type FixedTypedArray extends FixedTypedArrayBase
|
type FixedTypedArray extends FixedTypedArrayBase
|
||||||
generates 'TNode<FixedTypedArray>';
|
generates 'TNode<FixedTypedArray>';
|
||||||
|
type SloppyArgumentsElements extends FixedArray
|
||||||
|
generates 'TNode<FixedArray>';
|
||||||
type NumberDictionary extends HeapObject
|
type NumberDictionary extends HeapObject
|
||||||
generates 'TNode<NumberDictionary>';
|
generates 'TNode<NumberDictionary>';
|
||||||
|
|
||||||
type NativeContextSlot generates 'TNode<IntPtrT>' constexpr 'int32_t';
|
type NativeContextSlot generates 'TNode<IntPtrT>' constexpr 'int32_t';
|
||||||
const ARRAY_JOIN_STACK_INDEX: constexpr NativeContextSlot
|
const ARRAY_JOIN_STACK_INDEX: constexpr NativeContextSlot
|
||||||
generates 'Context::ARRAY_JOIN_STACK_INDEX';
|
generates 'Context::ARRAY_JOIN_STACK_INDEX';
|
||||||
const FAST_ALIASED_ARGUMENTS_MAP_INDEX: constexpr NativeContextSlot
|
|
||||||
generates 'Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX';
|
|
||||||
const SLOW_ALIASED_ARGUMENTS_MAP_INDEX: constexpr NativeContextSlot
|
|
||||||
generates 'Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX';
|
|
||||||
const STRICT_ARGUMENTS_MAP_INDEX: constexpr NativeContextSlot
|
|
||||||
generates 'Context::STRICT_ARGUMENTS_MAP_INDEX';
|
|
||||||
const SLOPPY_ARGUMENTS_MAP_INDEX: constexpr NativeContextSlot
|
|
||||||
generates 'Context::SLOPPY_ARGUMENTS_MAP_INDEX';
|
|
||||||
extern operator '[]' macro LoadContextElement(
|
extern operator '[]' macro LoadContextElement(
|
||||||
NativeContext, NativeContextSlot): Object;
|
NativeContext, NativeContextSlot): Object;
|
||||||
extern operator '[]=' macro StoreContextElement(
|
extern operator '[]=' macro StoreContextElement(
|
||||||
@ -177,6 +175,18 @@ const kStringMaxLength: constexpr int31 generates 'String::kMaxLength';
|
|||||||
const kFixedArrayMaxLength:
|
const kFixedArrayMaxLength:
|
||||||
constexpr int31 generates 'FixedArray::kMaxLength';
|
constexpr int31 generates 'FixedArray::kMaxLength';
|
||||||
|
|
||||||
|
const kMaxRegularHeapObjectSize: constexpr int31
|
||||||
|
generates 'kMaxRegularHeapObjectSize';
|
||||||
|
|
||||||
|
const kMaxNewSpaceFixedArrayElements: constexpr int31
|
||||||
|
generates 'FixedArray::kMaxRegularLength';
|
||||||
|
const kSloppyArgumentsArgumentsIndex: constexpr int31
|
||||||
|
generates 'SloppyArgumentsElements::kArgumentsIndex';
|
||||||
|
const kSloppyArgumentsContextIndex: constexpr int31
|
||||||
|
generates 'SloppyArgumentsElements::kContextIndex';
|
||||||
|
const kSloppyArgumentsParameterMapStart: constexpr int31
|
||||||
|
generates 'SloppyArgumentsElements::kParameterMapStart';
|
||||||
|
|
||||||
const kTruncateMinusZero: constexpr ToIntegerTruncationMode
|
const kTruncateMinusZero: constexpr ToIntegerTruncationMode
|
||||||
generates 'ToIntegerTruncationMode::kTruncateMinusZero';
|
generates 'ToIntegerTruncationMode::kTruncateMinusZero';
|
||||||
|
|
||||||
@ -308,6 +318,11 @@ extern macro IsElementsKindGreaterThan(
|
|||||||
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
|
extern macro IsFastElementsKind(constexpr ElementsKind): constexpr bool;
|
||||||
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
|
extern macro IsDoubleElementsKind(constexpr ElementsKind): constexpr bool;
|
||||||
|
|
||||||
|
extern macro IsFastAliasedArgumentsMap(implicit context: Context)(Map): bool;
|
||||||
|
extern macro IsSlowAliasedArgumentsMap(implicit context: Context)(Map): bool;
|
||||||
|
extern macro IsSloppyArgumentsMap(implicit context: Context)(Map): bool;
|
||||||
|
extern macro IsStrictArgumentsMap(implicit context: Context)(Map): bool;
|
||||||
|
|
||||||
extern macro SmiAbove(Smi, Smi): bool;
|
extern macro SmiAbove(Smi, Smi): bool;
|
||||||
|
|
||||||
extern operator '==' macro WordEqual(intptr, intptr): bool;
|
extern operator '==' macro WordEqual(intptr, intptr): bool;
|
||||||
@ -442,6 +457,9 @@ extern macro HeapObjectToString(HeapObject): String
|
|||||||
labels CastError;
|
labels CastError;
|
||||||
extern macro HeapObjectToHeapNumber(HeapObject): HeapNumber
|
extern macro HeapObjectToHeapNumber(HeapObject): HeapNumber
|
||||||
labels CastError;
|
labels CastError;
|
||||||
|
extern macro HeapObjectToSloppyArgumentsElements(HeapObject):
|
||||||
|
SloppyArgumentsElements
|
||||||
|
labels CastError;
|
||||||
extern macro TaggedToNumber(Object): Number
|
extern macro TaggedToNumber(Object): Number
|
||||||
labels CastError;
|
labels CastError;
|
||||||
|
|
||||||
@ -459,6 +477,10 @@ CastHeapObject<FixedDoubleArray>(o: HeapObject): FixedDoubleArray
|
|||||||
labels CastError {
|
labels CastError {
|
||||||
return HeapObjectToFixedDoubleArray(o) otherwise CastError;
|
return HeapObjectToFixedDoubleArray(o) otherwise CastError;
|
||||||
}
|
}
|
||||||
|
CastHeapObject<SloppyArgumentsElements>(o: HeapObject): SloppyArgumentsElements
|
||||||
|
labels CastError {
|
||||||
|
return HeapObjectToSloppyArgumentsElements(o) otherwise CastError;
|
||||||
|
}
|
||||||
CastHeapObject<JSDataView>(o: HeapObject): JSDataView
|
CastHeapObject<JSDataView>(o: HeapObject): JSDataView
|
||||||
labels CastError {
|
labels CastError {
|
||||||
return HeapObjectToJSDataView(o) otherwise CastError;
|
return HeapObjectToJSDataView(o) otherwise CastError;
|
||||||
@ -766,17 +788,18 @@ UnsafeCast<String>(o: Object): String {
|
|||||||
// type check().
|
// type check().
|
||||||
extern macro RawCastObjectToJSArgumentsObjectWithLength(Object):
|
extern macro RawCastObjectToJSArgumentsObjectWithLength(Object):
|
||||||
JSArgumentsObjectWithLength;
|
JSArgumentsObjectWithLength;
|
||||||
|
extern macro RawCastObjectToFastJSArray(Object): FastJSArray;
|
||||||
|
extern macro RawCastObjectToFastJSArrayForCopy(Object): FastJSArrayForCopy;
|
||||||
|
|
||||||
macro BranchIfJSArgumentsObjectWithLength(implicit context: Context)(o: Object):
|
macro BranchIfJSArgumentsObjectWithLength(implicit context: Context)(o: Object):
|
||||||
never
|
never
|
||||||
labels True, False {
|
labels True, False {
|
||||||
const heapObject: HeapObject = Cast<HeapObject>(o) otherwise False;
|
const heapObject: HeapObject = Cast<HeapObject>(o) otherwise False;
|
||||||
const map: Map = heapObject.map;
|
const map: Map = heapObject.map;
|
||||||
const nativeContext: NativeContext = LoadNativeContext(context);
|
if (IsFastAliasedArgumentsMap(map)) goto True;
|
||||||
if (map == nativeContext[FAST_ALIASED_ARGUMENTS_MAP_INDEX]) goto True;
|
if (IsSloppyArgumentsMap(map)) goto True;
|
||||||
if (map == nativeContext[SLOW_ALIASED_ARGUMENTS_MAP_INDEX]) goto True;
|
if (IsStrictArgumentsMap(map)) goto True;
|
||||||
if (map == nativeContext[STRICT_ARGUMENTS_MAP_INDEX]) goto True;
|
if (!IsSlowAliasedArgumentsMap(map)) goto False;
|
||||||
if (map != nativeContext[SLOPPY_ARGUMENTS_MAP_INDEX]) goto False;
|
|
||||||
goto True;
|
goto True;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,17 +820,59 @@ Cast<JSArgumentsObjectWithLength>(implicit context: Context)(o: Object):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UnsafeCast<FastJSArray>(implicit context: Context)(o: Object): FastJSArray {
|
||||||
|
assert(BranchIfFastJSArrayForCopy(o, context));
|
||||||
|
return RawCastObjectToFastJSArray(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cast<FastJSArray>(implicit context: Context)(o: Object): FastJSArray
|
||||||
|
labels CastError {
|
||||||
|
if (BranchIfFastJSArray(o, context)) {
|
||||||
|
return UnsafeCast<FastJSArray>(o);
|
||||||
|
} else {
|
||||||
|
goto CastError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Cast<FastJSArray>(implicit context: Context)(ho: HeapObject): FastJSArray
|
||||||
|
labels CastError {
|
||||||
|
if (BranchIfFastJSArray(ho, context)) {
|
||||||
|
return UnsafeCast<FastJSArray>(ho);
|
||||||
|
} else {
|
||||||
|
goto CastError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UnsafeCast<FastJSArrayForCopy>(implicit context: Context)(o: Object):
|
||||||
|
FastJSArrayForCopy {
|
||||||
|
assert(BranchIfFastJSArrayForCopy(o, context));
|
||||||
|
return RawCastObjectToFastJSArrayForCopy(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
Cast<FastJSArrayForCopy>(implicit context: Context)(o: Object):
|
||||||
|
FastJSArrayForCopy
|
||||||
|
labels CastError {
|
||||||
|
if (BranchIfFastJSArrayForCopy(o, context)) {
|
||||||
|
return UnsafeCast<FastJSArrayForCopy>(o);
|
||||||
|
} else {
|
||||||
|
goto CastError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const kCOWMap: Map = UnsafeCast<Map>(LoadRoot(kFixedCOWArrayMapRootIndex));
|
const kCOWMap: Map = UnsafeCast<Map>(LoadRoot(kFixedCOWArrayMapRootIndex));
|
||||||
const kEmptyFixedArray: FixedArrayBase =
|
const kEmptyFixedArray: FixedArrayBase =
|
||||||
UnsafeCast<FixedArrayBase>(LoadRoot(kEmptyFixedArrayRootIndex));
|
UnsafeCast<FixedArrayBase>(LoadRoot(kEmptyFixedArrayRootIndex));
|
||||||
|
|
||||||
extern macro BranchIfFastJSArray(Object, Context): never
|
extern macro BranchIfFastJSArray(Object, Context): never
|
||||||
labels Taken, NotTaken;
|
labels Taken, NotTaken;
|
||||||
|
extern macro BranchIfFastJSArrayForCopy(Object, Context): never
|
||||||
|
labels Taken, NotTaken;
|
||||||
extern macro BranchIfNotFastJSArray(Object, Context): never
|
extern macro BranchIfNotFastJSArray(Object, Context): never
|
||||||
labels Taken, NotTaken;
|
labels Taken, NotTaken;
|
||||||
|
macro BranchIfNotFastJSArrayForCopy(implicit context: Context)(o: Object):
|
||||||
macro EnsureFastJSArray(context: Context, object: Object) labels Bailout {
|
never
|
||||||
if (BranchIfNotFastJSArray(object, context)) goto Bailout;
|
labels Taken, NotTaken {
|
||||||
|
BranchIfFastJSArrayForCopy(o, context) otherwise NotTaken, Taken;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern macro IsPrototypeInitialArrayPrototype(Context, Map): bool;
|
extern macro IsPrototypeInitialArrayPrototype(Context, Map): bool;
|
||||||
@ -832,7 +897,7 @@ extern operator '.length' macro LoadJSTypedArrayLength(JSTypedArray): Smi;
|
|||||||
extern operator '.length' macro LoadJSArrayLength(JSArray): Number;
|
extern operator '.length' macro LoadJSArrayLength(JSArray): Number;
|
||||||
extern operator '.length' macro LoadJSArgumentsObjectWithLength(
|
extern operator '.length' macro LoadJSArgumentsObjectWithLength(
|
||||||
JSArgumentsObjectWithLength): Object;
|
JSArgumentsObjectWithLength): Object;
|
||||||
extern operator '.length_fast' macro LoadFastJSArrayLength(JSArray): Smi;
|
extern operator '.length' macro LoadFastJSArrayLength(FastJSArray): Smi;
|
||||||
extern operator '.length=' macro StoreJSArrayLength(JSArray, Smi);
|
extern operator '.length=' macro StoreJSArrayLength(JSArray, Smi);
|
||||||
|
|
||||||
extern operator '.length' macro LoadFixedArrayBaseLength(FixedArrayBase): Smi;
|
extern operator '.length' macro LoadFixedArrayBaseLength(FixedArrayBase): Smi;
|
||||||
@ -944,6 +1009,7 @@ extern macro Call(
|
|||||||
extern macro Call(
|
extern macro Call(
|
||||||
Context, Callable, Object, Object, Object, Object, Object, Object): Object;
|
Context, Callable, Object, Object, Object, Object, Object, Object): Object;
|
||||||
|
|
||||||
|
extern builtin CloneFastJSArray(Context, FastJSArrayForCopy): JSArray;
|
||||||
extern macro ExtractFixedArray(FixedArrayBase, Smi, Smi, Smi): FixedArrayBase;
|
extern macro ExtractFixedArray(FixedArrayBase, Smi, Smi, Smi): FixedArrayBase;
|
||||||
extern macro ExtractFixedArray(
|
extern macro ExtractFixedArray(
|
||||||
FixedArrayBase, Smi, Smi, Smi,
|
FixedArrayBase, Smi, Smi, Smi,
|
||||||
@ -1080,8 +1146,7 @@ macro GetLengthProperty(implicit context: Context)(o: Object): Number {
|
|||||||
return a.length;
|
return a.length;
|
||||||
}
|
}
|
||||||
case (a: JSArgumentsObjectWithLength): {
|
case (a: JSArgumentsObjectWithLength): {
|
||||||
const length: Object = a.length;
|
goto ToLength(a.length);
|
||||||
return Cast<Smi>(length) otherwise goto ToLength(length);
|
|
||||||
}
|
}
|
||||||
case (Object): deferred {
|
case (Object): deferred {
|
||||||
goto ToLength(GetProperty(o, kLengthString));
|
goto ToLength(GetProperty(o, kLengthString));
|
||||||
|
@ -4674,7 +4674,8 @@ void CodeStubAssembler::CopyElements(ElementsKind kind,
|
|||||||
CSA_ASSERT(this, IntPtrLessThanOrEqual(
|
CSA_ASSERT(this, IntPtrLessThanOrEqual(
|
||||||
IntPtrAdd(src_index, length),
|
IntPtrAdd(src_index, length),
|
||||||
LoadAndUntagFixedArrayBaseLength(src_elements)));
|
LoadAndUntagFixedArrayBaseLength(src_elements)));
|
||||||
CSA_ASSERT(this, WordNotEqual(dst_elements, src_elements));
|
CSA_ASSERT(this, Word32Or(WordNotEqual(dst_elements, src_elements),
|
||||||
|
WordEqual(length, IntPtrConstant(0))));
|
||||||
|
|
||||||
// The write barrier can be ignored if {dst_elements} is in new space, or if
|
// The write barrier can be ignored if {dst_elements} is in new space, or if
|
||||||
// the elements pointer is FixedDoubleArray.
|
// the elements pointer is FixedDoubleArray.
|
||||||
@ -5831,6 +5832,38 @@ TNode<BoolT> CodeStubAssembler::IsPrototypeTypedArrayPrototype(
|
|||||||
return WordEqual(proto_of_proto, typed_array_prototype);
|
return WordEqual(proto_of_proto, typed_array_prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<BoolT> CodeStubAssembler::IsFastAliasedArgumentsMap(
|
||||||
|
TNode<Context> context, TNode<Map> map) {
|
||||||
|
TNode<Context> const native_context = LoadNativeContext(context);
|
||||||
|
TNode<Object> const arguments_map = LoadContextElement(
|
||||||
|
native_context, Context::FAST_ALIASED_ARGUMENTS_MAP_INDEX);
|
||||||
|
return WordEqual(arguments_map, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<BoolT> CodeStubAssembler::IsSlowAliasedArgumentsMap(
|
||||||
|
TNode<Context> context, TNode<Map> map) {
|
||||||
|
TNode<Context> const native_context = LoadNativeContext(context);
|
||||||
|
TNode<Object> const arguments_map = LoadContextElement(
|
||||||
|
native_context, Context::SLOW_ALIASED_ARGUMENTS_MAP_INDEX);
|
||||||
|
return WordEqual(arguments_map, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<BoolT> CodeStubAssembler::IsSloppyArgumentsMap(TNode<Context> context,
|
||||||
|
TNode<Map> map) {
|
||||||
|
TNode<Context> const native_context = LoadNativeContext(context);
|
||||||
|
TNode<Object> const arguments_map =
|
||||||
|
LoadContextElement(native_context, Context::SLOPPY_ARGUMENTS_MAP_INDEX);
|
||||||
|
return WordEqual(arguments_map, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<BoolT> CodeStubAssembler::IsStrictArgumentsMap(TNode<Context> context,
|
||||||
|
TNode<Map> map) {
|
||||||
|
TNode<Context> const native_context = LoadNativeContext(context);
|
||||||
|
TNode<Object> const arguments_map =
|
||||||
|
LoadContextElement(native_context, Context::STRICT_ARGUMENTS_MAP_INDEX);
|
||||||
|
return WordEqual(arguments_map, map);
|
||||||
|
}
|
||||||
|
|
||||||
TNode<BoolT> CodeStubAssembler::TaggedIsCallable(TNode<Object> object) {
|
TNode<BoolT> CodeStubAssembler::TaggedIsCallable(TNode<Object> object) {
|
||||||
return Select<BoolT>(
|
return Select<BoolT>(
|
||||||
TaggedIsSmi(object), [=] { return Int32FalseConstant(); },
|
TaggedIsSmi(object), [=] { return Int32FalseConstant(); },
|
||||||
|
@ -423,6 +423,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
return TNode<JSArgumentsObjectWithLength>::UncheckedCast(p_o);
|
return TNode<JSArgumentsObjectWithLength>::UncheckedCast(p_o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<JSArray> RawCastObjectToFastJSArray(TNode<Object> p_o) {
|
||||||
|
return TNode<JSArray>::UncheckedCast(p_o);
|
||||||
|
}
|
||||||
|
|
||||||
|
TNode<JSArray> RawCastObjectToFastJSArrayForCopy(TNode<Object> p_o) {
|
||||||
|
return TNode<JSArray>::UncheckedCast(p_o);
|
||||||
|
}
|
||||||
|
|
||||||
Node* MatchesParameterMode(Node* value, ParameterMode mode);
|
Node* MatchesParameterMode(Node* value, ParameterMode mode);
|
||||||
|
|
||||||
#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
|
#define PARAMETER_BINOP(OpName, IntPtrOpName, SmiOpName) \
|
||||||
@ -1639,6 +1647,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
return UncheckedCast<FixedDoubleArray>(base);
|
return UncheckedCast<FixedDoubleArray>(base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TNode<FixedArray> HeapObjectToSloppyArgumentsElements(TNode<HeapObject> base,
|
||||||
|
Label* cast_fail) {
|
||||||
|
GotoIf(WordNotEqual(LoadMap(base),
|
||||||
|
LoadRoot(RootIndex::kSloppyArgumentsElementsMap)),
|
||||||
|
cast_fail);
|
||||||
|
return UncheckedCast<FixedArray>(base);
|
||||||
|
}
|
||||||
|
|
||||||
TNode<Int32T> ConvertElementsKindToInt(TNode<Int32T> elements_kind) {
|
TNode<Int32T> ConvertElementsKindToInt(TNode<Int32T> elements_kind) {
|
||||||
return UncheckedCast<Int32T>(elements_kind);
|
return UncheckedCast<Int32T>(elements_kind);
|
||||||
}
|
}
|
||||||
@ -2008,6 +2024,14 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
|||||||
SloppyTNode<Map> map);
|
SloppyTNode<Map> map);
|
||||||
TNode<BoolT> IsPrototypeTypedArrayPrototype(SloppyTNode<Context> context,
|
TNode<BoolT> IsPrototypeTypedArrayPrototype(SloppyTNode<Context> context,
|
||||||
SloppyTNode<Map> map);
|
SloppyTNode<Map> map);
|
||||||
|
|
||||||
|
TNode<BoolT> IsFastAliasedArgumentsMap(TNode<Context> context,
|
||||||
|
TNode<Map> map);
|
||||||
|
TNode<BoolT> IsSlowAliasedArgumentsMap(TNode<Context> context,
|
||||||
|
TNode<Map> map);
|
||||||
|
TNode<BoolT> IsSloppyArgumentsMap(TNode<Context> context, TNode<Map> map);
|
||||||
|
TNode<BoolT> IsStrictArgumentsMap(TNode<Context> context, TNode<Map> map);
|
||||||
|
|
||||||
TNode<BoolT> IsSequentialStringInstanceType(
|
TNode<BoolT> IsSequentialStringInstanceType(
|
||||||
SloppyTNode<Int32T> instance_type);
|
SloppyTNode<Int32T> instance_type);
|
||||||
TNode<BoolT> IsUncachedExternalStringInstanceType(
|
TNode<BoolT> IsUncachedExternalStringInstanceType(
|
||||||
|
@ -3439,6 +3439,7 @@ Reduction JSCallReducer::ReduceJSCall(Node* node,
|
|||||||
case Builtins::kArrayPrototypeShift:
|
case Builtins::kArrayPrototypeShift:
|
||||||
return ReduceArrayPrototypeShift(node);
|
return ReduceArrayPrototypeShift(node);
|
||||||
case Builtins::kArrayPrototypeSlice:
|
case Builtins::kArrayPrototypeSlice:
|
||||||
|
case Builtins::kArraySlice:
|
||||||
return ReduceArrayPrototypeSlice(node);
|
return ReduceArrayPrototypeSlice(node);
|
||||||
case Builtins::kArrayPrototypeEntries:
|
case Builtins::kArrayPrototypeEntries:
|
||||||
return ReduceArrayIterator(node, IterationKind::kEntries);
|
return ReduceArrayIterator(node, IterationKind::kEntries);
|
||||||
|
@ -384,6 +384,8 @@ bool BuiltinToIntrinsicHasNoSideEffect(Builtins::Name builtin_id,
|
|||||||
/* Arrays */ \
|
/* Arrays */ \
|
||||||
V(Builtins::kArrayFilter, W(CreateDataProperty)) \
|
V(Builtins::kArrayFilter, W(CreateDataProperty)) \
|
||||||
V(Builtins::kArrayMap, W(CreateDataProperty)) \
|
V(Builtins::kArrayMap, W(CreateDataProperty)) \
|
||||||
|
V(Builtins::kArraySlice, \
|
||||||
|
W(CreateDataProperty) W(SetKeyedProperty) W(SetNamedProperty)) \
|
||||||
V(Builtins::kArrayPrototypeSlice, \
|
V(Builtins::kArrayPrototypeSlice, \
|
||||||
W(CreateDataProperty) W(SetKeyedProperty) W(SetNamedProperty)) \
|
W(CreateDataProperty) W(SetKeyedProperty) W(SetNamedProperty)) \
|
||||||
/* TypedArrays */ \
|
/* TypedArrays */ \
|
||||||
@ -556,6 +558,7 @@ DebugInfo::SideEffectState BuiltinGetSideEffectState(Builtins::Name id) {
|
|||||||
case Builtins::kArrayPrototypeKeys:
|
case Builtins::kArrayPrototypeKeys:
|
||||||
case Builtins::kArrayPrototypeLastIndexOf:
|
case Builtins::kArrayPrototypeLastIndexOf:
|
||||||
case Builtins::kArrayPrototypeSlice:
|
case Builtins::kArrayPrototypeSlice:
|
||||||
|
case Builtins::kArraySlice:
|
||||||
case Builtins::kArrayPrototypeSort:
|
case Builtins::kArrayPrototypeSort:
|
||||||
case Builtins::kArrayPrototypeToLocaleString:
|
case Builtins::kArrayPrototypeToLocaleString:
|
||||||
case Builtins::kArrayPrototypeToString:
|
case Builtins::kArrayPrototypeToString:
|
||||||
|
@ -228,8 +228,25 @@ void DeclarationVisitor::Visit(SpecializationDeclaration* decl) {
|
|||||||
|
|
||||||
if (matching_callable == nullptr) {
|
if (matching_callable == nullptr) {
|
||||||
std::stringstream stream;
|
std::stringstream stream;
|
||||||
|
if (generic_list->list().size() == 0) {
|
||||||
|
stream << "no generic defined with the name " << decl->name;
|
||||||
|
ReportError(stream.str());
|
||||||
|
}
|
||||||
stream << "specialization of " << decl->name
|
stream << "specialization of " << decl->name
|
||||||
<< " doesn't match any generic declaration";
|
<< " doesn't match any generic declaration\n";
|
||||||
|
stream << "specialization signature:";
|
||||||
|
stream << "\n " << signature_with_types;
|
||||||
|
stream << "\ncandidates are:";
|
||||||
|
for (Generic* generic : generic_list->list()) {
|
||||||
|
SpecializationKey key = {generic,
|
||||||
|
GetTypeVector(decl->generic_parameters)};
|
||||||
|
Declarations::CleanNodeScopeActivator specialization_activator(
|
||||||
|
declarations(), decl);
|
||||||
|
DeclareSpecializedTypes(key);
|
||||||
|
Signature generic_signature_with_types =
|
||||||
|
MakeSignature(generic->declaration()->callable->signature.get());
|
||||||
|
stream << "\n " << generic_signature_with_types;
|
||||||
|
}
|
||||||
ReportError(stream.str());
|
ReportError(stream.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,15 +112,19 @@ function array_natives_test() {
|
|||||||
assertEquals([2], a2.slice(1,2));
|
assertEquals([2], a2.slice(1,2));
|
||||||
a2 = [1.1,2,3];
|
a2 = [1.1,2,3];
|
||||||
assertTrue(%HasDoubleElements(a2.slice()));
|
assertTrue(%HasDoubleElements(a2.slice()));
|
||||||
assertTrue(%HasDoubleElements(a2.slice(1)));
|
assertTrue(%HasDoubleElements(a2.slice(1)) ||
|
||||||
assertTrue(%HasDoubleElements(a2.slice(1, 2)));
|
%HasSmiElements(a2.slice(1)));
|
||||||
|
assertTrue(%HasDoubleElements(a2.slice(1, 2)) ||
|
||||||
|
%HasSmiElements(a2.slice(1, 2)));
|
||||||
assertEquals([1.1,2,3], a2.slice());
|
assertEquals([1.1,2,3], a2.slice());
|
||||||
assertEquals([2,3], a2.slice(1));
|
assertEquals([2,3], a2.slice(1));
|
||||||
assertEquals([2], a2.slice(1,2));
|
assertEquals([2], a2.slice(1,2));
|
||||||
a2 = [{},2,3];
|
a2 = [{},2,3];
|
||||||
assertTrue(%HasObjectElements(a2.slice()));
|
assertTrue(%HasObjectElements(a2.slice()));
|
||||||
assertTrue(%HasObjectElements(a2.slice(1)));
|
assertTrue(%HasObjectElements(a2.slice(1)) ||
|
||||||
assertTrue(%HasObjectElements(a2.slice(1, 2)));
|
%HasSmiElements(a2.slice(1)));
|
||||||
|
assertTrue(%HasObjectElements(a2.slice(1, 2)) ||
|
||||||
|
%HasSmiElements(a2.slice(1, 2)));
|
||||||
assertEquals([{},2,3], a2.slice());
|
assertEquals([{},2,3], a2.slice());
|
||||||
assertEquals([2,3], a2.slice(1));
|
assertEquals([2,3], a2.slice(1));
|
||||||
assertEquals([2], a2.slice(1,2));
|
assertEquals([2], a2.slice(1,2));
|
||||||
|
@ -2,6 +2,22 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
function f() {
|
||||||
|
arguments.length = -5;
|
||||||
|
Array.prototype.slice.call(arguments);
|
||||||
|
}
|
||||||
|
f('a')
|
||||||
|
})();
|
||||||
|
|
||||||
|
(function () {
|
||||||
|
function f() {
|
||||||
|
arguments.length = 2.3;
|
||||||
|
Array.prototype.slice.call(arguments);
|
||||||
|
}
|
||||||
|
f('a')
|
||||||
|
})();
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
function f( __v_59960) {
|
function f( __v_59960) {
|
||||||
arguments.length = -5;
|
arguments.length = -5;
|
||||||
@ -13,7 +29,6 @@
|
|||||||
(function () {
|
(function () {
|
||||||
function f( __v_59960) {
|
function f( __v_59960) {
|
||||||
arguments.length = 2.3;
|
arguments.length = 2.3;
|
||||||
print(arguments.length);
|
|
||||||
Array.prototype.slice.call(arguments);
|
Array.prototype.slice.call(arguments);
|
||||||
}
|
}
|
||||||
f('a')
|
f('a')
|
||||||
|
21
third_party/v8/builtins/array-sort.tq
vendored
21
third_party/v8/builtins/array-sort.tq
vendored
@ -325,14 +325,12 @@ module array {
|
|||||||
builtin CanUseSameAccessor<ElementsAccessor: type>(
|
builtin CanUseSameAccessor<ElementsAccessor: type>(
|
||||||
context: Context, receiver: JSReceiver, initialReceiverMap: Object,
|
context: Context, receiver: JSReceiver, initialReceiverMap: Object,
|
||||||
initialReceiverLength: Number): Boolean {
|
initialReceiverLength: Number): Boolean {
|
||||||
assert(IsJSArray(receiver));
|
const a: JSArray = Cast<JSArray>(receiver) otherwise unreachable;
|
||||||
|
|
||||||
let a: JSArray = UnsafeCast<JSArray>(receiver);
|
|
||||||
if (a.map != initialReceiverMap) return False;
|
if (a.map != initialReceiverMap) return False;
|
||||||
|
|
||||||
assert(TaggedIsSmi(initialReceiverLength));
|
assert(TaggedIsSmi(initialReceiverLength));
|
||||||
let originalLength: Smi = UnsafeCast<Smi>(initialReceiverLength);
|
let originalLength: Smi = UnsafeCast<Smi>(initialReceiverLength);
|
||||||
if (a.length_fast != originalLength) return False;
|
if (a.length != originalLength) return False;
|
||||||
|
|
||||||
return True;
|
return True;
|
||||||
}
|
}
|
||||||
@ -547,13 +545,7 @@ module array {
|
|||||||
// Used for OOB asserts in Copy* builtins.
|
// Used for OOB asserts in Copy* builtins.
|
||||||
macro GetReceiverLengthProperty(
|
macro GetReceiverLengthProperty(
|
||||||
implicit context: Context)(sortState: FixedArray): Smi {
|
implicit context: Context)(sortState: FixedArray): Smi {
|
||||||
const receiver: JSReceiver = GetReceiver(sortState);
|
return Cast<Smi>(GetLengthProperty(GetReceiver(sortState))) otherwise unreachable;
|
||||||
|
|
||||||
if (IsJSArray(receiver)) return UnsafeCast<JSArray>(receiver).length_fast;
|
|
||||||
|
|
||||||
const len: Number =
|
|
||||||
ToLength_Inline(context, GetProperty(receiver, kLengthString));
|
|
||||||
return UnsafeCast<Smi>(len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro CopyToTempArray(
|
macro CopyToTempArray(
|
||||||
@ -1747,12 +1739,10 @@ module array {
|
|||||||
sortState[kBailoutStatusIdx] = kSuccess;
|
sortState[kBailoutStatusIdx] = kSuccess;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const a: JSArray = Cast<JSArray>(obj) otherwise Slow;
|
const a: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow;
|
||||||
const elementsKind: ElementsKind = map.elements_kind;
|
|
||||||
if (!IsFastElementsKind(elementsKind)) goto Slow;
|
|
||||||
|
|
||||||
// 3. Let len be ? ToLength(? Get(obj, "length")).
|
// 3. Let len be ? ToLength(? Get(obj, "length")).
|
||||||
const len: Smi = a.length_fast;
|
const len: Smi = a.length;
|
||||||
if (len < 2) return receiver;
|
if (len < 2) return receiver;
|
||||||
|
|
||||||
// TODO(szuend): Investigate performance tradeoff of skipping this step
|
// TODO(szuend): Investigate performance tradeoff of skipping this step
|
||||||
@ -1762,6 +1752,7 @@ module array {
|
|||||||
|
|
||||||
sortState[kInitialReceiverLengthIdx] = len;
|
sortState[kInitialReceiverLengthIdx] = len;
|
||||||
|
|
||||||
|
const elementsKind: ElementsKind = map.elements_kind;
|
||||||
if (IsDoubleElementsKind(elementsKind)) {
|
if (IsDoubleElementsKind(elementsKind)) {
|
||||||
InitializeSortStateAccessor<FastDoubleElements>(sortState);
|
InitializeSortStateAccessor<FastDoubleElements>(sortState);
|
||||||
} else if (elementsKind == PACKED_SMI_ELEMENTS) {
|
} else if (elementsKind == PACKED_SMI_ELEMENTS) {
|
||||||
|
@ -45,13 +45,13 @@ def postprocess(output):
|
|||||||
output = re.sub(r',([\n ]*)\/\*_LABELS_HOLD_\*\/', r'\1labels', output)
|
output = re.sub(r',([\n ]*)\/\*_LABELS_HOLD_\*\/', r'\1labels', output)
|
||||||
output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output)
|
output = re.sub(r'\/\*_OPE \'([^\']+)\'\*\/', r"operator '\1'", output)
|
||||||
output = re.sub(r'\/\*_TYPE\*\/(\s*)switch', r'typeswitch', output)
|
output = re.sub(r'\/\*_TYPE\*\/(\s*)switch', r'typeswitch', output)
|
||||||
output = re.sub(r'case ([^\:]+)\:\s*\/\*_TSXDEFERRED_\*\/',
|
output = re.sub(r'case (\w+)\:\s*\/\*_TSXDEFERRED_\*\/',
|
||||||
r'case (\1): deferred', output)
|
r'case (\1): deferred', output)
|
||||||
output = re.sub(r'case ([^\:]+)\:\s*\/\*_TSX\*\/',
|
output = re.sub(r'case (\w+)\:\s*\/\*_TSX\*\/',
|
||||||
r'case (\1):', output)
|
r'case (\1):', output)
|
||||||
output = re.sub(r'case ([^\:]+)\:\s*\/\*_TSVDEFERRED_([^\:]+)\:\*\/',
|
output = re.sub(r'case (\w+)\:\s*\/\*_TSVDEFERRED_([^\:]+)\:\*\/',
|
||||||
r'case (\2: \1): deferred', output)
|
r'case (\2: \1): deferred', output)
|
||||||
output = re.sub(r'case ([^\:]+)\:\s*\/\*_TSV([^\:]+)\:\*\/',
|
output = re.sub(r'case (\w+)\:\s*\/\*_TSV([^\:]+)\:\*\/',
|
||||||
r'case (\2: \1):', output)
|
r'case (\2: \1):', output)
|
||||||
output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
|
output = re.sub(r'\n_GeNeRaTeS00_\s*\/\*([^@]+)@\*\/',
|
||||||
r"\n generates '\1'", output)
|
r"\n generates '\1'", output)
|
||||||
|
Loading…
Reference in New Issue
Block a user