Commit 6ff3b370 authored by Igor Sheludko's avatar Igor Sheludko Committed by Commit Bot

[builtins] Allow 2Gb TypedArrays on 64-bit architectures

... even with ptr-compr.

Although full uintptr-sized TypedArrays are not supported yet
we may already start using uint32-sized typed arrays as we no
longer rely on TypedArray length to be a Smi.

Bug: v8:4153
Change-Id: If179541ad4f02c4ec7de9d1f3836138fe526d8a5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1905847
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/master@{#64897}
parent 1a1a9cca
......@@ -5226,7 +5226,9 @@ class V8_EXPORT TypedArray : public ArrayBufferView {
/*
* The largest typed array size that can be constructed using New.
*/
static constexpr size_t kMaxLength = internal::kSmiMaxValue;
static constexpr size_t kMaxLength = internal::kApiSystemPointerSize == 4
? internal::kSmiMaxValue
: 0x7FFFFFFF; // kMaxInt32
/**
* Number of elements in this typed array
......
......@@ -7633,8 +7633,9 @@ size_t v8::TypedArray::Length() {
return obj->WasDetached() ? 0 : obj->length();
}
static_assert(v8::TypedArray::kMaxLength == i::Smi::kMaxValue,
"v8::TypedArray::kMaxLength must match i::Smi::kMaxValue");
static_assert(
v8::TypedArray::kMaxLength == i::JSTypedArray::kMaxLength,
"v8::TypedArray::kMaxLength must match i::JSTypedArray::kMaxLength");
#define TYPED_ARRAY_NEW(Type, type, TYPE, ctype) \
Local<Type##Array> Type##Array::New(Local<ArrayBuffer> array_buffer, \
......
......@@ -315,6 +315,8 @@ const kMaxArrayIndex:
constexpr uint32 generates 'JSArray::kMaxArrayIndex';
const kArrayBufferMaxByteLength:
constexpr uintptr generates 'JSArrayBuffer::kMaxByteLength';
const kTypedArrayMaxLength:
constexpr uintptr generates 'JSTypedArray::kMaxLength';
const kMaxTypedArrayInHeap:
constexpr int31 generates 'JSTypedArray::kMaxSizeInHeap';
// CSA does not support 64-bit types on 32-bit platforms so as a workaround the
......
......@@ -24,9 +24,8 @@ namespace typed_array {
struct TypedArrayElementsInfo {
// Calculates the number of bytes required for specified number of elements.
CalculateByteLength(length: uintptr): uintptr labels IfInvalid {
// TODO(v8:4153): use kArrayBufferMaxByteLength instead of kSmiMaxValue
// to allow creation of huge TypedArrays.
const maxArrayLength = kSmiMaxValue >>> this.sizeLog2;
if (length > kTypedArrayMaxLength) goto IfInvalid;
const maxArrayLength = kArrayBufferMaxByteLength >>> this.sizeLog2;
if (length > maxArrayLength) goto IfInvalid;
const byteLength = length << this.sizeLog2;
return byteLength;
......@@ -36,9 +35,7 @@ namespace typed_array {
// of bytes.
CalculateLength(byteLength: uintptr): uintptr labels IfInvalid {
const length = byteLength >>> this.sizeLog2;
// TODO(v8:4153): use kArrayBufferMaxByteLength instead of kSmiMaxValue
// to allow creation of huge TypedArrays.
if (length > kSmiMaxValue) goto IfInvalid;
if (length > kTypedArrayMaxLength) goto IfInvalid;
return length;
}
......
......@@ -129,19 +129,12 @@ class ShellArrayBufferAllocator : public ArrayBufferAllocatorBase {
private:
static constexpr size_t kVMThreshold = 65536;
static constexpr size_t kTwoGB = 2u * 1024u * 1024u * 1024u;
void* AllocateVM(size_t length) {
DCHECK_LE(kVMThreshold, length);
// TODO(titzer): allocations should fail if >= 2gb because array buffers
// store their lengths as a SMI internally.
if (length >= kTwoGB) return nullptr;
v8::PageAllocator* page_allocator = i::GetPlatformPageAllocator();
size_t page_size = page_allocator->AllocatePageSize();
size_t allocated = RoundUp(length, page_size);
// Rounding up could go over the limit.
if (allocated >= kTwoGB) return nullptr;
return i::AllocatePages(page_allocator, nullptr, allocated, page_size,
PageAllocator::kReadWrite);
}
......
......@@ -1273,6 +1273,18 @@ RUNTIME_FUNCTION(Runtime_HeapObjectVerify) {
return isolate->heap()->ToBoolean(true);
}
RUNTIME_FUNCTION(Runtime_ArrayBufferMaxByteLength) {
HandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return *isolate->factory()->NewNumber(JSArrayBuffer::kMaxByteLength);
}
RUNTIME_FUNCTION(Runtime_TypedArrayMaxLength) {
HandleScope shs(isolate);
DCHECK_EQ(0, args.length());
return *isolate->factory()->NewNumber(JSTypedArray::kMaxLength);
}
RUNTIME_FUNCTION(Runtime_WasmGetNumberOfInstances) {
SealHandleScope shs(isolate);
DCHECK_EQ(1, args.length());
......
......@@ -265,6 +265,7 @@ namespace internal {
F(GetModuleNamespace, 1, 1)
#define FOR_EACH_INTRINSIC_NUMBERS(F, I) \
F(ArrayBufferMaxByteLength, 0, 1) \
F(GetHoleNaNLower, 0, 1) \
F(GetHoleNaNUpper, 0, 1) \
I(IsSmi, 1, 1) \
......@@ -273,7 +274,8 @@ namespace internal {
F(NumberToString, 1, 1) \
F(StringParseFloat, 1, 1) \
F(StringParseInt, 2, 1) \
F(StringToNumber, 1, 1)
F(StringToNumber, 1, 1) \
F(TypedArrayMaxLength, 0, 1)
#define FOR_EACH_INTRINSIC_OBJECT(F, I) \
F(AddDictionaryProperty, 3, 1) \
......
......@@ -4,7 +4,7 @@
// Flags: --allow-natives-syntax
const limit = %MaxSmi() + 1;
const limit = %TypedArrayMaxLength() + 1;
(function() {
function foo() {
......
......@@ -211,8 +211,8 @@ tests.push(function TestFromTypedArraySpeciesDetachsBuffer(constr) {
assertThrows(() => new constr(a1));
});
tests.push(function TestLengthIsMaxSmi(constr) {
var myObject = { 0: 5, 1: 6, length: %MaxSmi() + 1 };
tests.push(function TestTypedArrayMaxLength(constr) {
var myObject = { 0: 5, 1: 6, length: %TypedArrayMaxLength() + 1 };
assertThrows(function() {
new constr(myObject);
......
......@@ -26,32 +26,36 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --nostress-opt --allow-natives-syntax --mock-arraybuffer-allocator
var maxSize = %MaxSmi() + 1;
var ab;
let kArrayBufferByteLengthLimit = %ArrayBufferMaxByteLength() + 1;
let kTypedArrayLengthLimit = %TypedArrayMaxLength() + 1;
// Allocate the largest ArrayBuffer we can on this architecture.
for (k = 8; k >= 1 && ab == null; k = k/2) {
try {
ab = new ArrayBuffer(maxSize * k);
} catch (e) {
ab = null;
}
}
let ab = new ArrayBuffer(kArrayBufferByteLengthLimit - 1);
assertTrue(ab != null);
function TestArray(constr, elementSize) {
assertEquals(kArrayBufferByteLengthLimit % elementSize, 0);
let bufferSizeLength = kArrayBufferByteLengthLimit / elementSize;
let minUnallocatableSize =
kTypedArrayLengthLimit < bufferSizeLength
? kTypedArrayLengthLimit
: bufferSizeLength;
function TestArray(constr) {
assertThrows(function() {
new constr(ab, 0, maxSize);
new constr(ab, 0, minUnallocatableSize);
}, RangeError);
// This one must succeed.
new constr(ab, 0, minUnallocatableSize - 1);
}
TestArray(Uint8Array);
TestArray(Int8Array);
TestArray(Uint16Array);
TestArray(Int16Array);
TestArray(Uint32Array);
TestArray(Int32Array);
TestArray(Float32Array);
TestArray(Float64Array);
TestArray(Uint8ClampedArray);
TestArray(Uint8Array, 1);
TestArray(Int8Array, 1);
TestArray(Uint16Array, 2);
TestArray(Int16Array, 2);
TestArray(Uint32Array, 4);
TestArray(Int32Array, 4);
TestArray(Float32Array, 4);
TestArray(Float64Array, 8);
TestArray(Uint8ClampedArray, 1);
// Copyright 2013 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
......@@ -26,20 +25,34 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --nostress-opt --allow-natives-syntax
var maxSize = %MaxSmi() + 1;
function TestArray(constr) {
// Flags: --nostress-opt --allow-natives-syntax --mock-arraybuffer-allocator
let kArrayBufferByteLengthLimit = %ArrayBufferMaxByteLength() + 1;
let kTypedArrayLengthLimit = %TypedArrayMaxLength() + 1;
function TestArray(constr, elementSize) {
assertEquals(kArrayBufferByteLengthLimit % elementSize, 0);
let bufferSizeLength = kArrayBufferByteLengthLimit / elementSize;
let minUnallocatableSize =
kTypedArrayLengthLimit < bufferSizeLength
? kTypedArrayLengthLimit
: bufferSizeLength;
assertThrows(function() {
new constr(maxSize);
new constr(minUnallocatableSize);
}, RangeError);
// This one must succeed.
new constr(minUnallocatableSize - 1);
}
TestArray(Uint8Array);
TestArray(Int8Array);
TestArray(Uint16Array);
TestArray(Int16Array);
TestArray(Uint32Array);
TestArray(Int32Array);
TestArray(Float32Array);
TestArray(Float64Array);
TestArray(Uint8ClampedArray);
TestArray(Uint8Array, 1);
TestArray(Int8Array, 1);
TestArray(Uint16Array, 2);
TestArray(Int16Array, 2);
TestArray(Uint32Array, 4);
TestArray(Int32Array, 4);
TestArray(Float32Array, 4);
TestArray(Float64Array, 8);
TestArray(Uint8ClampedArray, 1);
......@@ -18,9 +18,11 @@ try {
var __v_12 = new ArrayBuffer(2147483648);
ok = true;
} catch (e) {
// Can happen on 32 bit systems.
// Can happen if the allocation fails.
}
if (ok) {
var module = __f_61(this, null, __v_12);
assertTrue(%IsAsmWasmCode(__f_61));
// This fails AsmJS memory size validation because of kV8MaxWasmMemoryPages
// value.
assertFalse(%IsAsmWasmCode(__f_61));
}
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