[jsinterop] fix lowering of callMethod unchecked calls.

The lowering for external calls works in multiple steps:
- we first expand it into a `js_util.callMethod` call (which uses .apply
  internally)
- which we later refine in to a `js_util._callMethodUncheckedN` call, if
  possible (which calls the member directly)

The second step only happens if we can statically verify the arity of
the method being called and that every argument passed doesn't need a
allow-interop check. The latter is bypassed if we know from the types
that it cannot be a Dart Function.

The new JS interop always satisfies the check, but the second step above
failed to regonize it because it didn't account for extension types. This
CL does the incremental fix to recognize it. Long term, we should
instead change the lowering to use directly the js_interop_unsafe
methods, and tailor the lowering to the new interop.

Fixes https://github.com/dart-lang/sdk/issues/54862

Change-Id: Ieee560e5cd6bd9b6921368477bf8212cae5a1faa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/351221
Commit-Queue: Sigmund Cherem <sigmund@google.com>
Reviewed-by: Srujan Gaddam <srujzs@google.com>
This commit is contained in:
Sigmund Cherem 2024-02-09 01:59:46 +00:00 committed by Commit Queue
parent 244f8cee87
commit d82be109a2
6 changed files with 10 additions and 8 deletions

View file

@ -671,6 +671,7 @@ class JsUtilOptimizer extends Transformer {
/// Returns whether the given DartType is guaranteed to be not a function
/// and therefore allowed to interop with JS.
bool _allowedInteropType(DartType type) {
type = type.extensionTypeErasure;
if (type is InterfaceType) {
return type.classNode != _coreTypes.functionClass &&
type.classNode != _coreTypes.objectClass;

View file

@ -113,6 +113,7 @@ builddir
bulkcompile
busy
busywait
bx
bye
c's
ca

View file

@ -84,14 +84,14 @@ static method method(self::A a) → void {
a = js_2::getProperty<self::A>(b1, "field");
js_2::setProperty<self::A>(b1, "field", a);
a = js_2::_callMethodUnchecked0<self::A>(b1, "method");
b2 = js_2::callMethod<self::B% /* = self::A */>(b2, "genericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(b2, "genericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(b2, "getter");
js_2::setProperty<self::B /* = self::A */>(b1, "setter", b2);
js_2::setProperty<self::B /* = self::A */>(b1, "property", js_2::getProperty<self::B /* = self::A */>(b2, "property"));
a = js_2::getProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField");
js_2::setProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField", a);
a = js_2::_callMethodUnchecked0<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticMethod");
b2 = js_2::callMethod<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGetter");
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticSetter", b2);
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty", js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty"));

View file

@ -84,14 +84,14 @@ static method method(self::A a) → void {
a = js_2::getProperty<self::A>(b1, "field");
js_2::setProperty<self::A>(b1, "field", a);
a = js_2::_callMethodUnchecked0<self::A>(b1, "method");
b2 = js_2::callMethod<self::B% /* = self::A */>(b2, "genericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(b2, "genericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(b2, "getter");
js_2::setProperty<self::B /* = self::A */>(b1, "setter", b2);
js_2::setProperty<self::B /* = self::A */>(b1, "property", js_2::getProperty<self::B /* = self::A */>(b2, "property"));
a = js_2::getProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField");
js_2::setProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField", a);
a = js_2::_callMethodUnchecked0<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticMethod");
b2 = js_2::callMethod<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGetter");
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticSetter", b2);
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty", js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty"));

View file

@ -84,14 +84,14 @@ static method method(self::A a) → void {
a = js_2::getProperty<self::A>(b1, "field");
js_2::setProperty<self::A>(b1, "field", a);
a = js_2::_callMethodUnchecked0<self::A>(b1, "method");
b2 = js_2::callMethod<self::B% /* = self::A */>(b2, "genericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(b2, "genericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(b2, "getter");
js_2::setProperty<self::B /* = self::A */>(b1, "setter", b2);
js_2::setProperty<self::B /* = self::A */>(b1, "property", js_2::getProperty<self::B /* = self::A */>(b2, "property"));
a = js_2::getProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField");
js_2::setProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField", a);
a = js_2::_callMethodUnchecked0<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticMethod");
b2 = js_2::callMethod<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGetter");
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticSetter", b2);
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty", js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty"));

View file

@ -84,14 +84,14 @@ static method method(self::A a) → void {
a = js_2::getProperty<self::A>(b1, "field");
js_2::setProperty<self::A>(b1, "field", a);
a = js_2::_callMethodUnchecked0<self::A>(b1, "method");
b2 = js_2::callMethod<self::B% /* = self::A */>(b2, "genericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(b2, "genericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(b2, "getter");
js_2::setProperty<self::B /* = self::A */>(b1, "setter", b2);
js_2::setProperty<self::B /* = self::A */>(b1, "property", js_2::getProperty<self::B /* = self::A */>(b2, "property"));
a = js_2::getProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField");
js_2::setProperty<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticField", a);
a = js_2::_callMethodUnchecked0<self::A>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticMethod");
b2 = js_2::callMethod<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", <dynamic>[b2]);
b2 = js_2::_callMethodUnchecked1<self::B% /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGenericMethod", b2);
b1 = js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticGetter");
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticSetter", b2);
js_2::setProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty", js_2::getProperty<self::B /* = self::A */>(js_2::_getPropertyTrustType<core::Object>(_js2::staticInteropGlobalContext, "B"), "staticProperty"));