Skip to content

Commit 6c5d3fb

Browse files
osa1Commit Queue
authored andcommitted
[dart2wasm] Pass arg counts from JS to Dart as i32
The JS code we generate for converting a Dart function to a function callable from JS currently looks like this: _194: f => finalizeWrapper(f, function(x0,x1) { return dartInstance.exports._194(f,arguments.length,x0,x1) }), `_194` called by this JS code is an export: (func $_194 (;296;) (export "_194") (param $callback (;0;) anyref) (param $argumentsLength (;1;) f64) (param $x1 (;2;) externref) (param $x2 (;3;) externref) (result externref) ...) Here the `double` parameter current causing redundant boxing and slow `BoxedDouble` operations, because it's compared against an `int` values when checking whether the right number of arguments is passed to the Dart function: (in the body of `$_194`, unoptimized) local.get $argumentsLength local.set $var5 i32.const 75 local.get $var5 struct.new $BoxedDouble global.get $global664 call $BoxedDouble.>= ... We could compare it against double values instead of int to improve this, but a better way is to make `argumentsLength` an `i32`, as the argument will always be a small integer (smi), which can be passed without allocation, so that's what we do in this CL. The same code with this CL: (unoptimized) (func $_194 (;294;) (export "_194") (param $callback (;0;) anyref) (param $argumentsLengthWasmI32 (;1;) i32) (param $x1 (;2;) externref) (param $x2 (;3;) externref) (result externref) ... local.get $argumentsLengthWasmI32 i64.extend_i32_s local.set $argumentsLength local.get $argumentsLength i64.const 2 i64.ge_s ...) Change-Id: Ib9d4d625bea896e8b680e7e5bffc02c19db0d3cf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/423740 Reviewed-by: Srujan Gaddam <[email protected]> Commit-Queue: Ömer Ağacan <[email protected]>
1 parent 2d588d0 commit 6c5d3fb

File tree

2 files changed

+30
-7
lines changed

2 files changed

+30
-7
lines changed

pkg/dart2wasm/lib/js/callback_specializer.dart

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class CallbackSpecializer {
6161
/// Creates a callback trampoline for the given [function].
6262
///
6363
/// This callback trampoline expects a Dart callback as its first argument,
64-
/// then an integer value(double type) indicating the number of arguments
64+
/// then an integer value (as `WasmI32`) indicating the number of arguments
6565
/// passed, then a "cast closure" if needed, followed by all of the arguments
6666
/// to the Dart callback as JS objects. Depending on [boxExternRef], the
6767
/// trampoline will `dartifyRaw` or box all incoming JS objects and then cast
@@ -81,8 +81,9 @@ class CallbackSpecializer {
8181
// needed.
8282
final callbackVariable = VariableDeclaration('callback',
8383
type: _util.nonNullableObjectType, isSynthesized: true);
84-
final argumentsLength = VariableDeclaration('argumentsLength',
85-
type: _util.coreTypes.doubleNonNullableRawType, isSynthesized: true);
84+
final argumentsLengthWasmI32 = VariableDeclaration('argumentsLengthWasmI32',
85+
type: InterfaceType(_util.wasmI32Class, Nullability.nonNullable),
86+
isSynthesized: true);
8687
final castClosure = VariableDeclaration('castClosure',
8788
type: _util.nonNullableObjectType, isSynthesized: true);
8889

@@ -104,6 +105,24 @@ class CallbackSpecializer {
104105
// explicitly passed by the user, and then we dispatch to a Dart function
105106
// with the right number of arguments.
106107
List<Statement> body = [];
108+
109+
// Convert `WasmI32` argument to Dart `int`.
110+
final argumentsLength = VariableDeclaration('argumentsLength',
111+
type: _util.coreTypes.intNonNullableRawType,
112+
isSynthesized: true,
113+
initializer: InstanceInvocation(
114+
InstanceAccessKind.Instance,
115+
VariableGet(
116+
argumentsLengthWasmI32,
117+
),
118+
Name('toIntSigned'),
119+
Arguments([]),
120+
interfaceTarget: _util.wasmI32ToIntSigned,
121+
functionType:
122+
_util.wasmI32ToIntSigned.computeSignatureOrFunctionType()));
123+
124+
body.add(argumentsLength);
125+
107126
if (castClosureArguments.isNotEmpty) {
108127
// Call the cast closure, but only if the arity is okay. In the case where
109128
// the arity is not sufficient, we end up coercing `undefined` to `null`,
@@ -133,8 +152,7 @@ class CallbackSpecializer {
133152
i >= function.requiredParameterCount;
134153
i--) {
135154
body.add(IfStatement(
136-
_util.variableCheckConstant(
137-
argumentsLength, DoubleConstant(i.toDouble())),
155+
_util.variableCheckConstant(argumentsLength, IntConstant(i)),
138156
_generateDispatchCase(
139157
function, callbackVariable, positionalParameters, i,
140158
boxExternRef: boxExternRef),
@@ -151,7 +169,7 @@ class CallbackSpecializer {
151169
body.add(ExpressionStatement(Throw(StringConcatenation([
152170
StringLiteral('Too few arguments passed. '
153171
'Expected ${function.requiredParameterCount} or more, got '),
154-
invokeMethod(argumentsLength, _util.numToIntTarget),
172+
VariableGet(argumentsLength),
155173
StringLiteral(' instead.')
156174
]))));
157175
Statement functionTrampolineBody = Block(body);
@@ -167,7 +185,7 @@ class CallbackSpecializer {
167185
FunctionNode(functionTrampolineBody,
168186
positionalParameters: [
169187
callbackVariable,
170-
argumentsLength,
188+
argumentsLengthWasmI32,
171189
if (castClosureArguments.isNotEmpty) castClosure,
172190
...positionalParameters
173191
],

pkg/dart2wasm/lib/js/util.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class CoreTypesUtil {
3333
final Procedure wrapDartFunctionTarget;
3434
final Procedure exportWasmFunctionTarget;
3535
final Member wasmExternRefNullRef;
36+
final Class wasmI32Class;
37+
final Procedure wasmI32ToIntSigned;
3638

3739
// Dart value to JS converters.
3840
final Procedure toJSBoolean;
@@ -124,6 +126,9 @@ class CoreTypesUtil {
124126
wasmArrayClass = coreTypes.index.getClass('dart:_wasm', 'WasmArray'),
125127
wasmArrayRefClass =
126128
coreTypes.index.getClass('dart:_wasm', 'WasmArrayRef'),
129+
wasmI32Class = coreTypes.index.getClass('dart:_wasm', 'WasmI32'),
130+
wasmI32ToIntSigned = coreTypes.index
131+
.getProcedure('dart:_wasm', 'WasmI32', 'toIntSigned'),
127132
wrapDartFunctionTarget = coreTypes.index
128133
.getTopLevelProcedure('dart:_js_helper', '_wrapDartFunction'),
129134
exportWasmFunctionTarget = coreTypes.index

0 commit comments

Comments
 (0)