[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>
This commit is contained in:
committed by
Commit Queue
parent
090b7cbe40
commit
4bc9d31957
@@ -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<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 @@ 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<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 @@ 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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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');
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) <...>)
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,2 @@
|
||||
(module $module2
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
@@ -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
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user