Skip to content

Commit

Permalink
Use InteropLibrary when accepting String values (#9773)
Browse files Browse the repository at this point in the history
While investigating #9749 a JavaScript call to `Polyglot.eval("enso", ....).eval_expression("id")` was made. It crashed as JavaScript isn't using `String` but `TruffleString` to represent strings.
  • Loading branch information
JaroslavTulach authored Apr 24, 2024
1 parent fb9cf38 commit a786ad2
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.TruffleObject;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
import java.util.concurrent.Executors;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
Expand Down Expand Up @@ -44,7 +48,7 @@ public void testForeignFunctionParseFailure() {
assertTrue("Invoking non-installed foreign function should recover", res.isException());
try {
throw res.throwException();
} catch (Exception e) {
} catch (RuntimeException e) {
assertTrue(
"Wrong error message",
e.getMessage()
Expand All @@ -65,7 +69,7 @@ public void testInteropWithJavaScript() throws Exception {
""";

var module = ctx.eval("enso", source);
var third = module.invokeMember("eval_expression", "third");
var third = module.invokeMember("eval_expression", new AsString("third"));
var res = third.execute(13);
assertTrue("It is an array", res.hasArrayElements());
assertEquals(3, res.getArraySize());
Expand Down Expand Up @@ -102,7 +106,7 @@ public void testParallelInteropWithJavaScript() throws Exception {
""";

var module = ctx.eval("enso", source);
var third = module.invokeMember("eval_expression", "third");
var third = module.invokeMember("eval_expression", new AsString("third"));

var future =
Executors.newSingleThreadExecutor()
Expand All @@ -122,4 +126,23 @@ public void testParallelInteropWithJavaScript() throws Exception {
assertTrue("It is an array2", res2.hasArrayElements());
assertEquals(12, res2.getArrayElement(2).asInt());
}

@ExportLibrary(InteropLibrary.class)
static class AsString implements TruffleObject {
private final String value;

private AsString(String value) {
this.value = value;
}

@ExportMessage
boolean isString() {
return true;
}

@ExportMessage
String asString() {
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import com.oracle.truffle.api.interop.ArityException;
import com.oracle.truffle.api.interop.InteropLibrary;
import com.oracle.truffle.api.interop.UnknownIdentifierException;
import com.oracle.truffle.api.interop.UnsupportedMessageException;
import com.oracle.truffle.api.interop.UnsupportedTypeException;
import com.oracle.truffle.api.library.ExportLibrary;
import com.oracle.truffle.api.library.ExportMessage;
Expand Down Expand Up @@ -567,8 +568,12 @@ private static Function getMethod(ModuleScope scope, Object[] args)
}

private static Type getType(ModuleScope scope, Object[] args)
throws ArityException, UnsupportedTypeException {
String name = Types.extractArguments(args, String.class);
throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
var iop = InteropLibrary.getUncached();
if (!iop.isString(args[0])) {
throw UnsupportedTypeException.create(args, "First argument must be a string");
}
String name = iop.asString(args[0]);
return scope.getTypes().get(name);
}

Expand All @@ -586,15 +591,23 @@ private static Module reparse(Module module, Object[] args, EnsoContext context)
}

private static Module setSource(Module module, Object[] args, EnsoContext context)
throws ArityException, UnsupportedTypeException {
String source = Types.extractArguments(args, String.class);
throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
var iop = InteropLibrary.getUncached();
if (!iop.isString(args[0])) {
throw UnsupportedTypeException.create(args, "First argument must be a string");
}
String source = iop.asString(args[0]);
module.setLiteralSource(source);
return module;
}

private static Module setSourceFile(Module module, Object[] args, EnsoContext context)
throws ArityException, UnsupportedTypeException {
String file = Types.extractArguments(args, String.class);
throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
var iop = InteropLibrary.getUncached();
if (!iop.isString(args[0])) {
throw UnsupportedTypeException.create(args, "First argument must be a string");
}
String file = iop.asString(args[0]);
module.setSourceFile(context.getTruffleFile(new File(file)));
return module;
}
Expand All @@ -606,8 +619,15 @@ private static Type getAssociatedType(ModuleScope scope, Object[] args) throws A

private static Object evalExpression(
ModuleScope scope, Object[] args, EnsoContext context, CallOptimiserNode callOptimiserNode)
throws ArityException, UnsupportedTypeException {
String expr = Types.extractArguments(args, String.class);
throws ArityException, UnsupportedTypeException, UnsupportedMessageException {
if (args.length != 1) {
throw ArityException.create(1, 1, args.length);
}
var iop = InteropLibrary.getUncached();
if (!iop.isString(args[0])) {
throw UnsupportedTypeException.create(args, "First argument must be a string");
}
String expr = iop.asString(args[0]);
Builtins builtins = context.getBuiltins();
BuiltinFunction eval =
builtins
Expand Down Expand Up @@ -641,7 +661,10 @@ static Object doInvoke(
String member,
Object[] arguments,
@Cached LoopingCallOptimiserNode callOptimiserNode)
throws UnknownIdentifierException, ArityException, UnsupportedTypeException {
throws UnknownIdentifierException,
ArityException,
UnsupportedTypeException,
UnsupportedMessageException {
EnsoContext context = EnsoContext.get(null);
ModuleScope scope;
switch (member) {
Expand Down

0 comments on commit a786ad2

Please sign in to comment.