Graaljs: ArrayStoreException for delegating object/function proxy

Created on 15 Aug 2018  路  4Comments  路  Source: oracle/graaljs

In my Nashorn application, I have a piece of code that accepts a JavaScript function that comes from Jasmine (it's a spy function). The code creates a wrapper that delegates function execution as well as member access. The purpose is to process the return value of the spy function so that it mimics the "real world".

While converting this code to GraalJS, I ran into a problem - I get ArrayStoreException. I have created a minimal example that reproduces the problem.

My delegating function looks like this:

public class DelegatingFunction implements ProxyObject, ProxyExecutable {
    private final Value delegee;

    public DelegatingFunction(Value delegee) {
        this.delegee = delegee;
    }

    public Object execute(Value... arguments) {
        return delegee.execute(arguments);
    }

    public Object getMember(String key) {
        return delegee.getMember(key);
    }

    public Object getMemberKeys() {
        return delegee.getMemberKeys();
    }

    public boolean hasMember(String key) {
        return delegee.hasMember(key);
    }

    public void putMember(String key, Value value) {
        delegee.putMember(key, value);
    }

    public boolean removeMember(String key) {
        return delegee.removeMember(key);
    }
}

(It delegates member access since the spy function has identification properties.)

And my test code looks like this:

public class DelegatingFunctionTest {
    public static void main(String[] args) {
        Context context = Context.create("js");
        Value bindings = context.getBindings("js");


        bindings.putMember("main", new DelegatingFunctionTest());

        String src = "var original = function (arg) { print(arg); };\n" +
                "var wrapper = main.wrap(original);\n" +
                "wrapper('test');";
        context.eval("js", src);
    }

    public Object wrap(Value function) {
        assert function.canExecute() : "Not a function";
        return new DelegatingFunction(function);
    }
}

The error I get is:

Exception in thread "main" org.graalvm.polyglot.PolyglotException: java.lang.ArrayStoreException: java.lang.String
    at com.oracle.truffle.api.vm.PolyglotLanguageContext$ToGuestValuesNode.fastToGuestValuesUnroll(PolyglotLanguageContext.java:479)
    at com.oracle.truffle.api.vm.PolyglotLanguageContext$ToGuestValuesNode.apply(PolyglotLanguageContext.java:450)
    at com.oracle.truffle.api.vm.PolyglotValue$Interop$AbstractExecuteNode.executeShared(PolyglotValue.java:2166)
    at com.oracle.truffle.api.vm.PolyglotValue$Interop$ExecuteNode.executeImpl(PolyglotValue.java:2248)
    at com.oracle.truffle.api.vm.PolyglotValue$PolyglotNode.execute(PolyglotValue.java:551)
    at org.graalvm.polyglot.Value.execute(Value.java:312)
    at com.programmaticallyspeaking.gho.DelegatingFunction.execute(DelegatingFunction.java:16)
    at <js> :program(Unnamed:3:82-96)
    at org.graalvm.polyglot.Context.eval(Context.java:336)
    at com.programmaticallyspeaking.gho.DelegatingFunctionTest.main(DelegatingFunctionTest.java:17)
Original Internal Error: 
java.lang.ArrayStoreException: java.lang.String
    at com.oracle.truffle.api.vm.PolyglotLanguageContext$ToGuestValuesNode.fastToGuestValuesUnroll(PolyglotLanguageContext.java:479)
    at com.oracle.truffle.api.vm.PolyglotLanguageContext$ToGuestValuesNode.apply(PolyglotLanguageContext.java:450)
    at com.oracle.truffle.api.vm.PolyglotValue$Interop$AbstractExecuteNode.executeShared(PolyglotValue.java:2166)
    at com.oracle.truffle.api.vm.PolyglotValue$Interop$ExecuteNode.executeImpl(PolyglotValue.java:2248)
    at com.oracle.truffle.api.vm.PolyglotValue$PolyglotNode.execute(PolyglotValue.java:551)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callProxy(OptimizedCallTarget.java:262)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callRoot(OptimizedCallTarget.java:251)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:241)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:226)
    at org.graalvm.compiler.truffle.runtime.GraalTVMCI.callProfiled(GraalTVMCI.java:86)
    at com.oracle.truffle.api.impl.Accessor.callProfiled(Accessor.java:724)
    at com.oracle.truffle.api.vm.VMAccessor.callProfiled(VMAccessor.java:93)
    at com.oracle.truffle.api.vm.PolyglotValue$Interop.execute(PolyglotValue.java:1410)
    at org.graalvm.polyglot.Value.execute(Value.java:312)
    at com.programmaticallyspeaking.gho.DelegatingFunction.execute(DelegatingFunction.java:16)
    at com.oracle.truffle.api.vm.PolyglotProxy$ProxyExecuteNode.executeProxy(PolyglotProxy.java:137)
    at com.oracle.truffle.api.vm.PolyglotProxy$ProxyRootNode.execute(PolyglotProxy.java:96)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callProxy(OptimizedCallTarget.java:262)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callRoot(OptimizedCallTarget.java:251)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:241)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:226)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callDirect(OptimizedCallTarget.java:209)
    at org.graalvm.compiler.truffle.runtime.OptimizedDirectCallNode.callProxy(OptimizedDirectCallNode.java:86)
    at org.graalvm.compiler.truffle.runtime.OptimizedDirectCallNode.call(OptimizedDirectCallNode.java:70)
    at com.oracle.truffle.api.interop.InteropAccessNode.doCached(InteropAccessNode.java:186)
    at com.oracle.truffle.api.interop.InteropAccessNodeGen.executeAndSpecialize(InteropAccessNodeGen.java:82)
    at com.oracle.truffle.api.interop.InteropAccessNodeGen.executeImpl(InteropAccessNodeGen.java:45)
    at com.oracle.truffle.api.interop.InteropAccessNode.execute(InteropAccessNode.java:67)
    at com.oracle.truffle.api.interop.ForeignAccess.sendExecute(ForeignAccess.java:420)
    at com.oracle.truffle.js.runtime.truffleinterop.JSInteropNodeUtil.call(JSInteropNodeUtil.java:254)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode$ForeignExecuteNode.executeCallImpl(JSFunctionCallNode.java:1043)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode$ForeignExecuteNode.executeCall(JSFunctionCallNode.java:1035)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode$CacheNode.executeCall(JSFunctionCallNode.java:665)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode$UninitializedCacheNode.executeCall(JSFunctionCallNode.java:699)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode.executeCall(JSFunctionCallNode.java:217)
    at com.oracle.truffle.js.nodes.function.JSFunctionCallNode$CallNode.execute(JSFunctionCallNode.java:255)
    at com.oracle.truffle.js.nodes.access.JSWriteCurrentFrameSlotNodeGen.execute_generic3(JSWriteCurrentFrameSlotNodeGen.java:149)
    at com.oracle.truffle.js.nodes.access.JSWriteCurrentFrameSlotNodeGen.execute(JSWriteCurrentFrameSlotNodeGen.java:84)
    at com.oracle.truffle.js.nodes.access.JSWriteCurrentFrameSlotNodeGen.executeVoid(JSWriteCurrentFrameSlotNodeGen.java:281)
    at com.oracle.truffle.js.nodes.control.ExprBlockNode.execute(ExprBlockNode.java:68)
    at com.oracle.truffle.js.nodes.function.FunctionBodyNode.execute(FunctionBodyNode.java:66)
    at com.oracle.truffle.js.nodes.function.FunctionRootNode.executeInRealm(FunctionRootNode.java:139)
    at com.oracle.truffle.js.runtime.JavaScriptRealmBoundaryRootNode.execute(JavaScriptRealmBoundaryRootNode.java:92)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callProxy(OptimizedCallTarget.java:262)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callRoot(OptimizedCallTarget.java:251)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:241)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:226)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callDirect(OptimizedCallTarget.java:209)
    at org.graalvm.compiler.truffle.runtime.OptimizedDirectCallNode.callProxy(OptimizedDirectCallNode.java:86)
    at org.graalvm.compiler.truffle.runtime.OptimizedDirectCallNode.call(OptimizedDirectCallNode.java:70)
    at com.oracle.truffle.js.parser.JavaScriptLanguage$1.execute(JavaScriptLanguage.java:211)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callProxy(OptimizedCallTarget.java:262)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callRoot(OptimizedCallTarget.java:251)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.callBoundary(OptimizedCallTarget.java:241)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.doInvoke(OptimizedCallTarget.java:226)
    at org.graalvm.compiler.truffle.runtime.OptimizedCallTarget.call(OptimizedCallTarget.java:202)
    at com.oracle.truffle.api.vm.PolyglotContextImpl.eval(PolyglotContextImpl.java:746)
    at org.graalvm.polyglot.Context.eval(Context.java:311)
    at org.graalvm.polyglot.Context.eval(Context.java:336)
    at com.programmaticallyspeaking.gho.DelegatingFunctionTest.main(DelegatingFunctionTest.java:17)
Caused by: Attached Guest Language Frames (4)

What am I doing wrong?

bug

All 4 comments

You have discovered a bug (internal errors are always a bug on our side). This should workaround the problem:

public static class DelegatingFunction implements ProxyObject, ProxyExecutable {
...

        @Override
        public Object execute(Value... arguments) {
            Object[] o = new Object[arguments.length];
            System.arraycopy(arguments, 0, o, 0, o.length);
            return delegee.execute(o);
        }

...

    }

Not 100% sure what causes this. Will investigate further.

Thanks, I'll try the workaround later today!

The workaround worked, thanks!

Was this page helpful?
0 / 5 - 0 ratings