Commit 2f382887 authored by peterwmwong's avatar peterwmwong Committed by Commit Bot

[builtins] Cap and grow Array.p.join's internal buffer.

This allows very large arrays being joined to incrementally,
on-demand allocate the internal buffer. Previously, join
would allocate the buffer upfront and all at once. Large,
sparse arrays will use less memory.

Bug: chromium:897404
Change-Id: Id914b14a7c55a62834f63ad602bdb45363249075
Reviewed-on: https://chromium-review.googlesource.com/c/1303538
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57075}
parent d0e0bf21
...@@ -109,6 +109,27 @@ module array { ...@@ -109,6 +109,27 @@ module array {
} }
} }
// Stores an element to a fixed array and return the fixed array. If the fixed
// array is not large enough, create and return a new, larger fixed array that
// contains all previously elements and the new element.
macro StoreAndGrowFixedArray<T: type>(
fixedArray: FixedArray, index: intptr, element: T): FixedArray {
const length: intptr = fixedArray.length_intptr;
assert(index <= length);
if (index < length) {
fixedArray[index] = element;
return fixedArray;
} else
deferred {
const newLength: intptr = CalculateNewElementsCapacity(length);
assert(index < newLength);
const newfixedArray: FixedArray =
ExtractFixedArray(fixedArray, 0, length, newLength, kFixedArrays);
newfixedArray[index] = element;
return newfixedArray;
}
}
// Contains the information necessary to create a single, separator delimited, // Contains the information necessary to create a single, separator delimited,
// flattened one or two byte string. // flattened one or two byte string.
// The buffer is maintained and updated by BufferInit(), BufferAdd(), // The buffer is maintained and updated by BufferInit(), BufferAdd(),
...@@ -143,8 +164,8 @@ module array { ...@@ -143,8 +164,8 @@ module array {
} }
macro BufferInit(len: uintptr, sep: String): Buffer { macro BufferInit(len: uintptr, sep: String): Buffer {
const cappedBufferSize: intptr = len > kFixedArrayMaxLength ? const cappedBufferSize: intptr = len > kMaxNewSpaceFixedArrayElements ?
FromConstexpr<intptr>(kFixedArrayMaxLength) : kMaxNewSpaceFixedArrayElements :
Signed(len); Signed(len);
assert(cappedBufferSize > 0); assert(cappedBufferSize > 0);
const fixedArray: FixedArray = AllocateZeroedFixedArray(cappedBufferSize); const fixedArray: FixedArray = AllocateZeroedFixedArray(cappedBufferSize);
...@@ -164,11 +185,11 @@ module array { ...@@ -164,11 +185,11 @@ module array {
const totalStringLength: intptr = const totalStringLength: intptr =
AddStringLength(buffer.totalStringLength, str.length); AddStringLength(buffer.totalStringLength, str.length);
let index: intptr = buffer.index; let index: intptr = buffer.index;
assert(index < buffer.fixedArray.length_intptr); const fixedArray: FixedArray =
buffer.fixedArray[index++] = str; StoreAndGrowFixedArray<String>(buffer.fixedArray, index++, str);
const isOneByte: bool = const isOneByte: bool =
HasOnlyOneByteChars(str.instanceType) & buffer.isOneByte; HasOnlyOneByteChars(str.instanceType) & buffer.isOneByte;
return Buffer{buffer.fixedArray, index, totalStringLength, isOneByte}; return Buffer{fixedArray, index, totalStringLength, isOneByte};
} }
macro BufferAddSeparators(implicit context: Context)( macro BufferAddSeparators(implicit context: Context)(
...@@ -187,16 +208,12 @@ module array { ...@@ -187,16 +208,12 @@ module array {
const totalStringLength: intptr = const totalStringLength: intptr =
AddStringLength(buffer.totalStringLength, sepsLen); AddStringLength(buffer.totalStringLength, sepsLen);
let index: intptr = buffer.index; let index: intptr = buffer.index;
let fixedArray: FixedArray = buffer.fixedArray;
if (write) deferred { if (write) deferred {
assert(index < buffer.fixedArray.length_intptr); fixedArray = StoreAndGrowFixedArray<Smi>(
buffer.fixedArray[index++] = Convert<Smi>(nofSeparatorsInt); buffer.fixedArray, index++, Convert<Smi>(nofSeparatorsInt));
} }
return Buffer{ return Buffer{fixedArray, index, totalStringLength, buffer.isOneByte};
buffer.fixedArray,
index,
totalStringLength,
buffer.isOneByte
};
} }
macro BufferJoin(implicit context: Context)( macro BufferJoin(implicit context: Context)(
...@@ -381,10 +398,8 @@ module array { ...@@ -381,10 +398,8 @@ module array {
} }
// If no open slots were found, grow the stack and add receiver to the end. // If no open slots were found, grow the stack and add receiver to the end.
const newCapacity: intptr = CalculateNewElementsCapacity(capacity);
const newStack: FixedArray = const newStack: FixedArray =
ExtractFixedArray(stack, 0, capacity, newCapacity, kFixedArrays); StoreAndGrowFixedArray<JSReceiver>(stack, capacity, receiver);
newStack[capacity] = receiver;
SetJoinStack(newStack); SetJoinStack(newStack);
return True; return True;
} }
...@@ -460,8 +475,8 @@ module array { ...@@ -460,8 +475,8 @@ module array {
const len: Number = GetLengthProperty(o); const len: Number = GetLengthProperty(o);
// 3. If separator is undefined, let sep be the single-element String ",". // 3. If separator is undefined, let sep be the single-element String ",".
// 4. Else, let sep be ? ToString(separator). // 4. Else, let sep be ? ToString(separator).
let sep: String = sepObj == Undefined ? FromConstexpr<String>(',') : let sep: String =
ToString_Inline(context, sepObj); sepObj == Undefined ? ',' : ToString_Inline(context, sepObj);
try { try {
// Fast paths for zero elements // Fast paths for zero elements
if (len == 0) goto IfReturnEmpty; if (len == 0) goto IfReturnEmpty;
......
// 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.
function TestError() {}
const a = new Array(2**32 - 1);
// Force early exit to avoid an unreasonably long test.
a[0] = {
toString() { throw new TestError(); }
};
// Verify join throws test error and does not fail due to asserts (Negative
// length fixed array allocation).
assertThrows(() => a.join(), TestError);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment