From 4bc9d3195737b93f7a34684916c09a49333d72bc Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Tue, 4 Nov 2025 00:33:45 -0800 Subject: [PATCH] [dart2wasm] Move constants that are used by multiple modules out of main module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Nate Biggs Commit-Queue: Martin Kustermann --- pkg/dart2wasm/lib/constants.dart | 157 +++++++++++------- pkg/dart2wasm/lib/globals.dart | 19 +++ .../deferred.constant.multi_module_use.dart | 32 ++++ ...eferred.constant.multi_module_use.h.0.dart | 12 ++ ...eferred.constant.multi_module_use.h.1.dart | 12 ++ ...eferred.constant.multi_module_use.h.2.dart | 8 + .../deferred.constant.multi_module_use.wat | 46 +++++ ...rred.constant.multi_module_use_module1.wat | 57 +++++++ ...rred.constant.multi_module_use_module2.wat | 2 + ...rred.constant.multi_module_use_module3.wat | 57 +++++++ .../ir_tests/deferred.constant_module1.wat | 42 ++++- .../ir_tests/deferred.constant_module2.wat | 40 ++++- 12 files changed, 406 insertions(+), 78 deletions(-) create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.dart create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.0.dart create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.1.dart create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.h.2.dart create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use.wat create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module1.wat create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module2.wat create mode 100644 pkg/dart2wasm/test/ir_tests/deferred.constant.multi_module_use_module3.wat diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart index 257fbe37398..f3b898ab8c6 100644 --- a/pkg/dart2wasm/lib/constants.dart +++ b/pkg/dart2wasm/lib/constants.dart @@ -26,13 +26,24 @@ const int maxArrayNewFixedLength = 10000; const bool forceDelayedConstantDefinition = false; class ConstantDefinition { - final w.ModuleBuilder module; final w.Global global; final w.BaseFunction? _initFunction; + final Map? _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 @@ class Constants { } 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 @@ class _ConstantAccessor { 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 @@ class _ConstantAccessor { 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 @@ class _ConstantAccessor { // // 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? 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? 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 @@ class _ConstantAccessor { 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 @@ class _ConstantAccessor { 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 @@ class _ConstantAccessor { 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 5f3762ef0f7..5c8ae0f0ba2 100644 --- a/pkg/dart2wasm/lib/globals.dart +++ b/pkg/dart2wasm/lib/globals.dart @@ -72,6 +72,25 @@ class Globals { 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 00000000000..b21780fd3fb --- /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 00000000000..9f5a09999eb --- /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 00000000000..b8869894e71 --- /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 00000000000..47f29149ccb --- /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 00000000000..36006f27221 --- /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 " (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 00000000000..a1102cf8bda --- /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 " (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 00000000000..e7a73780556 --- /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 00000000000..7b5e2ccbdf9 --- /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 " (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 c63406b6257..07affdcc11f 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)) (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)" - 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 3326c9ed266..0743efaac66 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 <...>) (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