[array] Fix left-trimming in Array.p.sort
Whenever left-trimming is possible (e.g. whenever user code is called), we must not store a reference to an exposed JSArray's elements. Bug: chromium:897366,v8:7382 Change-Id: I8dd6a93aa6ed19e755ccce7122e0e019dc578a31 Reviewed-on: https://chromium-review.googlesource.com/c/1292066 Reviewed-by: Camillo Bruni <cbruni@chromium.org> Commit-Queue: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#56903}
This commit is contained in:
parent
66941872c0
commit
d31a5b6569
15
test/mjsunit/regress/regress-897366.js
Normal file
15
test/mjsunit/regress/regress-897366.js
Normal file
@ -0,0 +1,15 @@
|
||||
// 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.
|
||||
|
||||
// Flags: --gc-interval=100
|
||||
|
||||
let xs = [];
|
||||
for (let i = 0; i < 205; ++i) {
|
||||
xs.push(i);
|
||||
}
|
||||
xs.sort((a, b) => {
|
||||
xs.shift();
|
||||
xs[xs.length] = -246;
|
||||
return a - b;
|
||||
});
|
102
third_party/v8/builtins/array-sort.tq
vendored
102
third_party/v8/builtins/array-sort.tq
vendored
@ -543,9 +543,10 @@ module array {
|
||||
}
|
||||
|
||||
// Used for OOB asserts in Copy* builtins.
|
||||
macro GetReceiverLengthProperty(
|
||||
implicit context: Context)(sortState: FixedArray): Smi {
|
||||
return Cast<Smi>(GetLengthProperty(GetReceiver(sortState))) otherwise unreachable;
|
||||
macro GetReceiverLengthProperty(implicit context: Context)(
|
||||
sortState: FixedArray): Smi {
|
||||
return Cast<Smi>(GetLengthProperty(GetReceiver(sortState)))
|
||||
otherwise unreachable;
|
||||
}
|
||||
|
||||
macro CopyToTempArray(
|
||||
@ -814,7 +815,7 @@ module array {
|
||||
assert(i >= 0);
|
||||
assert(i == stackSize - 2 || i == stackSize - 3);
|
||||
|
||||
const elements: HeapObject = ReloadElements(sortState);
|
||||
let elements: HeapObject = ReloadElements(sortState);
|
||||
const load: LoadFn = GetLoadFn(sortState);
|
||||
|
||||
const pendingRuns: FixedArray =
|
||||
@ -847,6 +848,7 @@ module array {
|
||||
const k: Smi = CallGallopRight(
|
||||
context, sortState, load, keyRight, baseA, lengthA, 0, False)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(k >= 0);
|
||||
|
||||
baseA = baseA + k;
|
||||
@ -862,6 +864,7 @@ module array {
|
||||
lengthB = CallGallopLeft(
|
||||
context, sortState, load, keyLeft, baseB, lengthB, lengthB - 1, False)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(lengthB >= 0);
|
||||
if (lengthB == 0) return kSuccess;
|
||||
|
||||
@ -881,6 +884,12 @@ module array {
|
||||
}
|
||||
}
|
||||
|
||||
macro LoadElementsOrTempArray(
|
||||
useTempArray: Boolean, sortState: FixedArray): HeapObject {
|
||||
return useTempArray == True ? GetTempArray(sortState) :
|
||||
ReloadElements(sortState);
|
||||
}
|
||||
|
||||
// Locates the proper position of key in a sorted array; if the array contains
|
||||
// an element equal to key, return the position immediately to the left of
|
||||
// the leftmost equal element. (GallopRight does the same except returns the
|
||||
@ -904,25 +913,17 @@ module array {
|
||||
assert(length > 0 && base >= 0);
|
||||
assert(0 <= hint && hint < length);
|
||||
|
||||
// We cannot leave a pointer to elements on the stack (see comment at
|
||||
// ReloadElements). For this reason we pass a flag whether to reload
|
||||
// and which array to use.
|
||||
let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) :
|
||||
ReloadElements(sortState);
|
||||
|
||||
let lastOfs: Smi = 0;
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint)
|
||||
const baseHintElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, baseHintElement, key)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order < 0) {
|
||||
// a[base + hint] < key: gallop right, until
|
||||
@ -931,14 +932,13 @@ module array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint + offset)
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
// a[base + hint + offset] >= key? Break.
|
||||
if (order >= 0) break;
|
||||
@ -963,14 +963,13 @@ module array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint - offset)
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, offsetElement, key)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order < 0) break;
|
||||
|
||||
@ -999,14 +998,12 @@ module array {
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >>> 1);
|
||||
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + m)
|
||||
const baseMElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, baseMElement, key)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order < 0) {
|
||||
lastOfs = m + 1; // a[base + m] < key.
|
||||
@ -1039,25 +1036,17 @@ module array {
|
||||
assert(length > 0 && base >= 0);
|
||||
assert(0 <= hint && hint < length);
|
||||
|
||||
// We cannot leave a pointer to elements on the stack (see comment at
|
||||
// ReloadElements). For this reason we pass a flag whether to reload
|
||||
// and which array to use.
|
||||
let elements: HeapObject = useTempArray == True ? GetTempArray(sortState) :
|
||||
ReloadElements(sortState);
|
||||
|
||||
let lastOfs: Smi = 0;
|
||||
let offset: Smi = 1;
|
||||
|
||||
try {
|
||||
const baseHintElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint)
|
||||
const baseHintElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + hint)
|
||||
otherwise Bailout;
|
||||
let order: Number =
|
||||
CallCompareFn(context, sortState, key, baseHintElement)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order < 0) {
|
||||
// key < a[base + hint]: gallop left, until
|
||||
@ -1066,14 +1055,13 @@ module array {
|
||||
// a[base + hint] is lowest.
|
||||
let maxOfs: Smi = hint + 1;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint - offset)
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint - offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order >= 0) break;
|
||||
|
||||
@ -1097,14 +1085,13 @@ module array {
|
||||
// a[base + length - 1] is highest.
|
||||
let maxOfs: Smi = length - hint;
|
||||
while (offset < maxOfs) {
|
||||
const offsetElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + hint + offset)
|
||||
const offsetElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState),
|
||||
base + hint + offset)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, offsetElement)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
// a[base + hint + ofs] <= key.
|
||||
if (order < 0) break;
|
||||
@ -1132,14 +1119,12 @@ module array {
|
||||
while (lastOfs < offset) {
|
||||
const m: Smi = lastOfs + ((offset - lastOfs) >>> 1);
|
||||
|
||||
const baseMElement: Object =
|
||||
CallLoad(context, sortState, load, elements, base + m)
|
||||
const baseMElement: Object = CallLoad(
|
||||
context, sortState, load,
|
||||
LoadElementsOrTempArray(useTempArray, sortState), base + m)
|
||||
otherwise Bailout;
|
||||
order = CallCompareFn(context, sortState, key, baseMElement)
|
||||
otherwise Bailout;
|
||||
if (useTempArray == False) {
|
||||
elements = ReloadElements(sortState);
|
||||
}
|
||||
|
||||
if (order < 0) {
|
||||
offset = m; // key < a[base + m].
|
||||
@ -1276,6 +1261,7 @@ module array {
|
||||
nofWinsA = CallGallopRight(
|
||||
context, sortState, Load<TempArrayElements>, keyRight, cursorTemp,
|
||||
lengthA, 0, True) otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(nofWinsA >= 0);
|
||||
|
||||
if (nofWinsA > 0) {
|
||||
@ -1301,6 +1287,7 @@ module array {
|
||||
context, sortState, load, tempArray[cursorTemp], cursorB, lengthB,
|
||||
0, False)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(nofWinsB >= 0);
|
||||
if (nofWinsB > 0) {
|
||||
CallCopyWithinSortArray(
|
||||
@ -1449,6 +1436,7 @@ module array {
|
||||
context, sortState, load, tempArray[cursorTemp], baseA, lengthA,
|
||||
lengthA - 1, False)
|
||||
otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(k >= 0);
|
||||
nofWinsA = lengthA - k;
|
||||
|
||||
@ -1474,6 +1462,7 @@ module array {
|
||||
k = CallGallopLeft(
|
||||
context, sortState, Load<TempArrayElements>, key, 0, lengthB,
|
||||
lengthB - 1, True) otherwise Bailout;
|
||||
elements = ReloadElements(sortState);
|
||||
assert(k >= 0);
|
||||
nofWinsB = lengthB - k;
|
||||
|
||||
@ -1787,3 +1776,4 @@ module array {
|
||||
return receiver;
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user