Commit 2f4df8da authored by Jakob Kummerow's avatar Jakob Kummerow Committed by V8 LUCI CQ

[wasm-gc] Increase struct field limit to 2000

Due to popular demand.
As a necessary byproduct, this drops our former experimental in-progress
support for accessing struct fields from JS as `.field0` etc. If we need
something similar in the future, we'll have to build a new mechanism for
it that scales to >1020 fields.

Bug: v8:7748
Change-Id: I08b2051bd9f76cf7128f3d4c74910ca891c38130
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3793616Reviewed-by: 's avatarManos Koukoutos <manoskouk@chromium.org>
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82079}
parent 19bc589d
......@@ -3,19 +3,16 @@
// found in the LICENSE file.
#include "src/builtins/builtins-utils-inl.h"
#include "src/objects/js-struct-inl.h"
#include "src/objects/property-details.h"
namespace v8 {
namespace internal {
constexpr int kMaxJSStructFields = 999;
#ifdef V8_ENABLE_WEBASSEMBLY
#include "src/wasm/wasm-limits.h"
static_assert(wasm::kV8MaxWasmStructFields == kMaxJSStructFields,
"Max number of fields should be the same for both JS and "
"WebAssembly structs");
#endif // V8_ENABLE_WEBASSEMBLY
// Note: For Wasm structs, we currently allow 2000 fields, because there was
// specific demand for that. Ideally we'd have the same limit, but JS structs
// rely on DescriptorArrays and are hence limited to 1020 fields at most.
static_assert(kMaxJSStructFields <= kMaxNumberOfDescriptors);
BUILTIN(SharedStructTypeConstructor) {
DCHECK(FLAG_shared_string_table);
......
......@@ -83,40 +83,6 @@ class CompileImportWrapperJob final : public JobTask {
WasmImportWrapperCache::ModificationScope* const cache_scope_;
};
Handle<DescriptorArray> CreateStructDescriptorArray(
Isolate* isolate, const wasm::StructType* type) {
if (type->field_count() == 0) {
return isolate->factory()->empty_descriptor_array();
}
uint32_t field_count = type->field_count();
static_assert(kV8MaxWasmStructFields <= kMaxNumberOfDescriptors,
"Bigger numbers of struct fields require different approach");
Handle<DescriptorArray> descriptors =
isolate->factory()->NewDescriptorArray(field_count);
// TODO(ishell): cache Wasm field type in FieldType value.
MaybeObject any_type = MaybeObject::FromObject(FieldType::Any());
DCHECK(any_type->IsSmi());
base::EmbeddedVector<char, 128> name_buffer;
for (uint32_t i = 0; i < field_count; i++) {
// TODO(ishell): consider introducing a cache of first N internalized field
// names similar to LookupSingleCharacterStringFromCode().
SNPrintF(name_buffer, "$field%d", i);
Handle<String> name =
isolate->factory()->InternalizeUtf8String(name_buffer.begin());
PropertyAttributes attributes = type->mutability(i) ? SEALED : FROZEN;
PropertyDetails details(
PropertyKind::kData, attributes, PropertyLocation::kField,
PropertyConstness::kMutable, // Don't track constness
Representation::WasmValue(), static_cast<int>(i));
descriptors->Set(InternalIndex(i), *name, any_type, details);
}
descriptors->Sort();
return descriptors;
}
Handle<DescriptorArray> CreateArrayDescriptorArray(
Isolate* isolate, const wasm::ArrayType* type) {
uint32_t kDescriptorsCount = 1;
......@@ -153,13 +119,11 @@ Handle<Map> CreateStructMap(Isolate* isolate, const WasmModule* module,
Handle<WasmTypeInfo> type_info = isolate->factory()->NewWasmTypeInfo(
reinterpret_cast<Address>(type), opt_rtt_parent, real_instance_size,
instance);
Handle<DescriptorArray> descriptors =
CreateStructDescriptorArray(isolate, type);
Handle<Map> map = isolate->factory()->NewMap(
instance_type, map_instance_size, elements_kind, inobject_properties);
map->set_wasm_type_info(*type_info);
map->SetInstanceDescriptors(isolate, *descriptors,
descriptors->number_of_descriptors());
map->SetInstanceDescriptors(isolate,
*isolate->factory()->empty_descriptor_array(), 0);
map->set_is_extensible(false);
WasmStruct::EncodeInstanceSizeInMap(real_instance_size, *map);
return map;
......
......@@ -62,7 +62,7 @@ constexpr size_t kV8MaxWasmTables = 100000;
constexpr size_t kV8MaxWasmMemories = 1;
// GC proposal. These limits are not standardized yet.
constexpr size_t kV8MaxWasmStructFields = 999;
constexpr size_t kV8MaxWasmStructFields = 2000;
constexpr uint32_t kV8MaxRttSubtypingDepth = 31;
constexpr size_t kV8MaxWasmArrayNewFixedLength = 10000;
......
// Copyright 2021 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: --allow-natives-syntax --experimental-wasm-gc --wasm-gc-js-interop
// Flags: --expose-gc
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
const kIterationsCountForICProgression = 20;
function createSimpleStruct(field_type, value1, value2) {
const builder = new WasmModuleBuilder();
const is_small_int = (field_type == kWasmI8) || (field_type == kWasmI16);
const parameter_type = is_small_int ? kWasmI32 : field_type;
const struct_get_opcode = is_small_int ? kExprStructGetS : kExprStructGet;
const type_index = builder.addStruct([
{type: field_type, mutability: true},
]);
let sig_a_t = makeSig_r_x(kWasmDataRef, parameter_type);
let sig_t_a = makeSig_r_x(parameter_type, kWasmDataRef);
let sig_v_at = makeSig([kWasmDataRef, parameter_type], []);
builder.addFunction("new_struct", sig_a_t)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprStructNew, type_index]) // --
.exportAs("new_struct");
builder.addFunction("get_field", sig_t_a)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRefCastStatic, type_index, // --
kGCPrefix, struct_get_opcode, type_index, 0]) // --
.exportAs("get_field");
builder.addFunction("set_field", sig_v_at)
.addBody([
kExprLocalGet, 0, // --
kGCPrefix, kExprRefCastStatic, type_index, // --
kExprLocalGet, 1, // --
kGCPrefix, kExprStructSet, type_index, 0]) // --
.exportAs("set_field");
let instance = builder.instantiate();
let new_struct = instance.exports.new_struct;
let get_field = instance.exports.get_field;
let set_field = instance.exports.set_field;
// Check that ctor, getter and setter work.
let o = new_struct(value1);
let res;
res = get_field(o);
assertEquals(value1, res);
set_field(o, value2);
res = get_field(o);
assertEquals(value2, res);
return {new_struct, get_field, set_field};
}
function SimpleStructInterop(field_type, value_generator,
value1 = 42, value2 = 111) {
const { new_struct, get_field, set_field } =
createSimpleStruct(field_type, value1, value2);
function f(o, value) {
for (let i = 0; i < kIterationsCountForICProgression; i++) {
let store_IC_exception;
try { o.$field0 = value; } catch (e) { store_IC_exception = e; }
let set_field_exception;
try { set_field(o, value); } catch (e) { set_field_exception = e; };
// set_field() and store IC should throw the same error at the same time.
assertEquals(set_field_exception, store_IC_exception);
if (set_field_exception != undefined) continue;
let expected = get_field(o);
let v = o.$field0;
assertEquals(expected, v);
// "Clear" the field value.
set_field(o, value1);
assertEquals(value1, get_field(o));
o.$field0 = value;
assertEquals(expected, get_field(o));
v = o[i];
assertEquals(undefined, v);
}
}
// Start collecting feedback from scratch.
%ClearFunctionFeedback(f);
let o = new_struct(value1);
for (const value of value_generator()) {
print("value: " + value);
f(o, value);
}
gc();
}
function MakeValueGenerator(max, ValueConstructor = Number) {
return function*() {
const max_safe_integer_float = 2**23 - 1;
yield -max;
yield -max - ValueConstructor(1);
yield max;
yield 0.0;
yield -0.0;
yield 0n;
for (let i = 0; i < 10; i++) {
yield ValueConstructor(Math.floor((Math.random() - 0.5) * Number(max)));
}
// Try some non-trivial values.
yield 153;
yield 77n;
yield ValueConstructor(Number.MAX_SAFE_INTEGER);
yield ValueConstructor(Number.MIN_SAFE_INTEGER);
yield ValueConstructor(max_safe_integer_float);
yield { foo:17 };
yield "boom";
yield { valueOf() { return 42; } };
yield { valueOf() { return 15142n; } };
yield { valueOf() { return BigInt(max); } };
yield { toString() { return "" + max; } };
yield { toString() { return "" + (-max); } };
yield { toString() { return "5421351n"; } };
};
}
(function TestSimpleStructsInteropI8() {
const max = 0x7f;
SimpleStructInterop(kWasmI8, MakeValueGenerator(max));
})();
(function TestSimpleStructsInteropI16() {
const max = 0x7fff;
SimpleStructInterop(kWasmI16, MakeValueGenerator(max));
})();
(function TestSimpleStructsInteropI32() {
const max = 0x7fffffff;
SimpleStructInterop(kWasmI32, MakeValueGenerator(max));
})();
(function TestSimpleStructsInteropI64() {
const max = 0x7fffffffffffffn;
SimpleStructInterop(kWasmI64, MakeValueGenerator(max, BigInt), 42n, 153n);
})();
(function TestSimpleStructsInteropF32() {
const max = 3.402823466e+38;
SimpleStructInterop(kWasmF32, MakeValueGenerator(max));
})();
(function TestSimpleStructsInteropF64() {
const max = 1.7976931348623157e+308;
SimpleStructInterop(kWasmF64, MakeValueGenerator(max));
})();
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