[dart2wasm] Interfaces for accessing memories
This adds the `Memory` class to `dart:_wasm`, allowing Dart code to
load and store numeric types in linear memory.
Since `dart2wasm` doesn't generate a memory instance by default, there
is no singleton instance of `Memory`. Instead, memories are defined as
`external` top-level getters annotated with a pragma like
`@pragma('wasm:memory-tyype', MemoryType(limits: Limits(1, 10)))` to
declare their type.
Interop happens in a static way: Methods on `Memory` cannot be torn-off
and, since the target memory is encoded directly in the store/load
instruction, there's also no polymorphism for memories in Dart.
Attempting to call methods on a memory instance that isn't a direct
reference to its definition is a compile-time error.
Memories can also be imported and exported through the existing
`wasm:import` and `wasm:export` pragmas.
TEST=tests/web/wasm/memory_test.dart
Change-Id: I726f33ac2ec04afab55c5a2b6bc09079d0193e02
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/470020
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
47ba2f23a1
commit
7d8cd032dc
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
//
|
||||
// dart2wasmOptions=--enable-deferred-loading --extra-compiler-option=--enable-experimental-wasm-interop
|
||||
|
||||
import 'dart:_wasm';
|
||||
|
||||
import '' deferred as M;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void main() async {
|
||||
await M.loadLibrary();
|
||||
|
||||
write();
|
||||
Expect.equals(42, M.read());
|
||||
}
|
||||
|
||||
void write() {
|
||||
M.memory.storeInt64(0, WasmI64.fromInt(42));
|
||||
}
|
||||
|
||||
@pragma('wasm:memory-type', MemoryType(limits: Limits(1)))
|
||||
external Memory get memory;
|
||||
|
||||
@pragma('wasm:never-inline')
|
||||
int read() {
|
||||
return memory.loadInt64(0).toInt();
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
|
||||
|
||||
import 'dart:_wasm';
|
||||
|
||||
external Memory get missingAnnotation;
|
||||
// ^
|
||||
// [web] This external getter returns a memory instance, but no annotation describing it was found
|
||||
|
||||
@pragma('wasm:memory-type', MemoryType(limits: Limits(1, 10)))
|
||||
external Memory get validDefinition;
|
||||
|
||||
void main() {
|
||||
validDefinition.loadUint8(10);
|
||||
validDefinition.size;
|
||||
|
||||
print(validDefinition);
|
||||
// ^
|
||||
// [web] WebAssembly elements may only be referenced to directly call a method on them.
|
||||
|
||||
print(validDefinition.fill);
|
||||
// ^
|
||||
// [web] This intrinsic extension member may not be torn off.
|
||||
}
|
||||
|
||||
void invalidDynamicMemory(Memory memory) {
|
||||
memory.loadUint8(10);
|
||||
// ^
|
||||
// [web] The receiver of this call must be a top-level variable describing the WebAssembly element.
|
||||
}
|
||||
|
||||
int get notAConstant => 3;
|
||||
|
||||
void invalidNonConstantArguments() {
|
||||
validDefinition.loadUint8(0, offset: 12, align: 1);
|
||||
validDefinition.loadUint8(0, offset: notAConstant);
|
||||
// ^
|
||||
// [web] The variable 'offset' is not a constant, only constant expressions are allowed.
|
||||
validDefinition.loadUint8(0, align: notAConstant);
|
||||
// ^
|
||||
// [web] The variable 'align' is not a constant, only constant expressions are allowed.
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
// Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// dart2wasmOptions=--extra-compiler-option=--enable-experimental-wasm-interop
|
||||
|
||||
import 'dart:_wasm';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
@pragma('wasm:memory-type', MemoryType(limits: Limits(1, 10)))
|
||||
external Memory get _memory;
|
||||
|
||||
void main() {
|
||||
_testSizeAndGrow();
|
||||
_testFill();
|
||||
|
||||
_testFloat();
|
||||
_testInt();
|
||||
_testOffset();
|
||||
}
|
||||
|
||||
void _testSizeAndGrow() {
|
||||
Expect.equals(1, _memory.size);
|
||||
Expect.equals(1, _memory.grow(1));
|
||||
Expect.equals(2, _memory.size);
|
||||
|
||||
Expect.equals(0, _memory.loadInt32(Memory.pageSize + 1).toIntSigned());
|
||||
|
||||
Expect.equals(-1, _memory.grow(20));
|
||||
}
|
||||
|
||||
void _testFill() {
|
||||
_memory.fill(WasmI32.fromInt(42), 0, 1024);
|
||||
for (var i = 0; i < 1024; i++) {
|
||||
Expect.equals(42, _memory.loadUint8(i).toIntSigned());
|
||||
}
|
||||
}
|
||||
|
||||
void _testFloat() {
|
||||
_memory.storeFloat64(0, WasmF64.fromDouble(1.5));
|
||||
Expect.equals(1.5, _memory.loadFloat64(0).toDouble());
|
||||
|
||||
_memory.storeFloat32(0, WasmF32.fromDouble(1.5));
|
||||
Expect.equals(1.5, _memory.loadFloat32(0).toDouble());
|
||||
}
|
||||
|
||||
void _testInt() {
|
||||
_memory.storeInt8(0, WasmI32.fromInt(-1));
|
||||
Expect.equals(-1, _memory.loadInt8(0).toIntSigned());
|
||||
Expect.equals(255, _memory.loadUint8(0).toIntUnsigned());
|
||||
}
|
||||
|
||||
void _testOffset() {
|
||||
_memory.storeInt32(0, WasmI32.fromInt(0x01020304));
|
||||
Expect.equals(0x01, _memory.loadInt8(0, offset: 3).toIntSigned());
|
||||
Expect.equals(0x02, _memory.loadInt8(0, offset: 2).toIntSigned());
|
||||
Expect.equals(0x03, _memory.loadInt8(0, offset: 1).toIntSigned());
|
||||
Expect.equals(0x04, _memory.loadInt8(0, offset: 0).toIntSigned());
|
||||
}
|
||||
Reference in New Issue
Block a user