# HG changeset patch # User Jaroslav Tulach # Date 1433319439 -7200 # Node ID ed234a3178af8422526f2efb6409632f5dc0cf90 # Parent 889b45a0dedd7e23868fe40bb9b680fae09cf15f Behavior of null-like values is now part of the TCK diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java --- a/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/vm/TruffleTCK.java Wed Jun 03 10:17:19 2015 +0200 @@ -27,6 +27,7 @@ import org.junit.*; import com.oracle.truffle.api.vm.*; +import static org.junit.Assert.*; /** * A collection of tests that can certify language implementaiton to be complient with most recent @@ -66,6 +67,18 @@ } /** + * Name of a function that returns null. Truffle languages are encouraged to have + * their own type representing null, but when such value is returned from + * {@link TruffleVM#eval}, it needs to be converted to real Java null by sending a + * foreign access isNull message. There is a test to verify it is really true. + * + * @return name of globally exported symbol + */ + protected String returnsNull() { // abstract + return null; + } + + /** * Name of function to add two integer values together. The symbol will be invoked with two * parameters of type {@link Integer} and expects result of type {@link Number} which's * {@link Number#intValue()} is equivalent of param1 + param2. @@ -104,6 +117,18 @@ } @Test + public void testNull() throws Exception { + if (getClass() == TruffleTCK.class) { + return; + } + TruffleVM.Symbol retNull = findGlobalSymbol(returnsNull()); + + Object res = retNull.invoke(null); + + assertNull("Should yield real Java null", res); + } + + @Test public void testPlusWithInts() throws Exception { if (getClass() == TruffleTCK.class) { return; diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java --- a/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.interop/src/com/oracle/truffle/interop/SymbolInvokerImpl.java Wed Jun 03 10:17:19 2015 +0200 @@ -30,6 +30,7 @@ import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.impl.*; import com.oracle.truffle.api.interop.*; +import com.oracle.truffle.api.interop.exception.UnsupportedMessageException; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.interop.messages.*; import com.oracle.truffle.interop.node.*; @@ -39,10 +40,39 @@ @Override protected Object invoke(Object symbol, Object... arr) throws IOException { - ForeignObjectAccessNode executeMain = ForeignObjectAccessNode.getAccess(Execute.create(Receiver.create(), arr.length)); - CallTarget callTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(executeMain, (TruffleObject) symbol, arr)); + ForeignObjectAccessNode callMain = ForeignObjectAccessNode.getAccess(Execute.create(Receiver.create(), arr.length)); + CallTarget callMainTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(callMain, (TruffleObject) symbol, arr)); VirtualFrame frame = Truffle.getRuntime().createVirtualFrame(arr, UNUSED_FRAMEDESCRIPTOR); - return callTarget.call(frame); + Object ret = callMainTarget.call(frame); + if (ret instanceof TruffleObject) { + TruffleObject tret = (TruffleObject) ret; + Object isBoxedResult; + try { + ForeignObjectAccessNode isBoxed = ForeignObjectAccessNode.getAccess(IsBoxed.create(Receiver.create())); + CallTarget isBoxedTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isBoxed, tret)); + isBoxedResult = isBoxedTarget.call(frame); + } catch (UnsupportedMessageException ex) { + isBoxedResult = false; + } + if (Boolean.TRUE.equals(isBoxedResult)) { + ForeignObjectAccessNode unbox = ForeignObjectAccessNode.getAccess(Unbox.create(Receiver.create())); + CallTarget unboxTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(unbox, tret)); + Object unboxResult = unboxTarget.call(frame); + return unboxResult; + } else { + try { + ForeignObjectAccessNode isNull = ForeignObjectAccessNode.getAccess(IsNull.create(Receiver.create())); + CallTarget isNullTarget = Truffle.getRuntime().createCallTarget(new TemporaryRoot(isNull, tret)); + Object isNullResult = isNullTarget.call(frame); + if (Boolean.TRUE.equals(isNullResult)) { + return null; + } + } catch (UnsupportedMessageException ex) { + // fallthrough + } + } + } + return ret; } private static class TemporaryRoot extends RootNode { diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java --- a/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.sl.test/src/com/oracle/truffle/sl/test/SLTckTest.java Wed Jun 03 10:17:19 2015 +0200 @@ -41,14 +41,18 @@ @Override protected TruffleVM prepareVM() throws Exception { TruffleVM vm = TruffleVM.newVM().build(); - vm.eval("application/x-sl", // your langage - "function fourtyTwo() {\n" + // your script - " return 42;\n" + // - "}\n" + // - "function plus(a, b) {\n" + // - " return a + b;\n" + // - "}\n" // + // @formatter:off + vm.eval("application/x-sl", + "function fourtyTwo() {\n" + + " return 42;\n" + // + "}\n" + + "function plus(a, b) {\n" + + " return a + b;\n" + + "}\n" + + "function null() {\n" + + "}\n" ); + // @formatter:on return vm; } @@ -61,4 +65,9 @@ protected String plusInt() { return "plus"; } + + @Override + protected String returnsNull() { + return "null"; + } } diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLMain.java Wed Jun 03 10:17:19 2015 +0200 @@ -242,7 +242,7 @@ /* Call the main entry point, without any arguments. */ try { result = main.invoke(null); - if (result != SLNull.SINGLETON) { + if (result != null) { out.println(result); } } catch (UnsupportedSpecializationException ex) { diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLFunctionForeignAccess.java Wed Jun 03 10:17:19 2015 +0200 @@ -32,6 +32,7 @@ import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.interop.ForeignAccessArguments; import com.oracle.truffle.interop.messages.Execute; +import com.oracle.truffle.interop.messages.IsNull; import com.oracle.truffle.interop.messages.Receiver; import com.oracle.truffle.sl.nodes.call.SLDispatchNode; import com.oracle.truffle.sl.nodes.call.SLDispatchNodeGen; @@ -55,6 +56,8 @@ public CallTarget getAccess(Message tree) { if (Execute.create(Receiver.create(), 0).matchStructure(tree)) { return Truffle.getRuntime().createCallTarget(new SLForeignCallerRootNode()); + } else if (IsNull.create(Receiver.create()).matchStructure(tree)) { + return Truffle.getRuntime().createCallTarget(new SLForeignNullCheckNode()); } else { throw new UnsupportedMessageException(tree.toString() + " not supported"); } @@ -87,4 +90,11 @@ } + private static class SLForeignNullCheckNode extends RootNode { + @Override + public Object execute(VirtualFrame frame) { + Object receiver = ForeignAccessArguments.getReceiver(frame.getArguments()); + return SLNull.SINGLETON == receiver; + } + } } diff -r 889b45a0dedd -r ed234a3178af graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Tue Jun 02 21:15:59 2015 -0700 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/runtime/SLNull.java Wed Jun 03 10:17:19 2015 +0200 @@ -22,6 +22,9 @@ */ package com.oracle.truffle.sl.runtime; +import com.oracle.truffle.api.interop.ForeignAccessFactory; +import com.oracle.truffle.api.interop.TruffleObject; + /** * The SL type for a {@code null} (i.e., undefined) value. In Truffle, it is generally discouraged * to use the Java {@code null} value to represent the guest language {@code null} value. It is not @@ -30,7 +33,7 @@ * language {@code null} as a singleton, as in {@link #SINGLETON this class}, is the recommended * practice. */ -public final class SLNull { +public final class SLNull implements TruffleObject { /** * The canonical value to represent {@code null} in SL. @@ -52,4 +55,9 @@ public String toString() { return "null"; } + + @Override + public ForeignAccessFactory getForeignAccessFactory() { + return SLFunctionForeignAccess.INSTANCE; + } }