Files
sdk/tests/web/wasm/table_test.dart
Martin Kustermann b8b0cad67a [dart2wasm] Make most void functions have no return values
This gives around 0.2% improvement in compressed e main module.

In Dart a function with `void` return type can actually return values
that callers can observe. But most of the time this doesn't happen, most
times those functions return `null` values and callers don't observe
them.

Let's use inferred return value information to see if a function is
guaranteed to only return `null`. If so we make the wasm function
signature not return any values. Callers will then synthesize a `null`
which may immediatly be dropped or (in rare cases) actually be used.

This leads to less less instructions in the callee (as a callee doesn't
need to push the null onto the stack) and the caller (as the caller
doesn't have to drop it from the stack).

Change-Id: I3ed1be7592798ad0c697c5bc3ab2c4b64c156f03
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/497620
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
2026-04-28 00:20:02 -07:00

71 lines
2.2 KiB
Dart

// Copyright (c) 2022, 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=--extra-compiler-option=--enable-experimental-wasm-interop
import 'dart:_wasm';
import 'package:expect/expect.dart';
WasmTable<WasmFuncRef?> funcrefTable = WasmTable(3);
WasmTable<WasmFunction<WasmI32 Function(WasmI32)>?> funcTable = WasmTable(1);
WasmVoid f1() => WasmVoid();
WasmVoid f2(WasmI32 x) {
Expect.equals(4, x.toIntSigned());
return WasmVoid();
}
WasmI32 f3(WasmI32 x) => x + 1.toWasmI32();
main() {
// Initialize untyped function table
Expect.equals(3, funcrefTable.size.toIntUnsigned());
funcrefTable[0.toWasmI32()] = WasmFunction.fromFunction(f1);
funcrefTable[1.toWasmI32()] = WasmFunction.fromFunction(f2);
funcrefTable[2.toWasmI32()] = WasmFunction.fromFunction(f3);
// Reading and calling functions in untyped function table
WasmFunction<WasmVoid Function()>.fromFuncRef(
funcrefTable[0.toWasmI32()]!,
).call();
WasmFunction<WasmVoid Function(WasmI32)>.fromFuncRef(
funcrefTable[1.toWasmI32()]!,
).call(4.toWasmI32());
Expect.equals(
6,
WasmFunction<WasmI32 Function(WasmI32)>.fromFuncRef(
funcrefTable[2.toWasmI32()]!,
).call(5.toWasmI32()).toIntSigned(),
);
// Calling functions in untyped function table with callIndirect
funcrefTable.callIndirect<WasmVoid Function()>(0.toWasmI32())();
funcrefTable.callIndirect<WasmVoid Function(WasmI32)>(1.toWasmI32())(
4.toWasmI32(),
);
Expect.equals(
16,
funcrefTable
.callIndirect<WasmI32 Function(WasmI32)>(2.toWasmI32())(15.toWasmI32())
.toIntSigned(),
);
// Initialize typed function table
Expect.equals(1, funcTable.size.toIntUnsigned());
funcTable[0.toWasmI32()] = WasmFunction.fromFunction(f3);
// Reading and calling function in typed function table
Expect.equals(8, funcTable[0.toWasmI32()]!.call(7.toWasmI32()).toIntSigned());
// Calling function in typed function table with callIndirect
Expect.equals(
18,
funcTable
.callIndirect<WasmI32 Function(WasmI32)>(0.toWasmI32())(17.toWasmI32())
.toIntSigned(),
);
}