@@ -17,9 +17,6 @@ class CallbackSpecializer {
17
17
CallbackSpecializer (
18
18
this ._staticTypeContext, this ._util, this ._methodCollector);
19
19
20
- bool _needsArgumentsLength (FunctionType type) =>
21
- type.requiredParameterCount < type.positionalParameters.length;
22
-
23
20
Statement _generateDispatchCase (
24
21
FunctionType function,
25
22
VariableDeclaration callbackVariable,
@@ -54,12 +51,11 @@ class CallbackSpecializer {
54
51
/// Creates a callback trampoline for the given [function] .
55
52
///
56
53
/// This callback trampoline expects a Dart callback as its first argument,
57
- /// then an integer value(double type) indicating the position of the last
58
- /// defined argument(only for callbacks that take optional parameters),
59
- /// followed by all of the arguments to the Dart callback as JS objects. The
60
- /// trampoline will `dartifyRaw` or box all incoming JS objects and then cast
61
- /// them to their appropriate types, dispatch, and then `jsifyRaw` or box any
62
- /// returned value.
54
+ /// then an integer value(double type) indicating the number of arguments
55
+ /// passed, followed by all of the arguments to the Dart callback as JS
56
+ /// objects. The trampoline will `dartifyRaw` or box all incoming JS objects
57
+ /// and then cast them to their appropriate types, dispatch, and then
58
+ /// `jsifyRaw` or box any returned value.
63
59
///
64
60
/// Returns a [String] function name representing the name of the wrapping
65
61
/// function.
@@ -69,20 +65,18 @@ class CallbackSpecializer {
69
65
// arguments will be JS objects. The generated wrapper will cast each
70
66
// argument to the correct type. The first argument to this function will
71
67
// be the Dart callback, which will be cast to the supplied [FunctionType]
72
- // before being invoked. If the callback takes optional parameters then, the
73
- // second argument will be a `double` indicating the last defined argument .
68
+ // before being invoked. The second argument will be a `double` indicating
69
+ // the number of arguments passed .
74
70
int parameterId = 1 ;
75
71
final callbackVariable = VariableDeclaration ('callback' ,
76
72
type: _util.nonNullableObjectType, isSynthesized: true );
77
- VariableDeclaration ? argumentsLength;
78
- if (_needsArgumentsLength (function)) {
79
- argumentsLength = VariableDeclaration ('argumentsLength' ,
80
- type: _util.coreTypes.doubleNonNullableRawType, isSynthesized: true );
81
- }
73
+ final argumentsLength = VariableDeclaration ('argumentsLength' ,
74
+ type: _util.coreTypes.doubleNonNullableRawType, isSynthesized: true );
82
75
83
76
// Initialize variable declarations.
84
77
List <VariableDeclaration > positionalParameters = [];
85
- for (int j = 0 ; j < function.positionalParameters.length; j++ ) {
78
+ final positionalParametersLength = function.positionalParameters.length;
79
+ for (int j = 0 ; j < positionalParametersLength; j++ ) {
86
80
positionalParameters.add (VariableDeclaration ('x${parameterId ++}' ,
87
81
type: _util.nullableWasmExternRefType, isSynthesized: true ));
88
82
}
@@ -91,26 +85,42 @@ class CallbackSpecializer {
91
85
// find the last defined argument in JS, that is the last argument which was
92
86
// explicitly passed by the user, and then we dispatch to a Dart function
93
87
// with the right number of arguments.
94
- //
95
- // First we handle cases where some or all arguments are undefined.
96
- // TODO(joshualitt): Consider using a switch instead.
97
88
List <Statement > dispatchCases = [];
98
- for (int i = function.requiredParameterCount + 1 ;
99
- i <= function.positionalParameters.length;
100
- i++ ) {
89
+ // If more arguments were passed than there are parameters, ignore the extra
90
+ // arguments.
91
+ dispatchCases.add (IfStatement (
92
+ _util.variableGreaterThanOrEqualToConstant (
93
+ argumentsLength, IntConstant (positionalParametersLength)),
94
+ _generateDispatchCase (function, callbackVariable, positionalParameters,
95
+ positionalParametersLength,
96
+ boxExternRef: boxExternRef),
97
+ null ));
98
+ // TODO(srujzs): Consider using a switch instead.
99
+ for (int i = positionalParametersLength - 1 ;
100
+ i >= function.requiredParameterCount;
101
+ i-- ) {
101
102
dispatchCases.add (IfStatement (
102
103
_util.variableCheckConstant (
103
- argumentsLength! , DoubleConstant (i.toDouble ())),
104
+ argumentsLength, DoubleConstant (i.toDouble ())),
104
105
_generateDispatchCase (
105
106
function, callbackVariable, positionalParameters, i,
106
107
boxExternRef: boxExternRef),
107
108
null ));
108
109
}
109
110
110
- // Finally handle the case where only required parameters are passed.
111
- dispatchCases.add (_generateDispatchCase (function, callbackVariable,
112
- positionalParameters, function.requiredParameterCount,
113
- boxExternRef: boxExternRef));
111
+ // Throw since we have too few arguments. Alternatively, we can continue
112
+ // checking lengths and try to call the callback, which will then throw, but
113
+ // that's unnecessary extra code. Note that we can't exclude this and assume
114
+ // the last dispatch case will catch this. Since arguments that are not
115
+ // passed are `undefined` and `undefined` gets converted to `null`, they may
116
+ // be treated as valid `null` arguments to the Dart function even though
117
+ // they were never passed.
118
+ dispatchCases.add (ExpressionStatement (Throw (StringConcatenation ([
119
+ StringLiteral ('Too few arguments passed. '
120
+ 'Expected ${function .requiredParameterCount } or more, got ' ),
121
+ invokeMethod (argumentsLength, _util.numToIntTarget),
122
+ StringLiteral (' instead.' )
123
+ ]))));
114
124
Statement functionTrampolineBody = Block (dispatchCases);
115
125
116
126
// Create a new procedure for the callback trampoline. This procedure will
@@ -124,8 +134,9 @@ class CallbackSpecializer {
124
134
FunctionNode (functionTrampolineBody,
125
135
positionalParameters: [
126
136
callbackVariable,
127
- if (argumentsLength != null ) argumentsLength
128
- ].followedBy (positionalParameters).toList (),
137
+ argumentsLength,
138
+ ...positionalParameters
139
+ ],
129
140
returnType: _util.nullableWasmExternRefType)
130
141
..fileOffset = node.fileOffset,
131
142
node.fileUri,
@@ -144,11 +155,7 @@ class CallbackSpecializer {
144
155
jsParameters.add ('x$i ' );
145
156
}
146
157
String jsParametersString = jsParameters.join (',' );
147
- String dartArguments = 'f' ;
148
- bool needsArguments = _needsArgumentsLength (type);
149
- if (needsArguments) {
150
- dartArguments = '$dartArguments ,arguments.length' ;
151
- }
158
+ String dartArguments = 'f,arguments.length' ;
152
159
if (jsParameters.isNotEmpty) {
153
160
dartArguments = '$dartArguments ,$jsParametersString ' ;
154
161
}
@@ -171,24 +178,12 @@ class CallbackSpecializer {
171
178
// Create JS method.
172
179
// Note: We have to use a regular function for the inner closure in some
173
180
// cases because we need access to `arguments`.
174
- if (needsArguments) {
175
- _methodCollector.addMethod (
176
- dartProcedure,
177
- jsMethodName,
178
- "f => finalizeWrapper(f, function($jsParametersString ) {"
179
- " return dartInstance.exports.$functionTrampolineName ($dartArguments ) "
180
- "})" );
181
- } else {
182
- if (parametersNeedParens (jsParameters)) {
183
- jsParametersString = '($jsParametersString )' ;
184
- }
185
- _methodCollector.addMethod (
186
- dartProcedure,
187
- jsMethodName,
188
- "f => "
189
- "finalizeWrapper(f,$jsParametersString => "
190
- "dartInstance.exports.$functionTrampolineName ($dartArguments ))" );
191
- }
181
+ _methodCollector.addMethod (
182
+ dartProcedure,
183
+ jsMethodName,
184
+ "f => finalizeWrapper(f, function($jsParametersString ) {"
185
+ " return dartInstance.exports.$functionTrampolineName ($dartArguments ) "
186
+ "})" );
192
187
193
188
return dartProcedure;
194
189
}
@@ -207,6 +202,9 @@ class CallbackSpecializer {
207
202
/// these Dart functions flow to JS, they are replaced by their wrappers. If
208
203
/// the wrapper should ever flow back into Dart then it will be replaced by
209
204
/// the original Dart function.
205
+ // TODO(srujzs): It looks like there's no more code that references this
206
+ // function anymore in dart2wasm. Should we delete this lowering and related
207
+ // code?
210
208
Expression allowInterop (StaticInvocation staticInvocation) {
211
209
final argument = staticInvocation.arguments.positional.single;
212
210
final type = argument.getStaticType (_staticTypeContext) as FunctionType ;
0 commit comments