Skip to content
This repository was archived by the owner on Jul 12, 2024. It is now read-only.

Fix reflective proxy for Hijacked classes #108

Merged
merged 1 commit into from
Apr 18, 2024
Merged

Conversation

tanishiking
Copy link
Owner

@tanishiking tanishiking commented Apr 17, 2024

This commit fix 2 things

(1) Reflective proxy for methods in j.l.Object should call the methods in j.l.Object

Resolves: #97
Related: #98

When a reflective call is made on the clone method, reflective proxies are generated
for the clone method on the Hijacked classes, including java.lang.Void and java.lang.Boolean.

The issue arises because the generated reflective proxy contains a function call
to a non-existent function, such as $f#java.lang.Void#clone_Ljava.lang.Object in this example.

(func $f#java.lang.Void#clone_R (type $f.21)
   (param $___<this> (ref any)) (result anyref)
   local.get $___<this>
   call $f#java.lang.Void#clone_Ljava.lang.Object)

For Hijacked classes, genApply is transformed into genApplyStatically, which looks up
the method in the Hijacked class and calls it directly, instead of using table dispatching.
However, resolvePublicMethod incorrectly resolves the "clone" method from the Hijacked classes,
such as java.lang.Boolean, even though the method doesn't exist in the Hijacked class itself
(it is inherited from java.lang.Object).

In this context, resolvePublicMethod should not resolve methods that are not defined in the
specific Hijacked class.


(2) Workaround wrong t.tpe for This nodes inside reflective proxies.
In a hijacked class, This nodes are supposed to be typed as the corresponding primitive type.
However, the Scala.js linker frontend synthesizes reflective proxies that contain This nodes typed as the hijacked class' ClassType instead.
This is bad for us because it means genAdapt fails to box the primitives when required.
We work around this issue here by re-computing the correct type of This nodes.
#100

Synthetic This should have a primitive type instead of BoxedType

Fix #100

// }
if (methods.exists( m =>
m.name.simpleName == methodName.nameString &&
!m.isAbstract
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch, good catch!

@tanishiking tanishiking force-pushed the reflective-object-methods branch 3 times, most recently from cc381eb to 6747768 Compare April 18, 2024 09:53
@tanishiking tanishiking changed the title WIP: Reflective proxy for clone should call clone in j.l.Object Reflective proxy for clone should call clone in j.l.Object Apr 18, 2024
@tanishiking tanishiking marked this pull request as ready for review April 18, 2024 09:54
// The synthetic `This` may contains boxed primitive, instead of primitive types.
// However, the checker should ensure that the `This` is never boxed in Scala.js linker frontend.
// As a workaround, we unbox the `This` here.
val fixedTpe = t.tpe match {
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any better explanation?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps as follows:

Workaround wrong t.tpe for This nodes inside reflective proxies.
In a hijacked class, This nodes are supposed to be typed as the corresponding primitive type.
However, the Scala.js linker frontend synthesizes reflective proxies that contain This nodes typed as the hijacked class' ClassType instead.
This is bad for us because it means genAdapt fails to box the primitives when required.
We work around this issue here by re-computing the correct type of This nodes.

Copy link
Collaborator

@sjrd sjrd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. The commits should probably be squashed at this point.

This commit fix 2 things

(1) Reflective proxy for methods in `j.l.Object` should call the methods in `j.l.Object`

Resolves: #97
Related: #98

When a reflective call is made on the `clone` method, reflective proxies are generated
for the `clone` method on the Hijacked classes, including `java.lang.Void` and `java.lang.Boolean`.

The issue arises because the generated reflective proxy contains a function call
to a non-existent function, such as `$f#java.lang.Void#clone_Ljava.lang.Object` in this example.

```
(func $f#java.lang.Void#clone_R (type $f.21)
   (param $___<this> (ref any)) (result anyref)
   local.get $___<this>
   call $f#java.lang.Void#clone_Ljava.lang.Object)
```

For Hijacked classes, `genApply` is transformed into `genApplyStatically`, which looks up
the method in the Hijacked class and calls it directly, instead of using table dispatching.
However, `resolvePublicMethod` incorrectly resolves the "clone" method from the Hijacked classes,
such as `java.lang.Boolean`, even though the method doesn't exist in the Hijacked class itself
(it is inherited from java.lang.Object).

In this context, `resolvePublicMethod` should not resolve methods that are not defined in the
specific Hijacked class.

---

(2) Workaround wrong t.tpe for `This` nodes inside reflective proxies.
In a hijacked class, This nodes are supposed to be typed as the corresponding primitive type.
However, the Scala.js linker frontend synthesizes reflective proxies that contain This nodes typed as the hijacked class' ClassType instead.
This is bad for us because it means genAdapt fails to box the primitives when required.
We work around this issue here by re-computing the correct type of This nodes.
#100

Synthetic `This` should have a primitive type instead of BoxedType

Fix #100
@tanishiking tanishiking force-pushed the reflective-object-methods branch from 6747768 to 8d8a6c7 Compare April 18, 2024 11:59
@tanishiking
Copy link
Owner Author

Thanks, edited the comment, and squashed 👍

@tanishiking tanishiking changed the title Reflective proxy for clone should call clone in j.l.Object Fix reflective proxy for Hijacked classes Apr 18, 2024
@sjrd sjrd merged commit 17365de into main Apr 18, 2024
1 check passed
@sjrd sjrd deleted the reflective-object-methods branch April 18, 2024 12:41
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
2 participants