[dart2wasm] Add deferred loading support to dart2wasm (6/X).
Wasm globals serve a few purposes in the compiler such as storing static fields and closure vtables. Sometimes the access of these globals will be from a different module than the ones they're defined in. We need some indirection to be able to access them in these cross-module situations.
This change adds getter and setter functions that can be called via the StaticTable when a global needs to be accessed from a different module.
We use References to track the owning module for each global to determine if we can access it directly or not.
Change-Id: I93191c83dee1b7a47171c5808e64b071479cdeea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381324
Reviewed-by: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/async.dart b/pkg/dart2wasm/lib/async.dart
index 2918d60..7aba7ab 100644
--- a/pkg/dart2wasm/lib/async.dart
+++ b/pkg/dart2wasm/lib/async.dart
@@ -30,7 +30,8 @@
b.addLocal(w.RefType(asyncSuspendStateInfo.struct, nullable: false));
// AsyncResumeFun _resume
- b.global_get(translator.makeFunctionRef(resumeFun));
+ translator.globals
+ .readGlobal(b, translator.makeFunctionRef(b.module, resumeFun));
// WasmStructRef? _context
if (context != null) {
diff --git a/pkg/dart2wasm/lib/closures.dart b/pkg/dart2wasm/lib/closures.dart
index b29405b..690561d 100644
--- a/pkg/dart2wasm/lib/closures.dart
+++ b/pkg/dart2wasm/lib/closures.dart
@@ -31,8 +31,11 @@
/// The constant global variable pointing to the vtable.
final w.Global vtable;
- ClosureImplementation(
- this.representation, this.functions, this.dynamicCallEntry, this.vtable);
+ /// The module this closure is implemented in.
+ final w.ModuleBuilder module;
+
+ ClosureImplementation(this.representation, this.functions,
+ this.dynamicCallEntry, this.vtable, this.module);
}
/// Describes the representation of closures for a particular function
@@ -58,27 +61,120 @@
/// The struct type for the context of an instantiated closure.
final w.StructType? instantiationContextStruct;
+ final String exportSuffix;
+
/// Entry point functions for instantiations of this generic closure.
- late final List<w.BaseFunction> instantiationTrampolines =
+ late final List<w.BaseFunction> _instantiationTrampolines =
_instantiationTrampolinesThunk!();
List<w.BaseFunction> Function()? _instantiationTrampolinesThunk;
+ final Map<w.ModuleBuilder, List<w.BaseFunction>>
+ _instantiationTrampolinesImports = {};
+ late final List<String> _instantiationTrampolineImportNames = List.generate(
+ _instantiationTrampolines.length,
+ (i) => 'instantiationTrampoline-$i-$exportSuffix');
+ List<w.BaseFunction> _instantiationTrampolinesForModule(
+ Translator translator, w.ModuleBuilder module) {
+ if (translator.isMainModule(module)) {
+ return _instantiationTrampolines;
+ }
+ if (_instantiationTrampolinesImports.isEmpty) {
+ for (int i = 0; i < _instantiationTrampolines.length; i++) {
+ final exportName = _instantiationTrampolineImportNames[i];
+
+ translator.mainModule.exports
+ .export(exportName, _instantiationTrampolines[i]);
+ }
+ }
+ return _instantiationTrampolinesImports.putIfAbsent(module, () {
+ final importedTrampolines = <w.BaseFunction>[];
+ for (var i = 0; i < _instantiationTrampolines.length; i++) {
+ final importName = _instantiationTrampolineImportNames[i];
+ final function = _instantiationTrampolines[i];
+ importedTrampolines.add(module.functions.import(
+ translator.nameForModule(translator.mainModule),
+ importName,
+ function.type));
+ }
+ return importedTrampolines;
+ });
+ }
/// The function that instantiates this generic closure.
- late final w.BaseFunction instantiationFunction =
+ late final w.BaseFunction _instantiationFunction =
_instantiationFunctionThunk!();
w.BaseFunction Function()? _instantiationFunctionThunk;
+ final Map<w.ModuleBuilder, w.BaseFunction> _instantiationFunctionImports = {};
+ late final _instantiationFunctionExportName =
+ 'instantiationFunction-$exportSuffix';
+ w.BaseFunction instantiationFunctionForModule(
+ Translator translator, w.ModuleBuilder module) {
+ if (translator.isMainModule(module)) {
+ return _instantiationFunction;
+ }
+ if (_instantiationFunctionImports.isEmpty) {
+ translator.mainModule.exports
+ .export(_instantiationFunctionExportName, _instantiationFunction);
+ }
+ return _instantiationFunctionImports.putIfAbsent(module, () {
+ return module.functions.import(
+ translator.nameForModule(translator.mainModule),
+ _instantiationFunctionExportName,
+ _instantiationFunction.type);
+ });
+ }
/// The function that takes instantiation context of this generic closure and
/// another instantiation context (both as `ref
/// #InstantiationClosureContextBase`) and compares types in the contexts.
/// This function is used to implement function equality of instantiations.
- late final w.BaseFunction instantiationTypeComparisonFunction =
+ late final w.BaseFunction _instantiationTypeComparisonFunction =
_instantiationTypeComparisonFunctionThunk!();
w.BaseFunction Function()? _instantiationTypeComparisonFunctionThunk;
+ final Map<w.ModuleBuilder, w.BaseFunction>
+ _instantiationTypeComparisonFunctionImports = {};
+ late final _instantiationTypeComparisonExportName =
+ 'instantiationTypeComparison-$exportSuffix';
+ w.BaseFunction instantiationTypeComparisonFunctionForModule(
+ Translator translator, w.ModuleBuilder module) {
+ if (translator.isMainModule(module)) {
+ return _instantiationTypeComparisonFunction;
+ }
+ if (_instantiationTypeComparisonFunctionImports.isEmpty) {
+ translator.mainModule.exports.export(
+ _instantiationTypeComparisonExportName,
+ _instantiationTypeComparisonFunction);
+ }
+ return _instantiationTypeComparisonFunctionImports.putIfAbsent(module, () {
+ return module.functions.import(
+ translator.nameForModule(translator.mainModule),
+ _instantiationTypeComparisonExportName,
+ _instantiationTypeComparisonFunction.type);
+ });
+ }
- late final w.BaseFunction instantiationTypeHashFunction =
+ late final w.BaseFunction _instantiationTypeHashFunction =
_instantiationTypeHashFunctionThunk!();
w.BaseFunction Function()? _instantiationTypeHashFunctionThunk;
+ final Map<w.ModuleBuilder, w.BaseFunction>
+ _instantiationTypeHashFunctionImports = {};
+ late final _instantiationTypeHashExportName =
+ 'instantiationTypeHash-$exportSuffix';
+ w.BaseFunction instantiationTypeHashFunctionForModule(
+ Translator translator, w.ModuleBuilder module) {
+ if (translator.isMainModule(module)) {
+ return _instantiationTypeHashFunction;
+ }
+ if (_instantiationTypeHashFunctionImports.isEmpty) {
+ translator.mainModule.exports.export(
+ _instantiationTypeHashExportName, _instantiationTypeHashFunction);
+ }
+ return _instantiationTypeHashFunctionImports.putIfAbsent(module, () {
+ return module.functions.import(
+ translator.nameForModule(translator.mainModule),
+ _instantiationTypeHashExportName,
+ _instantiationTypeHashFunction.type);
+ });
+ }
/// The signature of the function that instantiates this generic closure.
w.FunctionType get instantiationFunctionType {
@@ -90,8 +186,13 @@
w.FunctionType getVtableFieldType(int index) =>
(vtableStruct.fields[index].type as w.RefType).heapType as w.FunctionType;
- ClosureRepresentation(this.typeCount, this.vtableStruct, this.closureStruct,
- this._indexOfCombination, this.instantiationContextStruct);
+ ClosureRepresentation(
+ this.typeCount,
+ this.vtableStruct,
+ this.closureStruct,
+ this._indexOfCombination,
+ this.instantiationContextStruct,
+ this.exportSuffix);
bool get isGeneric => typeCount > 0;
@@ -214,7 +315,7 @@
mutable: false)),
superType: vtableBaseStruct);
- /// Type of [ClosureRepresentation.instantiationTypeComparisonFunction].
+ /// Type of [ClosureRepresentation._instantiationTypeComparisonFunction].
late final w.FunctionType instantiationClosureTypeComparisonFunctionType =
translator.typesBuilder.defineFunction(
[
@@ -285,7 +386,6 @@
superType: superType);
}
- w.ModuleBuilder get m => translator.m;
w.ValueType get topType => translator.topInfo.nullableType;
ClosureLayouter(this.translator)
@@ -326,15 +426,16 @@
/// Get the representation for closures with a specific signature, described
/// by the number of type parameters, the maximum number of positional
/// parameters and the names of named parameters.
- ClosureRepresentation? getClosureRepresentation(
+ ClosureRepresentation? getClosureRepresentation(w.ModuleBuilder module,
int typeCount, int positionalCount, List<String> names) {
final representations =
_representationsForCounts(typeCount, positionalCount);
if (representations.withoutNamed == null) {
ClosureRepresentation? parent = positionalCount == 0
? null
- : getClosureRepresentation(typeCount, positionalCount - 1, const [])!;
- representations.withoutNamed = _createRepresentation(typeCount,
+ : getClosureRepresentation(
+ module, typeCount, positionalCount - 1, const [])!;
+ representations.withoutNamed = _createRepresentation(module, typeCount,
positionalCount, const [], parent, null, [positionalCount]);
}
@@ -344,6 +445,7 @@
representations.clusterForNames(names);
if (cluster == null) return null;
return cluster.representation ??= _createRepresentation(
+ module,
typeCount,
positionalCount,
names,
@@ -354,6 +456,7 @@
}
ClosureRepresentation _createRepresentation(
+ w.ModuleBuilder module,
int typeCount,
int positionalCount,
List<String> names,
@@ -375,7 +478,7 @@
if (typeCount > 0) {
// Add or set vtable field for the instantiation function.
instantiatedRepresentation =
- getClosureRepresentation(0, positionalCount, names)!;
+ getClosureRepresentation(module, 0, positionalCount, names)!;
w.RefType inputType = w.RefType.def(closureBaseStruct, nullable: false);
w.RefType outputType = w.RefType.def(
instantiatedRepresentation.closureStruct,
@@ -428,7 +531,8 @@
vtableStruct,
closureStruct,
indexOfCombination,
- instantiationContextStruct);
+ instantiationContextStruct,
+ nameTags.join('-'));
if (typeCount > 0) {
// The instantiation trampolines and the instantiation function can't be
@@ -440,7 +544,7 @@
representation._instantiationTrampolinesThunk = () {
List<w.BaseFunction> instantiationTrampolines = [
- ...?parent?.instantiationTrampolines
+ ...?parent?._instantiationTrampolines
];
String instantiationTrampolineFunctionName =
"${["#Instantiation", ...nameTags].join("-")} trampoline";
@@ -477,6 +581,7 @@
(positionalCount + 1) +
genericIndex)
: translator.globals.getDummyFunction(
+ translator.mainModule,
(instantiatedRepresentation
.vtableStruct
.fields[vtableBaseIndexNonGeneric +
@@ -493,9 +598,11 @@
String instantiationFunctionName =
["#Instantiation", ...nameTags].join("-");
return _createInstantiationFunction(
+ module,
typeCount,
instantiatedRepresentation!,
- representation.instantiationTrampolines,
+ representation._instantiationTrampolinesForModule(
+ translator, module),
representation.instantiationFunctionType,
instantiationContextStruct!,
closureStruct,
@@ -531,7 +638,8 @@
assert(genericFunctionType.inputs.length ==
instantiatedFunctionType.inputs.length + typeCount);
- final trampoline = m.functions.define(instantiatedFunctionType, name);
+ final trampoline =
+ translator.mainModule.functions.define(instantiatedFunctionType, name);
final b = trampoline.body;
// Cast context reference to actual context type.
@@ -573,9 +681,9 @@
return trampoline;
}
- w.BaseFunction _createInstantiationDynamicCallEntry(
+ w.BaseFunction _createInstantiationDynamicCallEntry(w.ModuleBuilder module,
int typeCount, w.StructType instantiationContextStruct) {
- final function = m.functions.define(
+ final function = module.functions.define(
translator.dynamicCallVtableEntryFunctionType,
"instantiation dynamic call entry");
final b = function.body;
@@ -625,6 +733,7 @@
}
w.BaseFunction _createInstantiationFunction(
+ w.ModuleBuilder module,
int typeCount,
ClosureRepresentation instantiatedRepresentation,
List<w.BaseFunction> instantiationTrampolines,
@@ -641,18 +750,19 @@
assert(functionType.outputs.single == instantiatedClosureType);
// Create vtable for the instantiated closure, containing the trampolines.
- final vtable = m.globals.define(w.GlobalType(
+ final vtable = module.globals.define(w.GlobalType(
w.RefType.def(instantiatedRepresentation.vtableStruct, nullable: false),
mutable: false));
final ib = vtable.initializer;
- ib.ref_func(_createInstantiationDynamicCallEntry(typeCount, contextStruct));
+ ib.ref_func(
+ _createInstantiationDynamicCallEntry(module, typeCount, contextStruct));
for (w.BaseFunction trampoline in instantiationTrampolines) {
ib.ref_func(trampoline);
}
ib.struct_new(instantiatedRepresentation.vtableStruct);
ib.end();
- final instantiationFunction = m.functions.define(functionType, name);
+ final instantiationFunction = module.functions.define(functionType, name);
final b = instantiationFunction.body;
w.Local preciseClosure = b.addLocal(genericClosureType);
@@ -674,7 +784,7 @@
}
b.struct_new(contextStruct);
- b.global_get(vtable);
+ translator.globals.readGlobal(b, vtable);
// Construct the type of the instantiated closure, which is the type of the
// original closure with the type arguments of the instantiation substituted
@@ -703,7 +813,7 @@
}
w.BaseFunction _createInstantiationTypeComparisonFunction(int numTypes) {
- final function = m.functions.define(
+ final function = translator.mainModule.functions.define(
instantiationClosureTypeComparisonFunctionType,
"#InstantiationTypeComparison-$numTypes");
@@ -752,7 +862,7 @@
}
w.BaseFunction _createInstantiationTypeHashFunction(int numTypes) {
- final function = m.functions.define(
+ final function = translator.mainModule.functions.define(
instantiationClosureTypeHashFunctionType,
"#InstantiationTypeHash-$numTypes");
@@ -770,7 +880,7 @@
// Same as `SystemHash.hashN` functions: combine first hash with
// `_hashSeed`.
- translator.globals.readGlobal(b, translator.hashSeed);
+ translator.callReference(translator.hashSeed.getterReference, b);
// Field 0 is the instantiated closure. Types start at 1.
for (int typeFieldIdx = 1; typeFieldIdx <= numTypes; typeFieldIdx += 1) {
@@ -1063,8 +1173,6 @@
: null;
}
- w.ModuleBuilder get m => translator.m;
-
late final w.ValueType typeType =
translator.classInfo[translator.typeClass]!.nonNullableType;
@@ -1153,8 +1261,6 @@
Translator get translator => closures.translator;
- w.ModuleBuilder get m => translator.m;
-
Source _currentSource;
@override
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 33314a0..cd2ca25 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -59,7 +59,7 @@
final Member enclosingMember;
// To be initialized in `generate()`
- late final w.InstructionsBuilder b;
+ late w.InstructionsBuilder b;
late final List<w.Local> paramLocals;
late final w.Label? returnLabel;
@@ -1991,12 +1991,7 @@
intrinsifier.generateStaticGetterIntrinsic(node);
if (intrinsicResult != null) return intrinsicResult;
- Member target = node.target;
- if (target is Field) {
- return translator.globals.readGlobal(b, target);
- } else {
- return translator.outputOrVoid(call(target.reference));
- }
+ return translator.outputOrVoid(call(node.targetReference));
}
@override
@@ -2010,39 +2005,20 @@
w.ValueType visitStaticSet(StaticSet node, w.ValueType expectedType) {
bool preserved = expectedType != voidMarker;
Member target = node.target;
- if (target is Field) {
- w.Global global = translator.globals.getGlobal(target);
- w.Global? flag = translator.globals.getGlobalInitializedFlag(target);
- wrap(node.value, global.type.type);
- b.global_set(global);
- if (flag != null) {
- b.i32_const(1); // true
- b.global_set(flag);
- }
- if (preserved) {
- b.global_get(global);
- return global.type.type;
- } else {
- return voidMarker;
- }
- } else {
- w.FunctionType targetFunctionType =
- translator.signatureForDirectCall(target.reference);
- w.ValueType paramType = targetFunctionType.inputs.single;
- wrap(node.value, paramType);
- w.Local? temp;
- if (preserved) {
- temp = addLocal(paramType);
- b.local_tee(temp);
- }
- call(target.reference);
- if (preserved) {
- b.local_get(temp!);
- return temp.type;
- } else {
- return voidMarker;
- }
+ w.ValueType paramType = target is Field
+ ? translator.globals.getGlobalForStaticField(target).type.type
+ : translator.signatureForDirectCall(target.reference).inputs.single;
+ wrap(node.value, paramType);
+ if (!preserved) {
+ call(node.targetReference);
+ return voidMarker;
}
+ w.Local temp = addLocal(paramType);
+ b.local_tee(temp);
+
+ call(node.targetReference);
+ b.local_get(temp);
+ return temp.type;
}
@override
@@ -2352,7 +2328,7 @@
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
pushContext();
- b.global_get(closure.vtable);
+ translator.globals.readGlobal(b, closure.vtable);
types.makeType(this, functionType);
b.struct_new(struct);
@@ -2368,7 +2344,8 @@
b.ref_as_non_null();
}
} else {
- b.global_get(translator.globals.dummyStructGlobal); // Dummy context
+ translator.globals
+ .readGlobal(b, translator.globals.dummyStructGlobal); // Dummy context
}
}
@@ -2394,7 +2371,7 @@
int posArgCount = arguments.positional.length;
List<String> argNames = arguments.named.map((a) => a.name).toList()..sort();
ClosureRepresentation? representation = translator.closureLayouter
- .getClosureRepresentation(typeCount, posArgCount, argNames);
+ .getClosureRepresentation(b.module, typeCount, posArgCount, argNames);
if (representation == null) {
// This is a dynamic function call with a signature that matches no
// functions in the program.
@@ -2466,7 +2443,8 @@
int posArgCount = type.positionalParameters.length;
List<String> argNames = type.namedParameters.map((a) => a.name).toList();
ClosureRepresentation representation = translator.closureLayouter
- .getClosureRepresentation(typeCount, posArgCount, argNames)!;
+ .getClosureRepresentation(
+ b.module, typeCount, posArgCount, argNames)!;
// Operand closure
w.RefType closureType =
@@ -3137,6 +3115,10 @@
if (member is Field) {
if (member.isStatic) {
+ if (reference.isImplicitGetter || reference.isImplicitSetter) {
+ return StaticFieldImplicitAccessorCodeGenerator(
+ translator, functionType, member, reference.isImplicitGetter);
+ }
return StaticFieldInitializerCodeGenerator(
translator, functionType, member);
}
@@ -3218,7 +3200,7 @@
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
b.local_get(paramLocals[0]); // `this` as context
- b.global_get(closure.vtable);
+ translator.globals.readGlobal(b, closure.vtable);
types.makeType(this, functionType);
b.struct_new(struct);
b.end();
@@ -3845,7 +3827,7 @@
closures.collectContexts(field);
closures.buildContexts();
- w.Global global = translator.globals.getGlobal(field);
+ w.Global global = translator.globals.getGlobalForStaticField(field);
w.Global? flag = translator.globals.getGlobalInitializedFlag(field);
wrap(field.initializer!, global.type.type);
b.global_set(global);
@@ -3860,6 +3842,64 @@
}
}
+class StaticFieldImplicitAccessorCodeGenerator extends AstCodeGenerator {
+ final Field field;
+ final bool isImplicitGetter;
+
+ StaticFieldImplicitAccessorCodeGenerator(Translator translator,
+ w.FunctionType functionType, this.field, this.isImplicitGetter)
+ : super(translator, functionType, field);
+
+ @override
+ void generateInternal() {
+ final global = translator.globals.getGlobalForStaticField(field);
+ final flag = translator.globals.getGlobalInitializedFlag(field);
+ if (isImplicitGetter) {
+ final initFunction =
+ translator.functions.getExistingFunction(field.fieldReference);
+ _generateGetter(global, flag, initFunction);
+ } else {
+ _generateSetter(global, flag);
+ }
+ b.end();
+ }
+
+ void _generateGetter(
+ w.Global global, w.Global? flag, w.BaseFunction? initFunction) {
+ if (initFunction == null) {
+ // Statically initialized
+ b.global_get(global);
+ } else {
+ if (flag != null) {
+ // Explicit initialization flag
+ assert(global.type.type == initFunction.type.outputs.single);
+ b.global_get(flag);
+ b.if_(const [], [global.type.type]);
+ b.global_get(global);
+ b.else_();
+ b.call(initFunction);
+ b.end();
+ } else {
+ // Null signals uninitialized
+ w.Label block = b.block(const [], [initFunction.type.outputs.single]);
+ b.global_get(global);
+ b.br_on_non_null(block);
+ b.call(initFunction);
+ b.end();
+ }
+ }
+ }
+
+ void _generateSetter(w.Global global, w.Global? flag) {
+ b.local_get(paramLocals.single);
+ b.global_set(global);
+ if (flag != null) {
+ b.i32_const(1); // true
+ b.global_set(flag);
+ }
+ }
+}
+
class ImplicitFieldAccessorCodeGenerator extends AstCodeGenerator {
final Field field;
final bool isImplicitGetter;
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 4fa57de..1dc5d58 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -26,6 +26,28 @@
ConstantInfo(this.constant, this.global, this.function);
bool get isLazy => function != null;
+
+ void _readGlobal(Translator translator, w.InstructionsBuilder b) {
+ translator.globals.readGlobal(b, global, importNameSuffix: 'constant');
+ }
+
+ w.ValueType readConstant(Translator translator, w.InstructionsBuilder b) {
+ final initFunction = function;
+ if (initFunction != null) {
+ // Lazily initialized constant.
+ w.ValueType type = global.type.type.withNullability(false);
+ w.Label done = b.block(const [], [type]);
+ _readGlobal(translator, b);
+ b.br_on_non_null(done);
+
+ translator.callFunction(initFunction, b);
+ b.end();
+ return type;
+ } else {
+ _readGlobal(translator, b);
+ return global.type.type;
+ }
+ }
}
typedef ConstantCodeGenerator = void Function(w.InstructionsBuilder);
@@ -82,7 +104,7 @@
Constants(this.translator);
- w.ModuleBuilder get m => translator.m;
+ // All constant constructs should go in the main module.
Types get types => translator.types;
CoreTypes get coreTypes => translator.coreTypes;
@@ -298,7 +320,6 @@
ConstantInstantiator(this.constants, this.b, this.expectedType);
Translator get translator => constants.translator;
- w.ModuleBuilder get m => translator.m;
void instantiate(Constant constant) {
w.ValueType resultType = constant.accept(this);
@@ -319,20 +340,7 @@
@override
w.ValueType defaultConstant(Constant constant) {
ConstantInfo info = ConstantCreator(constants).ensureConstant(constant)!;
- if (info.isLazy) {
- // Lazily initialized constant.
- w.ValueType type = info.global.type.type.withNullability(false);
- w.Label done = b.block(const [], [type]);
- b.global_get(info.global);
- b.br_on_non_null(done);
- b.call(info.function!);
- b.end();
- return type;
- } else {
- // Constant initialized eagerly in a global initializer.
- b.global_get(info.global);
- return info.global.type.type;
- }
+ return info.readConstant(translator, b);
}
@override
@@ -415,7 +423,6 @@
Translator get translator => constants.translator;
Types get types => translator.types;
- w.ModuleBuilder get m => constants.m;
Constant get _uninitializedHashBaseIndexConstant =>
(translator.uninitializedHashBaseIndex.initializer as ConstantExpression)
@@ -443,14 +450,16 @@
Constant constant, w.RefType type, ConstantCodeGenerator generator,
{bool lazy = false}) {
assert(!type.nullable);
+ final mainModule = translator.mainModule;
if (lazy) {
// Create uninitialized global and function to initialize it.
- final global = m.globals.define(w.GlobalType(type.withNullability(true)));
+ final global =
+ mainModule.globals.define(w.GlobalType(type.withNullability(true)));
global.initializer.ref_null(w.HeapType.none);
global.initializer.end();
w.FunctionType ftype =
translator.typesBuilder.defineFunction(const [], [type]);
- final function = m.functions.define(ftype, "$constant");
+ final function = mainModule.functions.define(ftype, "$constant");
final b2 = function.body;
generator(b2);
w.Local temp = b2.addLocal(type);
@@ -464,7 +473,8 @@
// Create global with the constant in its initializer.
assert(!constants.currentlyCreating);
constants.currentlyCreating = true;
- final global = m.globals.define(w.GlobalType(type, mutable: false));
+ final global =
+ mainModule.globals.define(w.GlobalType(type, mutable: false));
generator(global.initializer);
global.initializer.end();
constants.currentlyCreating = false;
@@ -513,7 +523,8 @@
return createConstant(constant, info.nonNullableType, (b) {
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
- b.global_get(translator.getInternalizedStringGlobal(constant.value));
+ b.global_get(
+ translator.getInternalizedStringGlobal(b.module, constant.value));
b.struct_new(info.struct);
});
}
@@ -536,11 +547,13 @@
w.DataSegmentBuilder segment;
Uint8List bytes;
if (isOneByte) {
- segment = constants.oneByteStringSegment ??= m.dataSegments.define();
+ segment = constants.oneByteStringSegment ??=
+ translator.mainModule.dataSegments.define();
bytes = Uint8List.fromList(constant.value.codeUnits);
} else {
assert(Endian.host == Endian.little);
- segment = constants.twoByteStringSegment ??= m.dataSegments.define();
+ segment = constants.twoByteStringSegment ??=
+ translator.mainModule.dataSegments.define();
bytes = Uint16List.fromList(constant.value.codeUnits)
.buffer
.asUint8List();
@@ -818,18 +831,24 @@
ClosureImplementation closure = translator.getTearOffClosure(member);
w.StructType struct = closure.representation.closureStruct;
w.RefType type = w.RefType.def(struct, nullable: false);
+
+ // The vtable for the target will be stored on a global in the target's
+ // module.
+ final isLazy = !translator
+ .isMainModule(translator.moduleForReference(constant.targetReference));
return createConstant(constant, type, (b) {
ClassInfo info = translator.closureInfo;
translator.functions.recordClassAllocation(info.classId);
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
- b.global_get(translator.globals.dummyStructGlobal); // Dummy context
- b.global_get(closure.vtable);
+ translator.globals
+ .readGlobal(b, translator.globals.dummyStructGlobal); // Dummy context
+ translator.globals.readGlobal(b, closure.vtable);
constants.instantiateConstant(
b, functionTypeConstant, types.nonNullableTypeType);
b.struct_new(struct);
- });
+ }, lazy: isLazy);
}
@override
@@ -840,6 +859,7 @@
.map((c) => ensureConstant(constants._lowerTypeConstant(c))!)
.toList();
Procedure tearOffProcedure = tearOffConstant.targetReference.asProcedure;
+ final module = translator.moduleForReference(tearOffProcedure.reference);
FunctionType tearOffFunctionType =
translator.getTearOffType(tearOffProcedure);
FunctionType instantiatedFunctionType =
@@ -855,16 +875,17 @@
tearOffConstant.function.namedParameters.map((p) => p.name!).toList();
ClosureRepresentation instantiationOfTearOffRepresentation = translator
.closureLayouter
- .getClosureRepresentation(0, positionalCount, names)!;
+ .getClosureRepresentation(module, 0, positionalCount, names)!;
ClosureRepresentation tearOffRepresentation = translator.closureLayouter
- .getClosureRepresentation(types.length, positionalCount, names)!;
+ .getClosureRepresentation(
+ module, types.length, positionalCount, names)!;
w.StructType struct = instantiationOfTearOffRepresentation.closureStruct;
w.RefType type = w.RefType.def(struct, nullable: false);
final tearOffConstantInfo = ensureConstant(tearOffConstant)!;
w.BaseFunction makeDynamicCallEntry() {
- final function = m.functions.define(
+ final function = module.functions.define(
translator.dynamicCallVtableEntryFunctionType, "dynamic call entry");
final b = function.body;
@@ -898,12 +919,12 @@
w.FunctionType signature, w.BaseFunction tearOffFunction) {
assert(tearOffFunction.type.inputs.length ==
signature.inputs.length + types.length);
- final function =
- m.functions.define(signature, "instantiation constant trampoline");
+ final function = module.functions
+ .define(signature, "instantiation constant trampoline");
final b = function.body;
b.local_get(function.locals[0]);
for (ConstantInfo typeInfo in types) {
- b.global_get(typeInfo.global);
+ typeInfo.readConstant(translator, b);
}
for (int i = 1; i < signature.inputs.length; i++) {
b.local_get(function.locals[i]);
@@ -926,17 +947,20 @@
// - non-generic closure / non-generic tear-off definitions
// - non-generic callers
// => We make a dummy entry which is unreachable.
- function = translator.globals.getDummyFunction(signature);
+ function = translator.globals
+ .getDummyFunction(translator.mainModule, signature);
} else {
final int tearOffFieldIndex = tearOffRepresentation
.fieldIndexForSignature(posArgCount, nameCombination.names);
w.BaseFunction tearOffFunction = tearOffClosure.functions[
tearOffFieldIndex - tearOffRepresentation.vtableBaseIndex];
- if (translator.globals.isDummyFunction(tearOffFunction)) {
+ if (translator.globals
+ .isDummyFunction(translator.mainModule, tearOffFunction)) {
// This name combination may not exist for the target, but got
// clustered together with other name combinations that do exist.
// => We make a dummy entry which is unreachable.
- function = translator.globals.getDummyFunction(signature);
+ function = translator.globals
+ .getDummyFunction(translator.mainModule, signature);
} else {
function = makeTrampoline(signature, tearOffFunction);
}
@@ -964,9 +988,10 @@
// Context is not used by the vtable functions, but it's needed for
// closure equality checks to work (`_Closure._equals`).
- b.global_get(tearOffConstantInfo.global);
+ tearOffConstantInfo.readConstant(translator, b);
+
for (final ty in types) {
- b.global_get(ty.global);
+ ty.readConstant(translator, b);
}
b.struct_new(tearOffRepresentation.instantiationContextStruct!);
diff --git a/pkg/dart2wasm/lib/functions.dart b/pkg/dart2wasm/lib/functions.dart
index a8d6d43..b7cfe85 100644
--- a/pkg/dart2wasm/lib/functions.dart
+++ b/pkg/dart2wasm/lib/functions.dart
@@ -228,12 +228,8 @@
@override
w.FunctionType visitField(Field node, Reference target) {
if (!node.isInstanceMember) {
- if (target == node.fieldReference) {
- // Static field initializer function
- return _makeFunctionType(translator, target, null);
- }
- String kind = target == node.setterReference ? "setter" : "getter";
- throw "No implicit $kind function for static field: $node";
+ // Static field initializer function or implicit getter/setter.
+ return _makeFunctionType(translator, target, null);
}
assert(!translator.dispatchTable
.selectorForTarget(target)
@@ -465,6 +461,19 @@
{bool isImportOrExport = false}) {
Member member = target.asMember;
+ if (member is Field && !member.isInstanceMember) {
+ final isGetter = target.isImplicitGetter;
+ final isSetter = target.isImplicitSetter;
+ if (isGetter || isSetter) {
+ final global = translator.globals.getGlobalForStaticField(member);
+ final globalType = global.type.type;
+ if (isGetter) {
+ return translator.typesBuilder.defineFunction(const [], [globalType]);
+ }
+ return translator.typesBuilder.defineFunction([globalType], const []);
+ }
+ }
+
// Translate types differently for imports and exports.
w.ValueType translateType(DartType type) => isImportOrExport
? translator.translateExternalType(type)
@@ -473,6 +482,7 @@
final List<w.ValueType> inputs = _getInputTypes(
translator, target, receiverType, isImportOrExport, translateType);
+ // Setters don't have an output with the exception of static implicit setters.
final bool emptyOutputList =
(member is Field && member.setterReference == target) ||
(member is Procedure && member.isSetter);
diff --git a/pkg/dart2wasm/lib/globals.dart b/pkg/dart2wasm/lib/globals.dart
index ae97c66..f5f64d2 100644
--- a/pkg/dart2wasm/lib/globals.dart
+++ b/pkg/dart2wasm/lib/globals.dart
@@ -12,15 +12,18 @@
class Globals {
final Translator translator;
- final Map<Field, w.Global> _globals = {};
+ final Map<Field, w.GlobalBuilder> _globals = {};
+ final Map<w.Global, w.BaseFunction> _globalGetters = {};
+ final Map<w.Global, w.BaseFunction> _globalSetters = {};
final Map<Field, w.BaseFunction> _globalInitializers = {};
final Map<Field, w.Global> _globalInitializedFlag = {};
- final Map<w.FunctionType, w.BaseFunction> _dummyFunctions = {};
+ final Map<(w.ModuleBuilder, w.FunctionType), w.BaseFunction> _dummyFunctions =
+ {};
final Map<w.HeapType, w.Global> _dummyValues = {};
+ final Map<w.Global, Map<w.ModuleBuilder, w.ImportedGlobal>> _importedGlobals =
+ {};
late final w.Global dummyStructGlobal;
- w.ModuleBuilder get m => translator.m;
-
Globals(this.translator) {
_initDummyValues();
}
@@ -29,7 +32,7 @@
// Create dummy struct for anyref/eqref/structref dummy values
w.StructType structType =
translator.typesBuilder.defineStruct("#DummyStruct");
- final dummyStructGlobalInit = m.globals.define(
+ final dummyStructGlobalInit = translator.mainModule.globals.define(
w.GlobalType(w.RefType.struct(nullable: false), mutable: false));
final ib = dummyStructGlobalInit.initializer;
ib.struct_new(structType);
@@ -42,9 +45,9 @@
/// Provide a dummy function with the given signature. Used for empty entries
/// in vtables and for dummy values of function reference type.
- w.BaseFunction getDummyFunction(w.FunctionType type) {
- return _dummyFunctions.putIfAbsent(type, () {
- final function = m.functions.define(type, "#dummy function $type");
+ w.BaseFunction getDummyFunction(w.ModuleBuilder module, w.FunctionType type) {
+ return _dummyFunctions.putIfAbsent((module, type), () {
+ final function = module.functions.define(type, "#dummy function $type");
final b = function.body;
b.unreachable();
b.end();
@@ -53,42 +56,46 @@
}
/// Returns whether the given function was provided by [getDummyFunction].
- bool isDummyFunction(w.BaseFunction function) {
- return _dummyFunctions[function.type] == function;
+ bool isDummyFunction(w.ModuleBuilder module, w.BaseFunction function) {
+ return _dummyFunctions[(module, function.type)] == function;
}
- w.Global? _prepareDummyValue(w.ValueType type) {
+ w.Global? _prepareDummyValue(w.ModuleBuilder module, w.ValueType type) {
if (type is w.RefType && !type.nullable) {
w.HeapType heapType = type.heapType;
- w.Global? foundGlobal = _dummyValues[heapType];
- if (foundGlobal != null) return foundGlobal;
- w.GlobalBuilder? global;
- if (heapType is w.DefType) {
- if (heapType is w.StructType) {
- for (w.FieldType field in heapType.fields) {
- _prepareDummyValue(field.type.unpacked);
+ return _dummyValues.putIfAbsent(heapType, () {
+ if (heapType is w.DefType) {
+ if (heapType is w.StructType) {
+ for (w.FieldType field in heapType.fields) {
+ _prepareDummyValue(module, field.type.unpacked);
+ }
+ final global =
+ module.globals.define(w.GlobalType(type, mutable: false));
+ final ib = global.initializer;
+ for (w.FieldType field in heapType.fields) {
+ instantiateDummyValue(ib, field.type.unpacked);
+ }
+ ib.struct_new(heapType);
+ ib.end();
+ return global;
+ } else if (heapType is w.ArrayType) {
+ final global =
+ module.globals.define(w.GlobalType(type, mutable: false));
+ final ib = global.initializer;
+ ib.array_new_fixed(heapType, 0);
+ ib.end();
+ return global;
+ } else if (heapType is w.FunctionType) {
+ final global =
+ module.globals.define(w.GlobalType(type, mutable: false));
+ final ib = global.initializer;
+ ib.ref_func(getDummyFunction(module, heapType));
+ ib.end();
+ return global;
}
- global = m.globals.define(w.GlobalType(type, mutable: false));
- final ib = global.initializer;
- for (w.FieldType field in heapType.fields) {
- instantiateDummyValue(ib, field.type.unpacked);
- }
- ib.struct_new(heapType);
- ib.end();
- } else if (heapType is w.ArrayType) {
- global = m.globals.define(w.GlobalType(type, mutable: false));
- final ib = global.initializer;
- ib.array_new_fixed(heapType, 0);
- ib.end();
- } else if (heapType is w.FunctionType) {
- global = m.globals.define(w.GlobalType(type, mutable: false));
- final ib = global.initializer;
- ib.ref_func(getDummyFunction(heapType));
- ib.end();
}
- _dummyValues[heapType] = global!;
- }
- return global;
+ throw 'Unexpected heapType: $heapType';
+ });
}
return null;
@@ -117,7 +124,7 @@
if (type.nullable) {
b.ref_null(heapType.bottomType);
} else {
- b.global_get(_prepareDummyValue(type)!);
+ readGlobal(b, _prepareDummyValue(b.module, type)!);
}
} else {
throw "Unsupported global type $type ($type)";
@@ -137,18 +144,100 @@
return null;
}
+ /// Reads the value of [w.Global] onto the stack in [b].
+ ///
+ /// Takes into account the calling module and the module the global belongs
+ /// to. If they are not the same then accesses the global indirectly, either
+ /// through an import or a getter call.
+ w.ValueType readGlobal(w.InstructionsBuilder b, w.Global global,
+ {String importNameSuffix = ''}) {
+ final owningModule = global.enclosingModule;
+ final callingModule = b.module;
+ if (owningModule == callingModule) {
+ b.global_get(global);
+ } else if (translator.isMainModule(owningModule)) {
+ final importedGlobals = _importedGlobals.putIfAbsent(global, () {
+ final importName = 'global$importNameSuffix${_importedGlobals.length}';
+ owningModule.exports.export(importName, global);
+ return {};
+ });
+ final importedGlobal = importedGlobals.putIfAbsent(callingModule, () {
+ return callingModule.globals.import(
+ translator.nameForModule(owningModule),
+ global.exportedName!,
+ global.type);
+ });
+
+ b.global_get(importedGlobal);
+ } else {
+ final getter = _globalGetters.putIfAbsent(global, () {
+ final getterType =
+ owningModule.types.defineFunction(const [], [global.type.type]);
+ final getterFunction = owningModule.functions.define(getterType);
+ final getterBody = getterFunction.body;
+ getterBody.global_get(global);
+ getterBody.end();
+ return getterFunction;
+ });
+
+ translator.callFunction(getter, b);
+ }
+ return global.type.type;
+ }
+
+ /// Sets the value of [w.Global] in [b].
+ ///
+ /// Takes into account the calling module and the module the global belongs
+ /// to. If they are not the same then sets the global indirectly, either
+ /// through an import or a setter call.
+ void updateGlobal(w.InstructionsBuilder b,
+ void Function(w.InstructionsBuilder b) pushValue, w.Global global) {
+ final owningModule = global.enclosingModule;
+ final callingModule = b.module;
+ if (owningModule == callingModule) {
+ pushValue(b);
+ b.global_set(global);
+ } else if (translator.isMainModule(owningModule)) {
+ final importName = 'global${_importedGlobals.length}';
+ final importedFunctions = _importedGlobals.putIfAbsent(global, () {
+ owningModule.exports.export(importName, global);
+ return {};
+ });
+ final importedGlobal = importedFunctions[b.module] ??= b.module.globals
+ .import(
+ translator.nameForModule(owningModule), importName, global.type);
+ pushValue(b);
+ b.global_set(importedGlobal);
+ } else {
+ final setter = _globalSetters.putIfAbsent(global, () {
+ final setterType =
+ owningModule.types.defineFunction([global.type.type], const []);
+ final setterFunction = owningModule.functions.define(setterType);
+ final setterBody = setterFunction.body;
+ setterBody.local_get(setterBody.locals.single);
+ setterBody.global_set(global);
+ setterBody.end();
+ return setterFunction;
+ });
+
+ pushValue(b);
+ translator.callFunction(setter, b);
+ }
+ }
+
/// Return (and if needed create) the Wasm global corresponding to a static
/// field.
- w.Global getGlobal(Field field) {
+ w.Global getGlobalForStaticField(Field field) {
assert(!field.isLate);
return _globals.putIfAbsent(field, () {
final Constant? init = _getConstantInitializer(field);
w.ValueType type = translator.translateTypeOfField(field);
+ final module = translator.moduleForReference(field.fieldReference);
if (init != null &&
!(translator.constants.ensureConstant(init)?.isLazy ?? false)) {
// Initialized to a constant
final global =
- m.globals.define(w.GlobalType(type, mutable: !field.isFinal));
+ module.globals.define(w.GlobalType(type, mutable: !field.isFinal));
translator.constants
.instantiateConstant(global.initializer, init, type);
global.initializer.end();
@@ -159,13 +248,13 @@
type = type.withNullability(true);
} else {
// Explicit initialization flag
- final flag = m.globals.define(w.GlobalType(w.NumType.i32));
+ final flag = module.globals.define(w.GlobalType(w.NumType.i32));
flag.initializer.i32_const(0);
flag.initializer.end();
_globalInitializedFlag[field] = flag;
}
- final global = m.globals.define(w.GlobalType(type));
+ final global = module.globals.define(w.GlobalType(type));
instantiateDummyValue(global.initializer, type);
global.initializer.end();
@@ -179,38 +268,8 @@
/// Return the Wasm global containing the flag indicating whether this static
/// field has been initialized, if such a flag global is needed.
///
- /// Note that [getGlobal] must have been called for the field beforehand.
+ /// Note that [getGlobalForStaticField] must have been called for the field beforehand.
w.Global? getGlobalInitializedFlag(Field variable) {
return _globalInitializedFlag[variable];
}
-
- /// Emit code to read a static field.
- w.ValueType readGlobal(w.InstructionsBuilder b, Field variable) {
- w.Global global = getGlobal(variable);
- w.BaseFunction? initFunction = _globalInitializers[variable];
- if (initFunction == null) {
- // Statically initialized
- b.global_get(global);
- return global.type.type;
- }
- w.Global? flag = _globalInitializedFlag[variable];
- if (flag != null) {
- // Explicit initialization flag
- assert(global.type.type == initFunction.type.outputs.single);
- b.global_get(flag);
- b.if_(const [], [global.type.type]);
- b.global_get(global);
- b.else_();
- b.call(initFunction);
- b.end();
- } else {
- // Null signals uninitialized
- w.Label block = b.block(const [], [initFunction.type.outputs.single]);
- b.global_get(global);
- b.br_on_non_null(block);
- b.call(initFunction);
- b.end();
- }
- return initFunction.type.outputs.single;
- }
}
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index f074a73..0bba712 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -1061,9 +1061,8 @@
StaticTearOffConstant func = f.constant as StaticTearOffConstant;
w.BaseFunction wasmFunction =
translator.functions.getFunction(func.targetReference);
- w.Global functionRef = translator.makeFunctionRef(wasmFunction);
- b.global_get(functionRef);
- return functionRef.type.type;
+ return translator.globals
+ .readGlobal(b, translator.makeFunctionRef(b.module, wasmFunction));
}
// Wasm(AnyRef|FuncRef|EqRef|StructRef|I32|I64|F32|F64) constructors
diff --git a/pkg/dart2wasm/lib/sync_star.dart b/pkg/dart2wasm/lib/sync_star.dart
index 70f6c4d..5bc2039 100644
--- a/pkg/dart2wasm/lib/sync_star.dart
+++ b/pkg/dart2wasm/lib/sync_star.dart
@@ -36,7 +36,8 @@
} else {
b.ref_null(w.HeapType.struct);
}
- b.global_get(translator.makeFunctionRef(resumeFun));
+ translator.globals
+ .readGlobal(b, translator.makeFunctionRef(b.module, resumeFun));
b.struct_new(syncStarIterableInfo.struct);
b.return_();
b.end();
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index 34676e6..012a4d32 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -129,7 +129,8 @@
/// Internalized strings to move to the JS runtime
final List<String> internalizedStringsForJSRuntime = [];
- final Map<String, w.Global> _internalizedStringGlobals = {};
+ final Map<(w.ModuleBuilder, String), w.Global> _internalizedStringGlobals =
+ {};
final Map<w.HeapType, ClassInfo> classForHeapType = {};
final Map<Field, int> fieldIndex = {};
@@ -568,6 +569,7 @@
if (type is FunctionType) {
ClosureRepresentation? representation =
closureLayouter.getClosureRepresentation(
+ mainModule,
type.typeParameters.length,
type.positionalParameters.length,
type.namedParameters.map((p) => p.name).toList());
@@ -631,9 +633,11 @@
return w.RefType.any(nullable: true);
}
- w.Global makeFunctionRef(w.BaseFunction f) {
+ /// Creates a global reference to [f] in [module]. [f] must also be located
+ /// in [module].
+ w.Global makeFunctionRef(w.ModuleBuilder module, w.BaseFunction f) {
return functionRefCache.putIfAbsent(f, () {
- final global = m.globals.define(
+ final global = module.globals.define(
w.GlobalType(w.RefType.def(f.type, nullable: false), mutable: false));
global.initializer.ref_func(f);
global.initializer.end();
@@ -652,6 +656,7 @@
ClosureImplementation getClosure(FunctionNode functionNode,
w.BaseFunction target, ParameterInfo paramInfo, String name) {
+ final targetModule = target.enclosingModule;
// The target function takes an extra initial parameter if it's a function
// expression / local function (which takes a context) or a tear-off of an
// instance method (which takes a receiver).
@@ -673,8 +678,9 @@
paramInfo.typeParamCount +
paramInfo.positional.length +
paramInfo.named.length);
- ClosureRepresentation representation = closureLayouter
- .getClosureRepresentation(typeCount, positionalCount, names)!;
+ ClosureRepresentation representation =
+ closureLayouter.getClosureRepresentation(
+ targetModule, typeCount, positionalCount, names)!;
assert(representation.vtableStruct.fields.length ==
representation.vtableBaseIndex +
(1 + positionalCount) +
@@ -728,7 +734,8 @@
w.BaseFunction makeTrampoline(
w.FunctionType signature, int posArgCount, List<String> argNames) {
- final trampoline = m.functions.define(signature, "$name trampoline");
+ final trampoline =
+ targetModule.functions.define(signature, "$name trampoline");
compilationQueue.add(CompilationTask(
trampoline,
_ClosureTrampolineGenerator(this, trampoline, target, typeCount,
@@ -737,7 +744,7 @@
}
w.BaseFunction makeDynamicCallEntry() {
- final function = m.functions.define(
+ final function = targetModule.functions.define(
dynamicCallVtableEntryFunctionType, "$name dynamic call entry");
compilationQueue.add(CompilationTask(
function,
@@ -754,21 +761,24 @@
w.FunctionType signature = representation.getVtableFieldType(fieldIndex);
w.BaseFunction function = canBeCalledWith(posArgCount, argNames)
? makeTrampoline(signature, posArgCount, argNames)
- : globals.getDummyFunction(signature);
+ : globals.getDummyFunction(ib.module, signature);
functions.add(function);
ib.ref_func(function);
}
- final vtable = m.globals.define(w.GlobalType(
+ final vtable = targetModule.globals.define(w.GlobalType(
w.RefType.def(representation.vtableStruct, nullable: false),
mutable: false));
final ib = vtable.initializer;
final dynamicCallEntry = makeDynamicCallEntry();
ib.ref_func(dynamicCallEntry);
if (representation.isGeneric) {
- ib.ref_func(representation.instantiationTypeComparisonFunction);
- ib.ref_func(representation.instantiationTypeHashFunction);
- ib.ref_func(representation.instantiationFunction);
+ ib.ref_func(representation.instantiationTypeComparisonFunctionForModule(
+ this, ib.module));
+ ib.ref_func(representation.instantiationTypeHashFunctionForModule(
+ this, ib.module));
+ ib.ref_func(
+ representation.instantiationFunctionForModule(this, ib.module));
}
for (int posArgCount = 0; posArgCount <= positionalCount; posArgCount++) {
fillVtableEntry(ib, posArgCount, const []);
@@ -780,7 +790,7 @@
ib.end();
return ClosureImplementation(
- representation, functions, dynamicCallEntry, vtable);
+ representation, functions, dynamicCallEntry, vtable, targetModule);
}
w.ValueType outputOrVoid(List<w.ValueType> outputs) {
@@ -1180,15 +1190,15 @@
ClassInfo getRecordClassInfo(RecordType recordType) =>
classInfo[recordClasses[RecordShape.fromType(recordType)]!]!;
- w.Global getInternalizedStringGlobal(String s) {
- w.Global? internalizedString = _internalizedStringGlobals[s];
+ w.Global getInternalizedStringGlobal(w.ModuleBuilder module, String s) {
+ w.Global? internalizedString = _internalizedStringGlobals[(module, s)];
if (internalizedString != null) {
return internalizedString;
}
final i = internalizedStringsForJSRuntime.length;
- internalizedString = m.globals.import('s', '$i',
+ internalizedString = module.globals.import('s', '$i',
w.GlobalType(w.RefType.extern(nullable: true), mutable: false));
- _internalizedStringGlobals[s] = internalizedString;
+ _internalizedStringGlobals[(module, s)] = internalizedString;
internalizedStringsForJSRuntime.add(s);
return internalizedString;
}
diff --git a/pkg/wasm_builder/lib/src/ir/global.dart b/pkg/wasm_builder/lib/src/ir/global.dart
index f56b9d3..c680809 100644
--- a/pkg/wasm_builder/lib/src/ir/global.dart
+++ b/pkg/wasm_builder/lib/src/ir/global.dart
@@ -10,6 +10,7 @@
final FinalizableIndex finalizableIndex;
final GlobalType type;
final ModuleBuilder enclosingModule;
+ String? exportedName;
/// Name of the global in the names section.
final String? globalName;
@@ -21,7 +22,11 @@
String toString() => globalName ?? "$finalizableIndex";
@override
- Export export(String name) => GlobalExport(name, this);
+ Export export(String name) {
+ assert(exportedName == null);
+ exportedName = name;
+ return GlobalExport(name, this);
+ }
}
/// A global variable defined in a module.