[dart2wasm] Fix signature selection for direct closure invocation.

Direct closure invocation on tearoffs was using the signature of the raw
member reference rather than the checked entry function. These don't
always have the same signature and therefore it was possible to generate
an invalid code by putting the incorrect # of parameters on the stack.

The added test fails prior to this fix when assertions are enabled.

Also include some small changes that helped with debugging this.

Change-Id: I8c50dca3999781213ea251c6ab97eb1eaf7d0c8b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/467500
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Nate Biggs <natebiggs@google.com>
This commit is contained in:
Nate Biggs
2025-12-11 00:32:20 -08:00
committed by Commit Queue
parent bac67ee558
commit e8b8ecfd52
4 changed files with 55 additions and 5 deletions
+2 -1
View File
@@ -127,7 +127,8 @@ class CompilerPhaseInputOutputManager {
final wasmOptPath = options.wasmOptPath?.toFilePath() ?? 'wasm-opt';
final result = await _runProcess(wasmOptPath, args);
if (result.exitCode != 0) {
throw Exception('wasm-opt failed with exit code ${result.exitCode}:'
throw Exception(
'wasm-opt failed on module $inputModuleName with exit code ${result.exitCode}:'
'\n${result.stdout}\n${result.stderr}');
}
}
+5 -2
View File
@@ -1695,10 +1695,13 @@ class Translator with KernelNodes {
return null;
}
final entryReference =
getFunctionEntry(member.reference, uncheckedEntry: false);
return SingleClosureTarget._(
member,
paramInfoForDirectCall(member.reference),
signatureForDirectCall(member.reference),
paramInfoForDirectCall(entryReference),
signatureForDirectCall(entryReference),
null,
);
} else {
+12 -2
View File
@@ -72,6 +72,7 @@ VM_ARGS=()
DART2WASM_ARGS=("--require-js-string-builtin")
DART_FILE=""
OUTPUT_FILE=""
PHASES=""
while [ $# -gt 0 ]; do
case "$1" in
--compile-benchmark=*)
@@ -102,6 +103,11 @@ while [ $# -gt 0 ]; do
shift
;;
--phases=*)
PHASES="${1#--phases=}"
shift
;;
--extra-compiler-option=--platform=*)
PLATFORM_FILENAME="${1#--extra-compiler-option=--platform=}"
shift
@@ -156,6 +162,10 @@ if [ -z "$DART_FILE" -o -z "$OUTPUT_FILE" ]; then
exit 1
fi
if [ -z "$PHASES" ]; then
PHASES="cfe,tfa,codegen"
fi
PLATFORM_ARG="--platform=$PLATFORM_FILENAME"
DART2WASM_AOT_SNAPSHOT="$BIN_DIR/$SNAPSHOT_NAME.snapshot"
@@ -192,9 +202,9 @@ COMPILER_GZIP_SIZE=0
function run_compiler() {
if [ $RUN_SRC -eq 1 ]; then
dart2wasm_command=("$DART" "${VM_ARGS[@]}" "$DART2WASM_SRC" "$LIBRARIES_JSON_ARG" "${DART2WASM_ARGS[@]}" "--phases=cfe,tfa,codegen" "$DART_FILE" "$OUTPUT_FILE")
dart2wasm_command=("$DART" "${VM_ARGS[@]}" "$DART2WASM_SRC" "$LIBRARIES_JSON_ARG" "${DART2WASM_ARGS[@]}" "--phases=$PHASES" "$DART_FILE" "$OUTPUT_FILE")
else
dart2wasm_command=("$DART_AOT_RUNTIME" "${VM_ARGS[@]}" "$DART2WASM_AOT_SNAPSHOT" "$PLATFORM_ARG" "${DART2WASM_ARGS[@]}" "--phases=cfe,tfa,codegen" "$DART_FILE" "$OUTPUT_FILE")
dart2wasm_command=("$DART_AOT_RUNTIME" "${VM_ARGS[@]}" "$DART2WASM_AOT_SNAPSHOT" "$PLATFORM_ARG" "${DART2WASM_ARGS[@]}" "--phases=$PHASES" "$DART_FILE" "$OUTPUT_FILE")
fi
if [ -n "$COMPILE_BENCHMARK_BASE_NAME" ]; then
@@ -0,0 +1,36 @@
// 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 Arg {}
abstract class Base<T> {
void foo(T a);
}
class A extends Base<Arg> {
@override
void foo(Arg a, [String? b]) {
print(a);
print(b);
}
}
class B extends A {
@override
void foo(Arg a, [String? b, int c = 0]) {
print(a);
print(b);
print(c);
}
}
void check(void Function(Arg) closure) {
closure(Arg());
}
void main() {
final closure = A().foo;
check(closure);
B().foo(Arg(), 'b', 3);
}