Describe GraalVM and your environment :
java -Xinternalversion: OpenJDK 64-Bit GraalVM CE 19.3.0 (25.232-b07-jvmci-19.3-b05) for bsd-amd64 JRE (8u232), built on Nov 14 2019 02:39:20 by "graal" with gcc 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.37)
Have you verified this issue still happens when using the latest snapshot?
Yes, still an issue in GraalVM CE 20.1.0-dev-20200204_0342.
Describe the issue
Sulong's ToI32Node throws an UnsupportedSpecializationException, which is propagated to the user:
ERROR: com.oracle.truffle.api.dsl.UnsupportedSpecializationException: Unexpected values provided for ToI32NodeGen@7efde843: [DynamicObject<undefined>@55fd5e4b], [DynamicObjectBasic]
org.graalvm.polyglot.PolyglotException: com.oracle.truffle.api.dsl.UnsupportedSpecializationException: Unexpected values provided for ToI32NodeGen@7efde843: [DynamicObject<undefined>@55fd5e4b], [DynamicObjectBasic]
at com.oracle.truffle.llvm.runtime.interop.convert.ToI32NodeGen.executeAndSpecialize(ToI32NodeGen.java:356)
at com.oracle.truffle.llvm.runtime.interop.convert.ToI32NodeGen.executeWithTarget(ToI32NodeGen.java:232)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNode$LLVMLookupDispatchForeignNode.doGeneric(LLVMDispatchNode.java:283)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNode$LLVMLookupDispatchForeignNode.doUnknownType(LLVMDispatchNode.java:296)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNodeGen$LLVMLookupDispatchForeignNodeGen.executeAndSpecialize(LLVMDispatchNodeGen.java:770)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNodeGen$LLVMLookupDispatchForeignNodeGen.execute(LLVMDispatchNodeGen.java:579)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNode.doForeign(LLVMDispatchNode.java:228)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNodeGen.executeAndSpecialize(LLVMDispatchNodeGen.java:340)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMDispatchNodeGen.executeDispatch(LLVMDispatchNodeGen.java:134)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMCallNode.executeGeneric(LLVMCallNode.java:70)
at com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode.executeI32(LLVMExpressionNode.java:100)
at com.oracle.truffle.llvm.runtime.nodes.others.LLVMValueProfilingNodeFactory$LLVMI32ProfiledValueNodeGen.executeI32(LLVMValueProfilingNodeFactory.java:304)
at com.oracle.truffle.llvm.runtime.nodes.vars.LLVMWriteNodeFactory$LLVMWriteI32NodeGen.execute(LLVMWriteNodeFactory.java:271)
at com.oracle.truffle.llvm.runtime.nodes.base.LLVMBasicBlockNode$InitializedBlock.execute(LLVMBasicBlockNode.java:158)
at com.oracle.truffle.llvm.runtime.nodes.control.LLVMDispatchBasicBlockNode.executeGeneric(LLVMDispatchBasicBlockNode.java:86)
at com.oracle.truffle.llvm.runtime.nodes.control.LLVMFunctionRootNode.executeGeneric(LLVMFunctionRootNode.java:74)
at com.oracle.truffle.llvm.runtime.nodes.func.LLVMFunctionStartNode.execute(LLVMFunctionStartNode.java:78)
at <llvm> main(Unknown)
at org.graalvm.polyglot.Value.execute(Value.java:366)
at com.oracle.truffle.llvm.launcher.LLVMLauncher.execute(LLVMLauncher.java:219)
at com.oracle.truffle.llvm.launcher.LLVMLauncher.launch(LLVMLauncher.java:63)
at org.graalvm.launcher.AbstractLanguageLauncher.launch(AbstractLanguageLauncher.java:121)
at org.graalvm.launcher.PolyglotLauncher.switchToLauncher(PolyglotLauncher.java:345)
at org.graalvm.launcher.PolyglotLauncher.launch(PolyglotLauncher.java:191)
at org.graalvm.launcher.PolyglotLauncher.main(PolyglotLauncher.java:434)
Code snippet or code repository that reproduces the issue
#include <stdlib.h>
#include <stdio.h>
#include <polyglot.h>
struct Order {
int price;
};
POLYGLOT_DECLARE_STRUCT(Order)
struct Order *newOrder(int price) {
struct Order *order = (struct Order *) malloc(sizeof(struct Order));
order->price = price;
return order;
}
int main() {
void *foo = polyglot_eval("js", "(order) => order.price");
printf("%d\n", ((int (*)(struct Order *order)) foo)(newOrder(100)));
return 0;
}
Steps to reproduce the issue
Please include both build steps as well as run steps
$LLVM_TOOLCHAIN/clang repro.cpp -lpolyglot-mock -o repro.bclli --polyglot repro.bcExpected behavior
Not sure this is expected to fail, but if it should, then UnsupportedSpecializationException shouldn't be visible to the user.
Thanks for the report!
The problem with the example is that it's missing type information. Unfortunately we can't rely in general on all the types from the C language to still be there in bitcode except for functions themselves (but not function pointers).
The place where we cross the language boundary to JS is the foo function pointer. We don't have any type information for that function pointer. From the JS side there is no type, and from the bitcode side, the typecast is lost, we just see that it's a pointer.
This line would work:
printf("%d\n", ((int (*)(void *)) foo)(polyglot_from_Order(newOrder(100))));
Here we don't assume any type on foo, and instead do an explicit cast from struct Order * to an interop object.
Note that the newOrder function itself does have a type. But you're not calling newOrder from JS (that would work as expected). You're just passing an arbitrary pointer to an untyped function pointer.
That being said, the UnsupportedSpecializationException is still a real bug.
What's happening here is that the pointer is passed untyped, so on the JS side we try to read the member price from a raw pointer. JS being helpful as ever doesn't throw an exception, but just returns undefined. And that's of course not convertible to int. But that situation should not lead to an internal error, it should be a proper interop exception (preferrably one that tells you it's about undefined).
Thanks for looking into this, @rschatz!
The wrong exception should be fixed in https://github.com/oracle/graal/commit/6e6940c20f52fda72ad509733cee0eaa16b06a6c
Thanks!