Description
For historical reasons, dart2js does not make much distinction between instance method calls and dynamic calls. In Dart 1, all instance calls where effectively dynamic calls. Now the vast majority of calls are not dynamic so we should consider compiling dynamic calls differently.
dart2js uses code of the form a.b()
for both instance calls and dynamic calls for selectors that do not use the interceptor calling convention. For example, this method:
demo(dynamic x, dynamic y) {
print(x.difference(y));
print(x.intersection(y));
}
compiles the calls differently because intersection
is defined for JavaScript DOMRect, but difference
is not defined on any type that is not declared as an ordinary Dart class.
demo(x, y) {
A.print(x.difference$1(y));
A.print(getInterceptor(x).intersection$1(x, y));
}
We can minify intersection$1
to anything we like since all JavaScript calls have a receiver that we control.
We currently have to be careful with minifying difference$1
. For example, we can't choose at
, since String.prototype.at
is defined and will return some value rather than crashing with a TypeError
that can be understood as a NoSuchMethodError
.
This problem could be solved by using the interceptor calling convention for dynamic calls, but that comes at a cost of making all methods that can be called from dynamic calls compatible the more cumbersome interceptor calling convention.
One could use different selector for dynamic calls. This selector would be for the 'dynamic entry point' which could, in spec mode, contain checks on all parameters.
When there are no checks over those required for the instance call entry point (e.g. Set.difference
could have been written to require parametric covariance check) the dynamic selector could just be an alias.
To avoid collisions with the JavaScript environment, the dynamic selector could be a JavaScript symbol x[dynamicSelectors.intersection$1](y)
.
One downside of having dynamic and instance entry-points is that functions, including tear-offs, need them too.
Tearing-off a method that passes to a dynamic closure call implies the need for dynamic checking of the arguments.
Most tearoffs would appear to escape to a potential dynamic closure call.