[dart2wasm] Fix @pragma('wasm:initialize-at-startup') in deferred loading scenario
The module owning the storage for the static field has to emit the initialization code in it's start function. Change-Id: I9089e99d6e12ea275343cebe3e456658a7c7a540 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/485480 Reviewed-by: Nate Biggs <natebiggs@google.com> Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
committed by
Commit Queue
parent
c421bc9df2
commit
2c8f4300d0
@@ -650,8 +650,9 @@ class DynamicModuleInfo {
|
||||
}
|
||||
|
||||
void finishDynamicModule() {
|
||||
_registerModuleRefs(
|
||||
isSubmodule ? initFunction.body : translator.initFunction.body);
|
||||
_registerModuleRefs(isSubmodule
|
||||
? initFunction.body
|
||||
: translator.mainModule.startFunction.body);
|
||||
}
|
||||
|
||||
void _registerModuleRefs(w.InstructionsBuilder b) {
|
||||
|
||||
@@ -160,15 +160,11 @@ class DartGlobals {
|
||||
final definition =
|
||||
_defineGlobalBasedField(field, fieldType, module, true, init, null);
|
||||
|
||||
if (module.module == translator.initFunction.enclosingModule) {
|
||||
// We have to initialize the global field in the same module as where
|
||||
// the field value is defined in.
|
||||
// TODO: Once dynamic modules only compile code for the submodule and
|
||||
// not the main module, we should turn this into an assert.
|
||||
EagerStaticFieldInitializerCodeGenerator(
|
||||
translator, field, definition.global)
|
||||
.generate(translator.initFunction.body, [], null);
|
||||
}
|
||||
// We have to initialize the global field in the same module as where
|
||||
// the field value is defined in.
|
||||
EagerStaticFieldInitializerCodeGenerator(
|
||||
translator, field, definition.global)
|
||||
.generate(module.startFunction.body, [], null);
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
@@ -247,7 +247,6 @@ class Translator with KernelNodes {
|
||||
final Set<Member> membersContainingInnerFunctions = {};
|
||||
final Set<Member> membersBeingGenerated = {};
|
||||
final Map<Reference, Closures> constructorClosures = {};
|
||||
late final w.FunctionBuilder initFunction;
|
||||
late final w.ValueType voidMarker =
|
||||
w.RefType.def(w.StructType("void"), nullable: true);
|
||||
// Lazily import FFI memory if used.
|
||||
@@ -595,8 +594,6 @@ class Translator with KernelNodes {
|
||||
Map<ModuleMetadata, w.Module> translate(
|
||||
Uri Function(String moduleName)? sourceMapUrlGenerator) {
|
||||
_initModules(sourceMapUrlGenerator);
|
||||
initFunction = mainModule.startFunction;
|
||||
|
||||
closureLayouter.collect();
|
||||
classInfoCollector.collect();
|
||||
|
||||
@@ -637,7 +634,7 @@ class Translator with KernelNodes {
|
||||
}
|
||||
});
|
||||
}
|
||||
_printFunction(initFunction, "init");
|
||||
_printFunction(mainModule.startFunction, "init");
|
||||
|
||||
// Remove empty modules.
|
||||
_outputToBuilder.removeWhere((outputModule, moduleBuilder) {
|
||||
|
||||
@@ -64,6 +64,7 @@ void main(List<String> args) async {
|
||||
'pkg/dart2wasm/tool/compile_benchmark',
|
||||
for (final option in compilerOptions) '--extra-compiler-option=$option',
|
||||
'--extra-compiler-option=--no-unique-constant-names',
|
||||
'--extra-compiler-option=--enable-experimental-wasm-interop',
|
||||
if (runFromSource) '--src',
|
||||
'--no-strip-wasm',
|
||||
'-o',
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright (c) 2026, 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=write|read|#init
|
||||
// tableFilter=cross-module-funcs
|
||||
// globalFilter=array
|
||||
// typeFilter=NoMatch
|
||||
// compilerOption=--enable-deferred-loading
|
||||
// compilerOption=--no-minify
|
||||
|
||||
import 'dart:_wasm';
|
||||
|
||||
import '' deferred as D;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void main() async {
|
||||
await D.loadLibrary();
|
||||
|
||||
D.write();
|
||||
Expect.equals('hello', D.read());
|
||||
}
|
||||
|
||||
void write() => array[0] = 'hello';
|
||||
String read() => array[0]!;
|
||||
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
final WasmArray<String?> array = WasmArray<String?>(1);
|
||||
@@ -0,0 +1,34 @@
|
||||
(module $module0
|
||||
(type $#Top <...>)
|
||||
(type $Array<String> <...>)
|
||||
(type $Array<WasmI16> <...>)
|
||||
(type $Array<int> <...>)
|
||||
(type $JSExternWrapper <...>)
|
||||
(type $Object <...>)
|
||||
(table $cross-module-funcs-0 (export "cross-module-funcs-0") 3 funcref)
|
||||
(global $"\"1.0\"" (ref $JSExternWrapper) <...>)
|
||||
(global $BoxedDouble._cacheKeys (mut (ref $Array<int>)) <...>)
|
||||
(global $BoxedDouble._cacheValues (mut (ref $Array<String>)) <...>)
|
||||
(global $JSStringImpl._stringFromCodePointBuffer (mut (ref $Array<WasmI16>)) <...>)
|
||||
(global $_deletedDataMarker (mut (ref $#Top)) <...>)
|
||||
(elem $cross-module-funcs-0
|
||||
(set 2 (ref.func $"_TypeError._throwNullCheckErrorWithCurrentStack <noInline>")))
|
||||
(func $_TypeError._throwNullCheckErrorWithCurrentStack <noInline> (result (ref none)) <...>)
|
||||
(func $#init
|
||||
global.get $"\"1.0\""
|
||||
i32.const 16
|
||||
array.new $Array<String>
|
||||
global.set $BoxedDouble._cacheValues
|
||||
i64.const 4607182418800017408
|
||||
i32.const 16
|
||||
array.new $Array<int>
|
||||
global.set $BoxedDouble._cacheKeys
|
||||
i32.const 2
|
||||
array.new_default $Array<WasmI16>
|
||||
global.set $JSStringImpl._stringFromCodePointBuffer
|
||||
i32.const 1
|
||||
i32.const 0
|
||||
struct.new $Object
|
||||
global.set $_deletedDataMarker
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,37 @@
|
||||
(module $module1
|
||||
(type $#Top <...>)
|
||||
(type $Array<String?> <...>)
|
||||
(type $JSExternWrapper <...>)
|
||||
(global $"\"hello\"" (import "module0" "global0") (ref $JSExternWrapper))
|
||||
(table $module0.cross-module-funcs-0 (import "module0" "cross-module-funcs-0") 3 funcref)
|
||||
(global $array (mut (ref $Array<String?>))
|
||||
(array.new_fixed $Array<String?> 0))
|
||||
(elem $module0.cross-module-funcs-0
|
||||
(set 0 (ref.func $write))
|
||||
(set 1 (ref.func $read)))
|
||||
(func $#init
|
||||
i32.const 1
|
||||
array.new_default $Array<String?>
|
||||
global.set $array
|
||||
)
|
||||
(func $read (result (ref $JSExternWrapper))
|
||||
block $label0 (result (ref $JSExternWrapper))
|
||||
global.get $array
|
||||
i32.const 0
|
||||
array.get $Array<String?>
|
||||
br_on_non_null $label0
|
||||
i32.const 2
|
||||
call_indirect (result (ref none))
|
||||
unreachable
|
||||
end $label0
|
||||
)
|
||||
(func $write (result (ref null $#Top))
|
||||
(local $var0 (ref $JSExternWrapper))
|
||||
global.get $array
|
||||
i32.const 0
|
||||
global.get $"\"hello\""
|
||||
local.tee $var0
|
||||
array.set $Array<String?>
|
||||
local.get $var0
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2026, 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.
|
||||
//
|
||||
// dart2wasmOptions=--enable-deferred-loading --extra-compiler-option=--enable-experimental-wasm-interop
|
||||
|
||||
import 'dart:_wasm';
|
||||
|
||||
import '' deferred as D;
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void main() async {
|
||||
await D.loadLibrary();
|
||||
|
||||
D.write();
|
||||
Expect.equals('hello', D.read());
|
||||
}
|
||||
|
||||
void write() => array[0] = 'hello';
|
||||
String read() => array[0]!;
|
||||
|
||||
@pragma("wasm:initialize-at-startup")
|
||||
final WasmArray<String?> array = WasmArray<String?>(1);
|
||||
Reference in New Issue
Block a user