[dart2wasm] Allow using experimental dart:ffi in deferred modules

The experimental `dart:ffi` support predates deferred loading
implementation. Any use of FFI features would lazily import `ffi.memory`
into the (fixed coded) main module.

This CL now lazily imports the `ffi.memory` module into all modules that
operate on the memory.

=> This will now allow a flutter app that is compiled with dart2wasm
   in deferred loading mode to possibly defer parts of flutter
   engine code that uses FFI into deferred modules.

Issue https://github.com/dart-lang/sdk/issues/56952

Change-Id: Idf821ce2dd92c36ac1be9dae24307516a1ae86d9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/510760
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Martin Kustermann
2026-06-10 02:34:44 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent c5f9583eb3
commit 034b90af5d
3 changed files with 48 additions and 31 deletions
+20 -19
View File
@@ -1610,42 +1610,43 @@ class Intrinsifier {
b.i32_add();
offset = 0;
}
final memory = translator.ffiMemory(b.moduleBuilder);
switch (intrinsic) {
case StaticIntrinsic.loadInt8:
b.i64_load8_s(translator.ffiMemory, offset);
b.i64_load8_s(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadUint8:
b.i64_load8_u(translator.ffiMemory, offset);
b.i64_load8_u(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadInt16:
b.i64_load16_s(translator.ffiMemory, offset);
b.i64_load16_s(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadUint16:
b.i64_load16_u(translator.ffiMemory, offset);
b.i64_load16_u(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadInt32:
b.i64_load32_s(translator.ffiMemory, offset);
b.i64_load32_s(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadUint32:
b.i64_load32_u(translator.ffiMemory, offset);
b.i64_load32_u(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadInt64:
case StaticIntrinsic.loadUint64:
b.i64_load(translator.ffiMemory, offset);
b.i64_load(memory, offset);
return w.NumType.i64;
case StaticIntrinsic.loadFloat:
b.f32_load(translator.ffiMemory, offset);
b.f32_load(memory, offset);
b.f64_promote_f32();
return w.NumType.f64;
case StaticIntrinsic.loadFloatUnaligned:
b.f32_load(translator.ffiMemory, offset, 0);
b.f32_load(memory, offset, 0);
b.f64_promote_f32();
return w.NumType.f64;
case StaticIntrinsic.loadDouble:
b.f64_load(translator.ffiMemory, offset);
b.f64_load(memory, offset);
return w.NumType.f64;
case StaticIntrinsic.loadDoubleUnaligned:
b.f64_load(translator.ffiMemory, offset, 0);
b.f64_load(memory, offset, 0);
return w.NumType.f64;
case StaticIntrinsic.storeInt8:
case StaticIntrinsic.storeUint8:
@@ -1653,7 +1654,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.i64,
);
b.i64_store8(translator.ffiMemory, offset);
b.i64_store8(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt16:
@@ -1662,7 +1663,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.i64,
);
b.i64_store16(translator.ffiMemory, offset);
b.i64_store16(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt32:
@@ -1671,7 +1672,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.i64,
);
b.i64_store32(translator.ffiMemory, offset);
b.i64_store32(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeInt64:
@@ -1680,7 +1681,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.i64,
);
b.i64_store(translator.ffiMemory, offset);
b.i64_store(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeFloat:
@@ -1689,7 +1690,7 @@ class Intrinsifier {
w.NumType.f64,
);
b.f32_demote_f64();
b.f32_store(translator.ffiMemory, offset);
b.f32_store(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeFloatUnaligned:
@@ -1698,7 +1699,7 @@ class Intrinsifier {
w.NumType.f64,
);
b.f32_demote_f64();
b.f32_store(translator.ffiMemory, offset, 0);
b.f32_store(memory, offset, 0);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeDouble:
@@ -1706,7 +1707,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.f64,
);
b.f64_store(translator.ffiMemory, offset);
b.f64_store(memory, offset);
b.ref_null(w.HeapType.none);
return translator.topType;
case StaticIntrinsic.storeDoubleUnaligned:
@@ -1714,7 +1715,7 @@ class Intrinsifier {
node.arguments.positional[2],
w.NumType.f64,
);
b.f64_store(translator.ffiMemory, offset, 0);
b.f64_store(memory, offset, 0);
b.ref_null(w.HeapType.none);
return translator.topType;
default:
+15 -12
View File
@@ -204,16 +204,22 @@ class Translator with KernelNodes {
w.StructType("void"),
nullable: true,
);
// Lazily import FFI memory if used.
late final w.Memory ffiMemory = mainModule.memories.import(
"ffi",
"memory",
options.importSharedMemory,
0,
options.sharedMemoryMaxPages,
);
final Map<Procedure, w.Memory> _memories = {};
// Lazily import FFI memory if used.
final _ffiMemoryImports = <w.ModuleBuilder, w.Memory>{};
w.Memory ffiMemory(w.ModuleBuilder usingModule) {
return _ffiMemoryImports.putIfAbsent(usingModule, () {
return usingModule.memories.import(
"ffi",
"memory",
options.importSharedMemory,
0,
options.sharedMemoryMaxPages,
);
});
}
/// Maps record shapes to the record class for the shape. Classes generated
/// by `record_class_generator` library.
final Map<RecordShape, Class> recordClasses;
@@ -2192,10 +2198,7 @@ class Translator with KernelNodes {
return _shouldInlineProcedureCall(target, signature, member as Procedure);
}
InliningDecision _shouldInlineFieldAccessor(
Reference target,
Field field,
) {
InliningDecision _shouldInlineFieldAccessor(Reference target, Field field) {
if (field.isInstanceMember) {
// Implicit instance getters are just loads.
if (target.isImplicitGetter) {