oracle / graal

GraalVM compiles Java applications into native executables that start instantly, scale fast, and use fewer compute resources 🚀
https://www.graalvm.org
Other
19.96k stars 1.6k forks source link

[GR-54959] `ProxyInstantiable` carries no class information #9167

Open sgammon opened 1 week ago

sgammon commented 1 week ago

Describe the issue I want to create polyglot-capable objects with a ProxyInstantiable, but I also want such objects to pass type checks in guest languages.

Code snippet or code repository that reproduces the issue

val ctx: Context = /* ... */
val bindings = ctx.getBindings("js").putMember("SomeType", ProxyInstantiable {
  SomeImplementingHostType()
})

Later, in a guest language...

const x = new SomeType()
x instanceof SomeType  // always returns `false`, because `SomeType` is a `ProxyInstantiable`

Additional context I've considered the alternative of a facade guest type, like:

// obtain raw host type somehow
const RawSomeType = /* ... */

class SomeType extends RawSomeType {
  // ...
}

But this requires up-front execution of preparatory code in the guest context.

I've also tried installing the host type directly, but then I must register my constructors for reflective access, and I must share host constructors with guest constructors, which especially complicates instantiation with varargs Value. The flexibility of ProxyInstantiable, which allows vararg Value, is especially useful for interop with JavaScript, but is hard to adapt to type checks.

selhagani commented 6 days ago

Hi @sgammon , thanks for reaching out to us. We'll be taking a look into this shortly

iamstolis commented 3 days ago

I've considered the alternative of a facade guest type, like: ... but, constructors can't return other types

In fact, constructors (in JavaScript) can return arbitrary objects and you can abuse that to implement what you need using something like

class SomeType {
    constructor(...args) {
        return new RawSomeType(...args);
    };
    static [Symbol.hasInstance](o) {
        // some code that is able to recognize instances of RawSomeType
        // and return true for them (and false otherwise)
    }
}

Would that work for you?

sgammon commented 3 days ago

@iamstolis Lol. JavaScript never ceases to amaze. I updated my description.

This will work for us for now, yes, but this approach generally requires us to execute preparatory code in the guest context before executing actual guest code which relies on instanceof working.

Ideally, we'd be able to inject a type from the host context, without resorting to guest code. It would be really cool to make static [Symbol.hasInstance] possible from the host, and I don't know of a way to do that today.

iamstolis commented 3 days ago

This will work for us for now, yes, but this approach generally requires us to execute preparatory code in the guest context before executing actual guest code ... Ideally, we'd be able to inject a type from the host context, without resorting to guest code.

I am sorry, I don't understand why exactly are you more concerned by the execution of preparatory code compared to the usage of methods of Value class (like putMember()).