Skip to content

Commit cc8fd04

Browse files
liamappelbecommit-bot@chromium.org
authored andcommitted
[wasm] Add WasmMemory class.
Also, port the old wasm memory tests, and fix some NNBD issues. Bug: #37882 Change-Id: I131ba5836bb0a3dd946cf9b0fa3f2e186b6b132e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/162801 Commit-Queue: Liam Appelbe <[email protected]> Reviewed-by: Ryan Macnak <[email protected]>
1 parent 53e707f commit cc8fd04

File tree

9 files changed

+255
-84
lines changed

9 files changed

+255
-84
lines changed

pkg/wasm/lib/src/function.dart

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ class WasmFunction {
1616
Pointer<WasmerValue> _args;
1717
Pointer<WasmerValue> _result;
1818

19-
WasmFunction(this._name, this._func, this._argTypes, this._returnType) {
20-
_args = allocate<WasmerValue>(count: _argTypes.length);
21-
_result = allocate<WasmerValue>();
19+
WasmFunction(this._name, this._func, this._argTypes, this._returnType)
20+
: _args = allocate<WasmerValue>(count: _argTypes.length),
21+
_result = allocate<WasmerValue>() {
2222
for (var i = 0; i < _argTypes.length; ++i) {
2323
_args[i].tag = _argTypes[i];
2424
}
@@ -43,6 +43,7 @@ class WasmFunction {
4343
_args[i].f64 = arg;
4444
return true;
4545
}
46+
return false;
4647
}
4748

4849
dynamic apply(List<dynamic> args) {

pkg/wasm/lib/src/module.dart

+63-10
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ class WasmModule {
1414
Pointer<WasmerModule> _module;
1515

1616
/// Compile a module.
17-
WasmModule(Uint8List data) {
18-
_module = WasmRuntime().compile(data);
19-
}
17+
WasmModule(Uint8List data) : _module = WasmRuntime().compile(data) {}
2018

2119
/// Instantiate the module with the given imports.
2220
WasmInstance instantiate(WasmImports imports) {
@@ -49,9 +47,9 @@ class WasmImports {
4947
int _length;
5048

5149
/// Create an imports object.
52-
WasmImports([this._capacity = 4]) : _length = 0 {
53-
_imports = allocate<WasmerImport>(count: this._capacity);
54-
}
50+
WasmImports([this._capacity = 4])
51+
: _imports = allocate<WasmerImport>(count: _capacity),
52+
_length = 0 {}
5553

5654
/// Returns the number of imports.
5755
int get length => _length;
@@ -61,12 +59,13 @@ class WasmImports {
6159
class WasmInstance {
6260
Pointer<WasmerModule> _module;
6361
Pointer<WasmerInstance> _instance;
64-
Map<String, WasmFunction> _functions;
62+
Pointer<WasmerMemory>? _exportedMemory;
63+
Map<String, WasmFunction> _functions = {};
6564

66-
WasmInstance(this._module, WasmImports imports) {
65+
WasmInstance(this._module, WasmImports imports)
66+
: _instance = WasmRuntime()
67+
.instantiate(_module, imports._imports, imports.length) {
6768
var runtime = WasmRuntime();
68-
_instance = runtime.instantiate(_module, imports._imports, imports.length);
69-
_functions = {};
7069
var exps = runtime.exports(_instance);
7170
for (var e in exps) {
7271
var kind = runtime.exportKind(e);
@@ -75,6 +74,9 @@ class WasmInstance {
7574
var f = runtime.exportToFunction(e);
7675
_functions[name] = WasmFunction(
7776
name, f, runtime.getArgTypes(f), runtime.getReturnType(f));
77+
} else if (kind == WasmerImpExpKindMemory) {
78+
// WASM currently allows only one memory per module.
79+
_exportedMemory = runtime.exportToMemory(e);
7880
}
7981
}
8082
}
@@ -84,4 +86,55 @@ class WasmInstance {
8486
dynamic lookupFunction(String name) {
8587
return _functions[name];
8688
}
89+
90+
/// Returns the memory exported from this instance.
91+
WasmMemory get memory {
92+
if (_exportedMemory == null) {
93+
throw Exception("Wasm module did not export its memory.");
94+
}
95+
return WasmMemory._fromExport(_exportedMemory as Pointer<WasmerMemory>);
96+
}
97+
}
98+
99+
/// WasmMemory contains the memory of a WasmInstance.
100+
class WasmMemory {
101+
Pointer<WasmerMemory> _mem;
102+
late Uint8List _view;
103+
104+
WasmMemory._fromExport(this._mem) {
105+
_view = WasmRuntime().memoryView(_mem);
106+
}
107+
108+
/// Create a new memory with the given number of initial pages, and optional
109+
/// maximum number of pages.
110+
WasmMemory(int pages, [int? maxPages])
111+
: _mem = WasmRuntime().newMemory(pages, maxPages) {
112+
_view = WasmRuntime().memoryView(_mem);
113+
}
114+
115+
/// The WASM spec defines the page size as 64KiB.
116+
static const int kPageSizeInBytes = 64 * 1024;
117+
118+
/// Returns the length of the memory in pages.
119+
int get lengthInPages {
120+
return WasmRuntime().memoryLength(_mem);
121+
}
122+
123+
/// Returns the length of the memory in bytes.
124+
int get lengthInBytes => _view.lengthInBytes;
125+
126+
/// Returns the byte at the given index.
127+
int operator [](int index) => _view[index];
128+
129+
/// Sets the byte at the given index to value.
130+
void operator []=(int index, int value) {
131+
_view[index] = value;
132+
}
133+
134+
/// Grow the memory by deltaPages.
135+
void grow(int deltaPages) {
136+
var runtime = WasmRuntime();
137+
runtime.growMemory(_mem, deltaPages);
138+
_view = runtime.memoryView(_mem);
139+
}
87140
}

pkg/wasm/lib/src/runtime.dart

+96-31
Original file line numberDiff line numberDiff line change
@@ -24,41 +24,47 @@ class WasmExportDescriptor {
2424
}
2525

2626
class WasmRuntime {
27-
static WasmRuntime _inst;
27+
static WasmRuntime? _inst;
2828

2929
DynamicLibrary _lib;
30-
WasmerCompileFn _compile;
31-
WasmerInstantiateFn _instantiate;
32-
WasmerInstanceExportsFn _instance_exports;
33-
WasmerExportsLenFn _exports_len;
34-
WasmerExportsGetFn _exports_get;
35-
WasmerExportKindFn _export_kind;
36-
WasmerExportToFuncFn _export_to_func;
37-
WasmerExportFuncReturnsArityFn _export_func_returns_arity;
38-
WasmerExportFuncReturnsFn _export_func_returns;
39-
WasmerExportFuncParamsArityFn _export_func_params_arity;
40-
WasmerExportFuncParamsFn _export_func_params;
41-
WasmerExportFuncCallFn _export_func_call;
42-
WasmerExportNamePtrFn _export_name_ptr;
43-
WasmerExportDescriptorsFn _export_descriptors;
44-
WasmerExportDescriptorsDestroyFn _export_descriptors_destroy;
45-
WasmerExportDescriptorsLenFn _export_descriptors_len;
46-
WasmerExportDescriptorsGetFn _export_descriptors_get;
47-
WasmerExportDescriptorKindFn _export_descriptor_kind;
48-
WasmerExportDescriptorNamePtrFn _export_descriptor_name_ptr;
49-
WasmerImportDescriptorModuleNamePtrFn _import_descriptor_module_name_ptr;
50-
WasmerImportDescriptorNamePtrFn _import_descriptor_name_ptr;
51-
WasmerImportDescriptorsFn _import_descriptors;
52-
WasmerImportDescriptorsDestroyFn _import_descriptors_destroy;
53-
WasmerImportDescriptorsLenFn _import_descriptors_len;
54-
WasmerImportDescriptorsGetFn _import_descriptors_get;
55-
WasmerImportDescriptorKindFn _import_descriptor_kind;
30+
late WasmerCompileFn _compile;
31+
late WasmerInstantiateFn _instantiate;
32+
late WasmerInstanceExportsFn _instance_exports;
33+
late WasmerExportsLenFn _exports_len;
34+
late WasmerExportsGetFn _exports_get;
35+
late WasmerExportKindFn _export_kind;
36+
late WasmerExportToFuncFn _export_to_func;
37+
late WasmerExportFuncReturnsArityFn _export_func_returns_arity;
38+
late WasmerExportFuncReturnsFn _export_func_returns;
39+
late WasmerExportFuncParamsArityFn _export_func_params_arity;
40+
late WasmerExportFuncParamsFn _export_func_params;
41+
late WasmerExportFuncCallFn _export_func_call;
42+
late WasmerExportNamePtrFn _export_name_ptr;
43+
late WasmerExportDescriptorsFn _export_descriptors;
44+
late WasmerExportDescriptorsDestroyFn _export_descriptors_destroy;
45+
late WasmerExportDescriptorsLenFn _export_descriptors_len;
46+
late WasmerExportDescriptorsGetFn _export_descriptors_get;
47+
late WasmerExportDescriptorKindFn _export_descriptor_kind;
48+
late WasmerExportDescriptorNamePtrFn _export_descriptor_name_ptr;
49+
late WasmerImportDescriptorModuleNamePtrFn _import_descriptor_module_name_ptr;
50+
late WasmerImportDescriptorNamePtrFn _import_descriptor_name_ptr;
51+
late WasmerImportDescriptorsFn _import_descriptors;
52+
late WasmerImportDescriptorsDestroyFn _import_descriptors_destroy;
53+
late WasmerImportDescriptorsLenFn _import_descriptors_len;
54+
late WasmerImportDescriptorsGetFn _import_descriptors_get;
55+
late WasmerImportDescriptorKindFn _import_descriptor_kind;
56+
late WasmerExportToMemoryFn _export_to_memory;
57+
late WasmerMemoryNewPtrFn _memory_new_ptr;
58+
late WasmerMemoryGrowFn _memory_grow;
59+
late WasmerMemoryLengthFn _memory_length;
60+
late WasmerMemoryDataFn _memory_data;
61+
late WasmerMemoryDataLengthFn _memory_data_length;
5662

5763
factory WasmRuntime() {
5864
if (_inst == null) {
5965
_inst = WasmRuntime._init();
6066
}
61-
return _inst;
67+
return _inst as WasmRuntime;
6268
}
6369

6470
static String _getLibName() {
@@ -96,9 +102,8 @@ class WasmRuntime {
96102
return commonLibDir;
97103
}
98104

99-
WasmRuntime._init() {
100-
var libPath = path.join(_getLibDir(), _getLibName());
101-
_lib = DynamicLibrary.open(libPath);
105+
WasmRuntime._init()
106+
: _lib = DynamicLibrary.open(path.join(_getLibDir(), _getLibName())) {
102107
_compile = _lib.lookupFunction<NativeWasmerCompileFn, WasmerCompileFn>(
103108
'wasmer_compile');
104109
_instantiate =
@@ -171,6 +176,22 @@ class WasmRuntime {
171176
_import_descriptor_name_ptr = _lib.lookupFunction<
172177
NativeWasmerImportDescriptorNamePtrFn,
173178
WasmerImportDescriptorNamePtrFn>('wasmer_import_descriptor_name_ptr');
179+
_export_to_memory = _lib.lookupFunction<NativeWasmerExportToMemoryFn,
180+
WasmerExportToMemoryFn>('wasmer_export_to_memory');
181+
_memory_new_ptr =
182+
_lib.lookupFunction<NativeWasmerMemoryNewPtrFn, WasmerMemoryNewPtrFn>(
183+
'wasmer_memory_new_ptr');
184+
_memory_grow =
185+
_lib.lookupFunction<NativeWasmerMemoryGrowFn, WasmerMemoryGrowFn>(
186+
'wasmer_memory_grow');
187+
_memory_length =
188+
_lib.lookupFunction<NativeWasmerMemoryLengthFn, WasmerMemoryLengthFn>(
189+
'wasmer_memory_length');
190+
_memory_data =
191+
_lib.lookupFunction<NativeWasmerMemoryDataFn, WasmerMemoryDataFn>(
192+
'wasmer_memory_data');
193+
_memory_data_length = _lib.lookupFunction<NativeWasmerMemoryDataLengthFn,
194+
WasmerMemoryDataLengthFn>('wasmer_memory_data_length');
174195
}
175196

176197
Pointer<WasmerModule> compile(Uint8List data) {
@@ -331,4 +352,48 @@ class WasmRuntime {
331352
throw Exception("Failed to call WASM function");
332353
}
333354
}
355+
356+
Pointer<WasmerMemory> exportToMemory(Pointer<WasmerExport> export) {
357+
var memPtrPtr = allocate<Pointer<WasmerMemory>>();
358+
var result = _export_to_memory(export, memPtrPtr);
359+
if (result != WasmerResultOk) {
360+
free(memPtrPtr);
361+
throw Exception("Failed to get exported memory");
362+
}
363+
Pointer<WasmerMemory> memPtr = memPtrPtr.value;
364+
free(memPtrPtr);
365+
return memPtr;
366+
}
367+
368+
Pointer<WasmerMemory> newMemory(int pages, int? maxPages) {
369+
var memPtrPtr = allocate<Pointer<WasmerMemory>>();
370+
var limPtr = allocate<WasmerLimits>();
371+
limPtr.ref.min = pages;
372+
limPtr.ref.has_max = maxPages != null ? 1 : 0;
373+
limPtr.ref.max = maxPages ?? 0;
374+
var result = _memory_new_ptr(memPtrPtr, limPtr);
375+
free(limPtr);
376+
if (result != WasmerResultOk) {
377+
free(memPtrPtr);
378+
throw Exception("Failed to create memory");
379+
}
380+
Pointer<WasmerMemory> memPtr = memPtrPtr.value;
381+
free(memPtrPtr);
382+
return memPtr;
383+
}
384+
385+
void growMemory(Pointer<WasmerMemory> memory, int deltaPages) {
386+
var result = _memory_grow(memory, deltaPages);
387+
if (result != WasmerResultOk) {
388+
throw Exception("Failed to grow memory");
389+
}
390+
}
391+
392+
int memoryLength(Pointer<WasmerMemory> memory) {
393+
return _memory_length(memory);
394+
}
395+
396+
Uint8List memoryView(Pointer<WasmerMemory> memory) {
397+
return _memory_data(memory).asTypedList(_memory_data_length(memory));
398+
}
334399
}

0 commit comments

Comments
 (0)