Skip to content

Function cannot use variable from scope it is defined if it is migrated more than once #927

@Siriusmart

Description

@Siriusmart

Hello people.
I noticed a weird behaviour on GraalJS when passing a function from one Context to another Context.

import org.graalvm.polyglot.Context;

public class App {
    public static void main(String[] args) {
        Context one = Context.create("js");
        Context two = Context.create("js");
        Context three = Context.create("js");

        one.eval("js", "let pi = 3;");
        one.eval("js", "function getPi() { console.log(pi) }");

        two.getBindings("js").putMember("getPi", one.getBindings("js").getMember("getPi"));

        three.getBindings("js").putMember("getPi", two.getBindings("js").getMember("getPi"));
        three.eval("js", "getPi()");

    }
}

Where getPi is a function from one that uses pi from Context one, assigned to a variable in Context two from one, then assigned to variable from Context two to three. This yields error

Exception in thread "main" ReferenceError: pi is not defined
        at <js> getPi(Unnamed:1:31-32)
        at <js> :program(Unknown)
        at org.graalvm.polyglot.Context.eval(Context.java:446)
        at App.main(App.java:19)

This behaviour occurs when a function uses a variable from the Context it is declared, then is assigned to at least variables in different Context before used. So by removing a Context will result of code that does not thrown an error.

Context one = Context.create("js");
Context three = Context.create("js");

one.eval("js", "let pi = 3;");
one.eval("js", "function getPi() { console.log(pi) }");

three.getBindings("js").putMember("getPi", one.getBindings("js").getMember("getPi"));
three.eval("js", "getPi()");

For some reason, declaring a variable with the same name in Context two will also stop the errors.

Context one = Context.create("js");
Context two = Context.create("js");
Context three = Context.create("js");

one.eval("js", "let pi = 3;");
one.eval("js", "function getPi() { console.log(pi) }");

two.eval("js", "let pi = 3;"); // redeclared in Context two
two.getBindings("js").putMember("getPi", one.getBindings("js").getMember("getPi"));

three.getBindings("js").putMember("getPi", two.getBindings("js").getMember("getPi"));
three.eval("js", "getPi()");

I would assume this is not intended behaviour as it doesn't match how JS normally behaves (in nodejs), has anyone encountered this issue before/any workarounds?

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions