[dart2wasm] Move constants that are used by multiple modules out of main module
This reduces ACX gallery main module by 4.3%.
If a constant is used by multiple (non-main) modules this CL will
* force the constant to be lazy now
* make a global in the main module
* make each use lazily initialize with a module-local initializer
function (i.e. several modules may have the same initializer
function)
I plan on doing more optimizations for this multi-module constant
use scenario.
Change-Id: If5c6d5de474f9794415c889f0bd98465b73e4b96
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/458860
Reviewed-by: Ömer Ağacan <omersa@google.com>
Reviewed-by: Nate Biggs <natebiggs@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 257fbe3..f3b898a 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -26,13 +26,24 @@
const bool forceDelayedConstantDefinition = false;
class ConstantDefinition {
- final w.ModuleBuilder module;
final w.Global global;
final w.BaseFunction? _initFunction;
+ final Map<w.ModuleBuilder, w.BaseFunction>? _initFunctionPerUsingModule;
- ConstantDefinition(this.module, this.global, this._initFunction);
+ ConstantDefinition(
+ this.global, this._initFunction, this._initFunctionPerUsingModule) {
+ assert(_initFunction == null || _initFunctionPerUsingModule == null);
+ }
- bool get isLazy => _initFunction != null;
+ bool get isLazy =>
+ _initFunction != null || _initFunctionPerUsingModule != null;
+
+ w.BaseFunction initializer(w.ModuleBuilder usingModule) {
+ if (_initFunctionPerUsingModule != null) {
+ return _initFunctionPerUsingModule[usingModule]!;
+ }
+ return _initFunction!;
+ }
}
class ConstantInfo {
@@ -254,9 +265,10 @@
}
if (definition != null && !definition.isLazy) {
- if (definition.module == usingModule) return true;
- if (definition.module == baseModule) return true;
- if (definition.module == translator.mainModule) return true;
+ final definingModule = definition.global.enclosingModule;
+ if (definingModule == usingModule.module) return true;
+ if (definingModule == baseModule.module) return true;
+ if (definingModule == translator.mainModule.module) return true;
}
return false;
@@ -1532,19 +1544,6 @@
rememberConstantUse(info);
- // If we have uses in multiple modules, we should place it a module that is
- // guaranteed to be loaded at the use time of those modules.
- //
- // => We are conservative and assign it to the main module.
- //
- // NOTE: Improve this by finding the closest common ancestor between the
- // modules in the loading graph.
- if (!forceDelayedConstantDefinition && moduleUses[info]!.length > 1) {
- final definition =
- _defineConstantInModuleRecursive(translator.mainModule, info);
- return _readDefinedConstant(b, info, definition);
- }
-
// The current module is the only one using the constant atm, but in the
// future other modules may also use it. So we don't know where to place
// it just yet.
@@ -1573,7 +1572,8 @@
w.ValueType _readDefinedConstant(w.InstructionsBuilder b, ConstantInfo info,
ConstantDefinition definition) {
final globalDefinition = definition.global;
- final globalInitializer = definition._initFunction;
+ final globalInitializer =
+ definition.isLazy ? definition.initializer(b.moduleBuilder) : null;
// Eagerly initialized constant.
if (globalInitializer == null) {
@@ -1612,46 +1612,61 @@
//
// We want to choose a module that is available by the time the constant is
// used. If only one module uses the constant we place it in that module. If
- // it's used by multiple modules we (conservatively) place it in the main
- // module.
- //
- // NOTE: Improve this by finding the closest common ancestor between the
- // modules in the loading graph.
+ // it's used by multiple modules we make a global in the main module and
+ // make all using modules bring an initializer function with them.
+ Set<w.ModuleBuilder>? deferredUses;
if (assignedModule == null) {
final uses = moduleUses[info]!;
assert(uses.isNotEmpty);
- assignedModule = uses.length == 1 ? uses.single : translator.mainModule;
+ if (uses.length == 1) {
+ assignedModule = uses.single;
+ } else if (uses.contains(translator.mainModule)) {
+ assignedModule = translator.mainModule;
+ } else {
+ // Will become lazy constant with global in main module and initializer
+ // in all using modules.
+ deferredUses = uses;
+ }
}
- return _defineConstantInModule(assignedModule, info);
+ return _defineConstantInModule(assignedModule, deferredUses, info);
}
- ConstantDefinition _defineConstantInModule(
- w.ModuleBuilder targetModule, ConstantInfo info) {
+ ConstantDefinition _defineConstantInModule(w.ModuleBuilder? targetModule,
+ Set<w.ModuleBuilder>? deferredUses, ConstantInfo info) {
+ assert((targetModule != null) != (deferredUses != null));
+ assert(deferredUses == null ||
+ deferredUses.length > 1 &&
+ !deferredUses.contains(translator.mainModule));
+
final constant = info.constant;
// The constant itself may be forced to be lazy (e.g. array size too large).
bool lazy = !info.canBeEager;
+ // If there's uses in N different deferred modules, we make it lazy, define
+ // global in main module & initializer in each using module.
+ lazy |= deferredUses != null;
+
// The constant's children may influence laziness.
if (!lazy) {
for (final child in info.children) {
final definition = child._definition!;
// If the child is lazy, this constant becomes lazy.
- if (definition._initFunction != null) {
+ if (definition.isLazy) {
lazy = true;
break;
}
// If we place the constant in a module that may be loaded before the
// constants of children, it must get initialized lazily.
- final childModule = definition.module;
+ final childModule = definition.global.enclosingModule;
final baseModule = translator.isDynamicSubmodule
? translator.dynamicSubmodule
: translator.mainModule;
- if (childModule != targetModule &&
- childModule != translator.mainModule &&
- childModule != baseModule) {
+ if (childModule != targetModule?.module &&
+ childModule != translator.mainModule.module &&
+ childModule != baseModule.module) {
lazy = true;
break;
}
@@ -1663,17 +1678,28 @@
if (!lazy) {
// The constant codegen code may decide to make it lazy depending on which
// module it's going to be placed in.
- lazy = info._forceLazy(info, targetModule);
+ lazy = info._forceLazy(info, targetModule!);
}
// Define the lazy or non-lazy constant in the module.
final ConstantDefinition definition;
if (lazy) {
- final (global, initFunction) = _createLazyConstant(targetModule, info);
- definition = ConstantDefinition(targetModule, global, initFunction);
+ if (targetModule == null) {
+ final name = _constantName(info.constant);
+ final global = _createLazyGlobal(translator.mainModule, name, info);
+ final initFunctions = {
+ for (final usingModule in deferredUses!)
+ usingModule:
+ _createLazyInitializer(usingModule, global, name, info),
+ };
+ definition = ConstantDefinition(global, null, initFunctions);
+ } else {
+ final (global, initFunction) = _createLazyConstant(targetModule, info);
+ definition = ConstantDefinition(global, initFunction, null);
+ }
} else {
- final global = _createNonLazyConstant(targetModule, info);
- definition = ConstantDefinition(targetModule, global, null);
+ final global = _createNonLazyConstant(targetModule!, info);
+ definition = ConstantDefinition(global, null, null);
}
info.setDefinition(definition);
@@ -1681,7 +1707,7 @@
assert(translator.dynamicModuleSupportEnabled &&
!translator.isDynamicSubmodule);
translator.exporter.exportDynamicConstant(
- targetModule, constant, definition.global,
+ targetModule!, constant, definition.global,
initializer: definition._initFunction);
}
return definition;
@@ -1713,40 +1739,49 @@
globalName, fakeInitializer);
}
- info._definition =
- ConstantDefinition(fakeMainApp, fakeGlobal, fakeInitializer);
+ info._definition = ConstantDefinition(fakeGlobal, fakeInitializer, null);
}
(w.GlobalBuilder, w.FunctionBuilder) _createLazyConstant(
w.ModuleBuilder targetModule, ConstantInfo info) {
- final constant = info.constant;
- final type = info.type;
- final generator = info._codeGen;
+ final name = _constantName(info.constant);
- // Create uninitialized global and function to initialize it.
+ final definedGlobal = _createLazyGlobal(targetModule, name, info);
+ final initFunction =
+ _createLazyInitializer(targetModule, definedGlobal, name, info);
- final name = _constantName(constant);
- final globalType = w.GlobalType(type.withNullability(true));
- final definedGlobal = targetModule.globals.define(globalType, name);
+ return (definedGlobal, initFunction);
+ }
+
+ w.GlobalBuilder _createLazyGlobal(
+ w.ModuleBuilder module, String name, ConstantInfo info) {
+ final globalType = w.GlobalType(info.type.withNullability(true));
+ final definedGlobal = module.globals.define(globalType, name);
definedGlobal.initializer.ref_null(w.HeapType.none);
definedGlobal.initializer.end();
+ return definedGlobal;
+ }
+ w.FunctionBuilder _createLazyInitializer(w.ModuleBuilder module,
+ w.GlobalBuilder definedGlobal, String name, ConstantInfo info) {
+ final type = info.type;
final initFunctionType =
translator.typesBuilder.defineFunction(const [], [type]);
- final initFunction = targetModule.functions
- .define(initFunctionType, '$name (lazy initializer)}');
- final b2 = initFunction.body;
- generator(info, b2, true);
+ final initFunction =
+ module.functions.define(initFunctionType, '$name (lazy initializer)}');
+ final b = initFunction.body;
+ info._codeGen(info, b, true);
if (info.needsRuntimeCanonicalization) {
- final valueLocal = b2.addLocal(type);
- constant.accept(ConstantCanonicalizer(translator, b2, valueLocal));
+ final valueLocal = b.addLocal(type);
+ info.constant.accept(ConstantCanonicalizer(translator, b, valueLocal));
}
- w.Local temp = b2.addLocal(type);
- b2.local_tee(temp);
- b2.global_set(definedGlobal);
- b2.local_get(temp);
- b2.end();
- return (definedGlobal, initFunction);
+ w.Local temp = b.addLocal(type);
+ b.local_tee(temp);
+ translator.globals.writeGlobal(b, definedGlobal);
+ b.local_get(temp);
+ b.end();
+
+ return initFunction;
}
w.GlobalBuilder _createNonLazyConstant(
diff --git a/pkg/dart2wasm/lib/globals.dart b/pkg/dart2wasm/lib/globals.dart
index 5f3762e..5c8ae0f 100644
--- a/pkg/dart2wasm/lib/globals.dart
+++ b/pkg/dart2wasm/lib/globals.dart
@@ -72,6 +72,25 @@
return global.type.type;
}
+ /// Dual to [readGlobal]
+ void writeGlobal(w.InstructionsBuilder b, w.Global global) {
+ final owningModule = translator.moduleToBuilder[global.enclosingModule]!;
+ final callingModule = b.moduleBuilder;
+ if (owningModule == callingModule) {
+ b.global_set(global);
+ } else if (translator.isMainModule(owningModule)) {
+ final importedGlobal = _globalsModuleMap.get(global, callingModule);
+ b.global_set(importedGlobal);
+ } else {
+ // NOTE: Currently unused but we can support this just like in
+ // [readGlobal] via an indirect call to a setter function that's installed
+ // by the global-owning module.
+ throw UnsupportedError(
+ 'Currently we can only write to globals in the main module or in the '
+ 'local module in which the write happens.');
+ }
+ }
+
/// Return (and if needed create) the Wasm global corresponding to a static
/// field.
w.Global getGlobalForStaticField(Field field) {
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.dart b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.dart
new file mode 100644
index 0000000..b21780f
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.dart
@@ -0,0 +1,32 @@
+// Copyright (c) 2025, 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.
+
+// functionFilter=mainImpl
+// functionFilter=mod.*Use
+// functionFilter=MyConstClass
+// functionFilter=shared-const
+// tableFilter=static[0-9]+
+// globalFilter=MyConstClass
+// globalFilter=shared-const
+// type=MyConstClass
+// compilerOption=--enable-deferred-loading
+// compilerOption=--no-minify
+
+import 'deferred.constant.multi_module_use.h.0.dart' deferred as h0;
+import 'deferred.constant.multi_module_use.h.1.dart' deferred as h1;
+
+void main() async {
+ await h0.loadLibrary();
+ await h1.loadLibrary();
+
+ final returnShared = int.parse('1') == 0;
+ mainImpl(returnShared);
+}
+
+@pragma('wasm:never-inline')
+void mainImpl(bool returnShared) {
+ if (!identical(h0.modH0Use(returnShared), h1.modH1Use(returnShared))) {
+ throw 'bad';
+ }
+}
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.0.dart b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.0.dart
new file mode 100644
index 0000000..9f5a099
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.0.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2025, 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.
+
+import 'deferred.constant.multi_module_use.h.2.dart';
+
+@pragma('wasm:never-inline')
+MyConstClass modH0Use(bool nonShared) {
+ return nonShared
+ ? const MyConstClass('h0-nonshared-const')
+ : const MyConstClass('shared-const');
+}
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.1.dart b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.1.dart
new file mode 100644
index 0000000..b886989
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.1.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2025, 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.
+
+import 'deferred.constant.multi_module_use.h.2.dart';
+
+@pragma('wasm:never-inline')
+MyConstClass modH1Use(bool nonShared) {
+ return nonShared
+ ? const MyConstClass('h1-nonshared-const')
+ : const MyConstClass('shared-const');
+}
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.2.dart b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.2.dart
new file mode 100644
index 0000000..47f2914
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.2.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2025, 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.
+
+class MyConstClass {
+ final String b;
+ const MyConstClass(this.b);
+}
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.wat
new file mode 100644
index 0000000..36006f2
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.wat
@@ -0,0 +1,46 @@
+(module $module0
+ (type $#Top (struct
+ (field $field0 i32)))
+ (type $Object (sub $#Top (struct
+ (field $field0 i32)
+ (field $field1 (mut i32)))))
+ (type $JSStringImpl (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $_ref externref))))
+ (type $MyConstClass (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $b (ref $JSStringImpl)))))
+ (type $type1 (func
+ (param $var0 i32)
+ (result (ref $MyConstClass))))
+ (global $"C370 \"bad\"" (ref $JSStringImpl) <...>)
+ (global $"C489 \"shared-const\"" (mut (ref null $JSStringImpl))
+ (ref.null none))
+ (global $"C490 MyConstClass" (mut (ref null $MyConstClass))
+ (ref.null none))
+ (table $static0-0 (export "static0-0") 2 (ref null $type1))
+ (func $Error._throwWithCurrentStackTrace (param $var0 (ref $#Top)) <...>)
+ (func $"mainImpl <noInline>" (param $var0 i32)
+ (local $var1 (ref $MyConstClass))
+ i64.const 0
+ call $checkLibraryIsLoadedFromLoadId
+ local.get $var0
+ i32.const 0
+ call_indirect $static0-0 (param i32) (result (ref $MyConstClass))
+ i64.const 1
+ call $checkLibraryIsLoadedFromLoadId
+ local.get $var0
+ i32.const 1
+ call_indirect $static0-0 (param i32) (result (ref $MyConstClass))
+ ref.eq
+ i32.eqz
+ if
+ global.get $"C370 \"bad\""
+ call $Error._throwWithCurrentStackTrace
+ unreachable
+ end
+ )
+ (func $checkLibraryIsLoadedFromLoadId (param $var0 i64) <...>)
+)
\ No newline at end of file
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module1.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module1.wat
new file mode 100644
index 0000000..a1102cf
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module1.wat
@@ -0,0 +1,57 @@
+(module $module1
+ (type $#Top (struct
+ (field $field0 i32)))
+ (type $Object (sub $#Top (struct
+ (field $field0 i32)
+ (field $field1 (mut i32)))))
+ (type $JSStringImpl (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $_ref externref))))
+ (type $MyConstClass (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $b (ref $JSStringImpl)))))
+ (global $S.h1-nonshared-const (import "S" "h1-nonshared-const") (ref extern))
+ (global $S.shared-const (import "S" "shared-const") (ref extern))
+ (global $"C489 \"shared-const\"" (import "module0" "global0") (ref null $JSStringImpl))
+ (global $"C490 MyConstClass" (import "module0" "global1") (ref null $MyConstClass))
+ (global $"C488 MyConstClass" (ref $MyConstClass)
+ (i32.const 107)
+ (i32.const 0)
+ (i32.const 4)
+ (i32.const 0)
+ (global.get $S.h1-nonshared-const)
+ (struct.new $JSStringImpl)
+ (struct.new $MyConstClass))
+ (func $"modH1Use <noInline>" (param $var0 i32) (result (ref $MyConstClass))
+ (local $var1 (ref $JSStringImpl))
+ (local $var2 (ref $MyConstClass))
+ local.get $var0
+ if (result (ref $MyConstClass))
+ global.get $"C488 MyConstClass"
+ else
+ block $label0 (result (ref $MyConstClass))
+ global.get $"C490 MyConstClass"
+ br_on_non_null $label0
+ i32.const 107
+ i32.const 0
+ block $label1 (result (ref $JSStringImpl))
+ global.get $"C489 \"shared-const\""
+ br_on_non_null $label1
+ i32.const 4
+ i32.const 0
+ global.get $S.shared-const
+ struct.new $JSStringImpl
+ local.tee $var1
+ global.set $"C489 \"shared-const\""
+ local.get $var1
+ end $label1
+ struct.new $MyConstClass
+ local.tee $var2
+ global.set $"C490 MyConstClass"
+ local.get $var2
+ end $label0
+ end
+ )
+)
\ No newline at end of file
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module2.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module2.wat
new file mode 100644
index 0000000..e7a7378
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module2.wat
@@ -0,0 +1,2 @@
+(module $module2
+)
\ No newline at end of file
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module3.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module3.wat
new file mode 100644
index 0000000..7b5e2cc
--- /dev/null
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module3.wat
@@ -0,0 +1,57 @@
+(module $module3
+ (type $#Top (struct
+ (field $field0 i32)))
+ (type $Object (sub $#Top (struct
+ (field $field0 i32)
+ (field $field1 (mut i32)))))
+ (type $JSStringImpl (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $_ref externref))))
+ (type $MyConstClass (sub final $Object (struct
+ (field $field0 i32)
+ (field $field1 (mut i32))
+ (field $b (ref $JSStringImpl)))))
+ (global $S.shared-const (import "S" "shared-const") (ref extern))
+ (global $"C489 \"shared-const\"" (import "module0" "global0") (ref null $JSStringImpl))
+ (global $"C490 MyConstClass" (import "module0" "global1") (ref null $MyConstClass))
+ (global $S.h0-nonshared-const (import "S" "h0-nonshared-const") (ref extern))
+ (global $"C492 MyConstClass" (ref $MyConstClass)
+ (i32.const 107)
+ (i32.const 0)
+ (i32.const 4)
+ (i32.const 0)
+ (global.get $S.h0-nonshared-const)
+ (struct.new $JSStringImpl)
+ (struct.new $MyConstClass))
+ (func $"modH0Use <noInline>" (param $var0 i32) (result (ref $MyConstClass))
+ (local $var1 (ref $JSStringImpl))
+ (local $var2 (ref $MyConstClass))
+ local.get $var0
+ if (result (ref $MyConstClass))
+ global.get $"C492 MyConstClass"
+ else
+ block $label0 (result (ref $MyConstClass))
+ global.get $"C490 MyConstClass"
+ br_on_non_null $label0
+ i32.const 107
+ i32.const 0
+ block $label1 (result (ref $JSStringImpl))
+ global.get $"C489 \"shared-const\""
+ br_on_non_null $label1
+ i32.const 4
+ i32.const 0
+ global.get $S.shared-const
+ struct.new $JSStringImpl
+ local.tee $var1
+ global.set $"C489 \"shared-const\""
+ local.get $var1
+ end $label1
+ struct.new $MyConstClass
+ local.tee $var2
+ global.set $"C490 MyConstClass"
+ local.get $var2
+ end $label0
+ end
+ )
+)
\ No newline at end of file
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant_module1.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant_module1.wat
index c63406b..07affdc 100644
--- a/pkg/dart2wasm/test/ir_tests/deferred.constant_module1.wat
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant_module1.wat
@@ -6,6 +6,8 @@
(type $Array<_Type> <...>)
(type $JSStringImpl <...>)
(type $type20 <...>)
+ (type $_TopType <...>)
+ (type $Array<_NamedParameter> <...>)
(type $_FunctionType <...>)
(type $#ClosureBase <...>)
(type $#Vtable-0-1 <...>)
@@ -23,8 +25,12 @@
(func $print (import "module0" "func5") (param (ref null $#Top)) (result (ref null $#Top)))
(func $JSStringImpl._interpolate (import "module0" "func6") (param (ref $Array<Object?>)) (result (ref $JSStringImpl)))
(global $"C21 \")\"" (import "module0" "global0") (ref $JSStringImpl))
- (global $"C28 _InterfaceType" (import "module0" "global5") (ref $_InterfaceType))
- (global $"C455 _FunctionType" (import "module0" "global7") (ref $_FunctionType))
+ (global $"C1 WasmArray<_Type>[0]" (import "module0" "global1") (ref $Array<_Type>))
+ (global $"C331 _TopType" (import "module0" "global2") (ref $_TopType))
+ (global $"C62 WasmArray<_Type>[1]" (import "module0" "global3") (ref $Array<_Type>))
+ (global $"C306 WasmArray<_NamedParameter>[0]" (import "module0" "global4") (ref $Array<_NamedParameter>))
+ (global $"C455 _FunctionType" (import "module0" "global5") (ref null $_FunctionType))
+ (global $"C28 _InterfaceType" (import "module0" "global8") (ref $_InterfaceType))
(global $S.globalH1Bar< (import "S" "globalH1Bar<") (ref extern))
(global $global7 (ref $#Vtable-1-1) <...>)
(global $global4 (ref $#DummyStruct) <...>)
@@ -97,8 +103,9 @@
(func $instantiation constant trampoline (param $var0 (ref struct)) (param $var1 (ref null $#Top)) (result (ref null $#Top)) <...>)
(func $"C462 H1 (lazy initializer)}" (result (ref $H1))
(local $var0 (ref $#Closure-1-1))
- (local $var1 (ref $#Closure-0-1))
- (local $var2 (ref $H1))
+ (local $var1 (ref $_FunctionType))
+ (local $var2 (ref $#Closure-0-1))
+ (local $var3 (ref $H1))
i32.const 105
i32.const 0
block $label0 (result (ref $#Closure-0-1))
@@ -125,15 +132,32 @@
ref.func $"#dummy function (ref struct) -> (ref null #Top)"
ref.func $"instantiation constant trampoline"
struct.new $#Vtable-0-1
- global.get $"C455 _FunctionType"
+ block $label2 (result (ref $_FunctionType))
+ global.get $"C455 _FunctionType"
+ br_on_non_null $label2
+ i32.const 12
+ i32.const 0
+ i32.const 0
+ i64.const 0
+ global.get $"C1 WasmArray<_Type>[0]"
+ global.get $"C1 WasmArray<_Type>[0]"
+ global.get $"C331 _TopType"
+ global.get $"C62 WasmArray<_Type>[1]"
+ i64.const 1
+ global.get $"C306 WasmArray<_NamedParameter>[0]"
+ struct.new $_FunctionType
+ local.tee $var1
+ global.set $"C455 _FunctionType"
+ local.get $var1
+ end $label2
struct.new $#Closure-0-1
- local.tee $var1
+ local.tee $var2
global.set $"C461 InstantiationConstant(globalH1Foo<int>)"
- local.get $var1
+ local.get $var2
end $label0
struct.new $H1
- local.tee $var2
+ local.tee $var3
global.set $"C462 H1"
- local.get $var2
+ local.get $var3
)
)
\ No newline at end of file
diff --git a/pkg/dart2wasm/test/ir_tests/deferred.constant_module2.wat b/pkg/dart2wasm/test/ir_tests/deferred.constant_module2.wat
index 3326c9e..0743efa 100644
--- a/pkg/dart2wasm/test/ir_tests/deferred.constant_module2.wat
+++ b/pkg/dart2wasm/test/ir_tests/deferred.constant_module2.wat
@@ -4,6 +4,7 @@
(type $Array<Object?> <...>)
(type $JSStringImpl <...>)
(type $Array<_Type> <...>)
+ (type $Array<_NamedParameter> <...>)
(type $_FunctionType <...>)
(type $#ClosureBase <...>)
(type $#Vtable-0-1 <...>)
@@ -13,8 +14,13 @@
(field $field1 (mut i32))
(field $fun (ref $#Closure-0-1)))))
(type $#DummyStruct <...>)
+ (type $_TopType <...>)
(func $print (import "module0" "func5") (param (ref null $#Top)) (result (ref null $#Top)))
- (global $"C455 _FunctionType" (import "module0" "global7") (ref $_FunctionType))
+ (global $"C1 WasmArray<_Type>[0]" (import "module0" "global1") (ref $Array<_Type>))
+ (global $"C331 _TopType" (import "module0" "global2") (ref $_TopType))
+ (global $"C62 WasmArray<_Type>[1]" (import "module0" "global3") (ref $Array<_Type>))
+ (global $"C306 WasmArray<_NamedParameter>[0]" (import "module0" "global4") (ref $Array<_NamedParameter>))
+ (global $"C455 _FunctionType" (import "module0" "global5") (ref null $_FunctionType))
(global $S.globalH0Foo (import "S" "globalH0Foo") (ref extern))
(global $global6 (ref $#Vtable-0-1) <...>)
(global $global3 (ref $#DummyStruct) <...>)
@@ -40,8 +46,9 @@
call $print
)
(func $"C466 H0 (lazy initializer)}" (result (ref $H0))
- (local $var0 (ref $#Closure-0-1))
- (local $var1 (ref $H0))
+ (local $var0 (ref $_FunctionType))
+ (local $var1 (ref $#Closure-0-1))
+ (local $var2 (ref $H0))
i32.const 106
i32.const 0
block $label0 (result (ref $#Closure-0-1))
@@ -51,15 +58,32 @@
i32.const 0
global.get $global3
global.get $global6
- global.get $"C455 _FunctionType"
+ block $label1 (result (ref $_FunctionType))
+ global.get $"C455 _FunctionType"
+ br_on_non_null $label1
+ i32.const 12
+ i32.const 0
+ i32.const 0
+ i64.const 0
+ global.get $"C1 WasmArray<_Type>[0]"
+ global.get $"C1 WasmArray<_Type>[0]"
+ global.get $"C331 _TopType"
+ global.get $"C62 WasmArray<_Type>[1]"
+ i64.const 1
+ global.get $"C306 WasmArray<_NamedParameter>[0]"
+ struct.new $_FunctionType
+ local.tee $var0
+ global.set $"C455 _FunctionType"
+ local.get $var0
+ end $label1
struct.new $#Closure-0-1
- local.tee $var0
+ local.tee $var1
global.set $"C465 globalH0Foo tear-off"
- local.get $var0
+ local.get $var1
end $label0
struct.new $H0
- local.tee $var1
+ local.tee $var2
global.set $"C466 H0"
- local.get $var1
+ local.get $var2
)
)
\ No newline at end of file