Add support for importing shared memory as per wasm threading proposal.

Change-Id: I077b8d3a60f543c3e54cd3e6d024260adcb8ed83
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241420
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Jackson Gardner <jacksongardner@google.com>
This commit is contained in:
Jackson Gardner 2022-04-22 22:40:29 +00:00 committed by Commit Bot
parent e5f4b85066
commit 6466bac7cd
7 changed files with 38 additions and 14 deletions

View file

@ -13,6 +13,7 @@ import 'package:dart2wasm/translator.dart';
final Map<String, void Function(TranslatorOptions, bool)> boolOptionMap = {
"export-all": (o, value) => o.exportAll = value,
"import-shared-memory": (o, value) => o.importSharedMemory = value,
"inlining": (o, value) => o.inlining = value,
"lazy-constants": (o, value) => o.lazyConstants = value,
"local-nullability": (o, value) => o.localNullability = value,
@ -27,6 +28,7 @@ final Map<String, void Function(TranslatorOptions, bool)> boolOptionMap = {
"string-data-segments": (o, value) => o.stringDataSegments = value,
};
final Map<String, void Function(TranslatorOptions, int)> intOptionMap = {
"shared-memory-max-pages": (o, value) => o.sharedMemoryMaxPages = value,
"watch": (o, value) => (o.watchPoints ??= []).add(value),
};
@ -83,6 +85,11 @@ Future<int> main(List<String> args) async {
usage("Missing argument to ${args.last}");
}
if (options.importSharedMemory && options.sharedMemoryMaxPages == null) {
usage("--shared-memory-max-pages must be "
"specified if --import-shared-memory is used.");
}
if (nonOptions.length != 2) usage("Requires two file arguments");
String input = nonOptions[0];
String output = nonOptions[1];

View file

@ -12,6 +12,7 @@ where *options* include:
| --------------------------------------- | ------- | ----------- |
| `--dart-sdk=`*path* | relative to script | The location of the `sdk` directory inside the Dart SDK, containing the core library sources.
| `--`[`no-`]`export-all` | no | Export all functions; otherwise, just export `main`.
| `--`[`no-`]`import-shared-memory` | no | Import a shared memory buffer. If this is on, `--shared-memory-max-pages` must also be specified.
| `--`[`no-`]`inlining` | no | Inline small functions.
| `--`[`no-`]`lazy-constants` | no | Instantiate constants lazily.
| `--`[`no-`]`local-nullability` | no | Use non-nullable types for non-nullable locals and temporaries.
@ -22,6 +23,7 @@ where *options* include:
| `--`[`no-`]`print-kernel` | no | Print IR for each function before compiling it.
| `--`[`no-`]`print-wasm` | no | Print Wasm instructions of each compiled function.
| `--`[`no-`]`runtime-types` | no | Use RTTs for allocations and casts.
| `--shared-memory-max-pages` *pagecount* | | Max size of the imported memory buffer. If `--shared-import-memory` is specified, this must also be specified.
| `--`[`no-`]`string-data-segments` | no | Use experimental array init from data segment for string constants.
| `--watch` *offset* | | Print stack trace leading to the byte at offset *offset* in the `.wasm` output file. Can be specified multiple times.

View file

@ -175,7 +175,7 @@ class Constants {
.toBytes();
w.Memory stringMemory =
m.addMemory(stringsAsBytes.length, stringsAsBytes.length);
m.addMemory(false, stringsAsBytes.length, stringsAsBytes.length);
m.addDataSegment(stringsAsBytes, stringMemory, 0);
makeStringFunctionBody(translator.oneByteStringClass, oneByteStringFunction,
(b) {

View file

@ -27,6 +27,7 @@ import 'package:wasm_builder/wasm_builder.dart' as w;
/// Options controlling the translation.
class TranslatorOptions {
bool exportAll = false;
bool importSharedMemory = false;
bool inlining = false;
int inliningLimit = 3;
bool lazyConstants = false;
@ -38,6 +39,7 @@ class TranslatorOptions {
bool printKernel = false;
bool printWasm = false;
bool runtimeTypes = false;
int? sharedMemoryMaxPages;
bool stringDataSegments = false;
List<int>? watchPoints = null;
@ -127,7 +129,8 @@ class Translator {
// Lazily create exception tag if used.
late final w.Tag exceptionTag = createExceptionTag();
// Lazily import FFI memory if used.
late final w.Memory ffiMemory = m.importMemory("ffi", "memory", 0);
late final w.Memory ffiMemory = m.importMemory("ffi", "memory",
options.importSharedMemory, 0, options.sharedMemoryMaxPages);
// Caches for when identical source constructs need a common representation.
final Map<w.StorageType, w.ArrayType> arrayTypeCache = {};

View file

@ -130,9 +130,9 @@ class Module with SerializerMixin {
}
/// Add a new memory to the module.
DefinedMemory addMemory(int minSize, [int? maxSize]) {
DefinedMemory addMemory(bool shared, int minSize, [int? maxSize]) {
anyMemoriesDefined = true;
final memory = DefinedMemory(memories.length, minSize, maxSize);
final memory = DefinedMemory(memories.length, shared, minSize, maxSize);
memories.add(memory);
return memory;
}
@ -195,13 +195,14 @@ class Module with SerializerMixin {
///
/// All imported memories must be specified before any memories are declared
/// using [Module.addMemory].
ImportedMemory importMemory(String module, String name, int minSize,
ImportedMemory importMemory(
String module, String name, bool shared, int minSize,
[int? maxSize]) {
if (anyMemoriesDefined) {
throw "All memory imports must be specified before any definitions.";
}
final memory =
ImportedMemory(module, name, memories.length, minSize, maxSize);
ImportedMemory(module, name, memories.length, shared, minSize, maxSize);
memories.add(memory);
return memory;
}
@ -410,13 +411,23 @@ class Table implements Serializable {
/// A memory in a module.
class Memory {
final int index;
final bool shared;
final int minSize;
final int? maxSize;
Memory(this.index, this.minSize, [this.maxSize]);
Memory(this.index, this.shared, this.minSize, [this.maxSize]) {
if (shared && maxSize == null) {
throw "Shared memory must specify a maximum size.";
}
}
void _serializeLimits(Serializer s) {
if (maxSize == null) {
if (shared) {
assert(maxSize != null);
s.writeByte(0x03);
s.writeUnsigned(minSize);
s.writeUnsigned(maxSize!);
} else if (maxSize == null) {
s.writeByte(0x00);
s.writeUnsigned(minSize);
} else {
@ -428,8 +439,8 @@ class Memory {
}
class DefinedMemory extends Memory implements Serializable {
DefinedMemory(int index, int minSize, int? maxSize)
: super(index, minSize, maxSize);
DefinedMemory(int index, bool shared, int minSize, int? maxSize)
: super(index, shared, minSize, maxSize);
@override
void serialize(Serializer s) => _serializeLimits(s);
@ -556,8 +567,9 @@ class ImportedMemory extends Memory implements Import {
final String module;
final String name;
ImportedMemory(this.module, this.name, int index, int minSize, int? maxSize)
: super(index, minSize, maxSize);
ImportedMemory(
this.module, this.name, int index, bool shared, int minSize, int? maxSize)
: super(index, shared, minSize, maxSize);
@override
void serialize(Serializer s) {

View file

@ -38,7 +38,7 @@ void main() {
// Wrong kind of import.
Expect.throws(
() => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)),
() => mod.instantiate().addMemory(false, "env", "someFn", mod.createMemory(10)),
(Exception e) => "$e".contains("Import is not a memory"));
// Wrong namespace.

View file

@ -40,7 +40,7 @@ void main() {
// Wrong kind of import.
Expect.throws(
() => mod.instantiate().addMemory("env", "someFn", mod.createMemory(10)),
() => mod.instantiate().addMemory(false, "env", "someFn", mod.createMemory(10)),
(Exception e) => "$e".contains("Import is not a memory"));
// Wrong namespace.