diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java index eeb5dd0ceb3c25f714e58b1751a5d3bd2fcce3e7..7a2924577a1ebe8a2f65a0c61e6ee89d054c99b9 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/common/JavaUpCallsRFFIImpl.java @@ -878,20 +878,8 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } @Override - @TruffleBoundary public Object R_tryEval(Object expr, Object env, int silent) { - Object handlerStack = RErrorHandling.getHandlerStack(); - Object restartStack = RErrorHandling.getRestartStack(); - try { - // TODO handle silent - RErrorHandling.resetStacks(); - Object result = Rf_eval(expr, env); - return result; - } catch (Throwable t) { - return null; - } finally { - RErrorHandling.restoreStacks(handlerStack, restartStack); - } + throw implementedAsNode(); } /** diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java index da3d249e0dd4c25c4e487cfc76c9b701741ce7a8..ae738c977aec0e2f50ad9a5e728cbfe0f2a17a03 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/RfEvalNode.java @@ -65,13 +65,13 @@ public abstract class RfEvalNode extends FFIUpCallNode.Arg2 { @Specialization @TruffleBoundary Object handleExpression(RExpression expr, REnvironment env) { - return RContext.getEngine().eval(expr, env, RCaller.topLevel); + return RContext.getEngine().eval(expr, env, null); } @Specialization @TruffleBoundary Object handleLanguage(RLanguage expr, REnvironment env) { - return RContext.getEngine().eval(expr, env, RCaller.topLevel); + return RContext.getEngine().eval(expr, env, null); } @Specialization diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/TryRfEvalNode.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/TryRfEvalNode.java new file mode 100644 index 0000000000000000000000000000000000000000..64d544f386ddc03116d3f24d580109a1e6988993 --- /dev/null +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/TryRfEvalNode.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.truffle.r.ffi.impl.nodes; + +import com.oracle.truffle.r.runtime.RErrorHandling; + +public class TryRfEvalNode extends FFIUpCallNode.Arg3 { + @Child RfEvalNode rfEvalNode = RfEvalNode.create(); + + @Override + public Object executeObject(Object expr, Object env, @SuppressWarnings("unused") Object silent) { + Object handlerStack = RErrorHandling.getHandlerStack(); + Object restartStack = RErrorHandling.getRestartStack(); + try { + // TODO handle silent + RErrorHandling.resetStacks(); + return rfEvalNode.executeObject(expr, env); + } catch (Throwable t) { + return null; + } finally { + RErrorHandling.restoreStacks(handlerStack, restartStack); + } + } +} diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java index 90dba617d41e82a72eb5964bd987e6f026d72731..1f85756b25d0f1bdc1752c47bdc0b3ce200eddeb 100644 --- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java +++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/upcalls/StdUpCallsRFFI.java @@ -52,6 +52,7 @@ import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes; import com.oracle.truffle.r.ffi.impl.nodes.MiscNodes.LENGTHNode; import com.oracle.truffle.r.ffi.impl.nodes.RandFunctionsNodes; import com.oracle.truffle.r.ffi.impl.nodes.RfEvalNode; +import com.oracle.truffle.r.ffi.impl.nodes.TryRfEvalNode; import com.oracle.truffle.r.ffi.processor.RFFICstring; import com.oracle.truffle.r.ffi.processor.RFFIRunGC; import com.oracle.truffle.r.ffi.processor.RFFIUpCallNode; @@ -273,6 +274,8 @@ public interface StdUpCallsRFFI { void Rf_copyMatrix(Object s, Object t, int byrow); + @RFFIRunGC + @RFFIUpCallNode(TryRfEvalNode.class) Object R_tryEval(Object expr, Object env, int silent); Object R_ToplevelExec(); diff --git a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h index c305453c283d0c934e99e13942a7399d78aabf1d..7a7193a66caef511c33b627cc3f3640e9d032a75 100644 --- a/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h +++ b/com.oracle.truffle.r.native/fficall/src/truffle_common/Rinternals_truffle_common.h @@ -1366,7 +1366,7 @@ SEXP Rf_asS4(SEXP x, Rboolean b, int i) { static SEXP R_tryEvalInternal(SEXP x, SEXP y, int *ErrorOccurred, int silent) { TRACE0(); - unimplemented("R_tryEvalInternal"); + return ((call_R_tryEval) callbacks[R_tryEval_x])(x, y, silent); } SEXP R_tryEval(SEXP x, SEXP y, int *ErrorOccurred) { diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java index 01d7eaa01723bbeef0689b6981dc96b6ef27f790..906f67906eb3c1dad6bc7903825c1530c41e04e9 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/Eval.java @@ -48,6 +48,7 @@ import com.oracle.truffle.r.nodes.builtin.base.GetFunctionsFactory.GetNodeGen; import com.oracle.truffle.r.nodes.function.PromiseHelperNode.PromiseCheckHelperNode; import com.oracle.truffle.r.nodes.function.visibility.SetVisibilityNode; import com.oracle.truffle.r.runtime.ArgumentsSignature; +import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RType; @@ -170,8 +171,8 @@ public abstract class Eval extends RBuiltinNode.Arg3 { @Specialization protected Object doEval(VirtualFrame frame, RLanguage expr, Object envir, Object enclos) { - RCaller rCaller = RCaller.create(frame, getOriginalCall()); REnvironment environment = envCast.execute(frame, envir, enclos); + RCaller rCaller = getCaller(frame, environment); try { return RContext.getEngine().eval(expr, environment, rCaller); } catch (ReturnException ret) { @@ -187,8 +188,8 @@ public abstract class Eval extends RBuiltinNode.Arg3 { @Specialization protected Object doEval(VirtualFrame frame, RExpression expr, Object envir, Object enclos) { - RCaller rCaller = RCaller.create(frame, getOriginalCall()); REnvironment environment = envCast.execute(frame, envir, enclos); + RCaller rCaller = getCaller(frame, environment); try { return RContext.getEngine().eval(expr, environment, rCaller); } catch (ReturnException ret) { @@ -272,4 +273,12 @@ public abstract class Eval extends RBuiltinNode.Arg3 { visibility.execute(frame, true); return expr; } + + private RCaller getCaller(VirtualFrame frame, REnvironment environment) { + if (environment instanceof REnvironment.Function) { + return RArguments.getCall(environment.getFrame()); + } else { + return RCaller.create(frame, getOriginalCall()); + } + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java index 7eae87ef3866b9eb754f29a2c251b42923662118..336a2cf0b0154fd749988d7fce63335750014419 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/VirtualEvalFrame.java @@ -99,7 +99,12 @@ public abstract class VirtualEvalFrame extends SubstituteVirtualFrame implements Object[] arguments = Arrays.copyOf(originalFrame.getArguments(), originalFrame.getArguments().length); arguments[RArguments.INDEX_IS_IRREGULAR] = true; arguments[RArguments.INDEX_FUNCTION] = function; - arguments[RArguments.INDEX_CALL] = call; + if (call != null) { + // Otherwise leave here the call from originalFrame + arguments[RArguments.INDEX_CALL] = call; + } else if (arguments[RArguments.INDEX_CALL] == null) { + arguments[RArguments.INDEX_CALL] = RCaller.topLevel; + } MaterializedFrame unwrappedFrame = originalFrame instanceof SubstituteVirtualFrame ? ((SubstituteVirtualFrame) originalFrame).getOriginalFrame() : originalFrame; @SuppressWarnings("unchecked") Class<MaterializedFrame> clazz = (Class<MaterializedFrame>) unwrappedFrame.getClass(); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java index b31e710df2030d6d11415e6dfa360c7c3839b3d3..fda95437ebad45eeaccbaf9d2d422317f3ed76c4 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/Engine.java @@ -199,12 +199,14 @@ public interface Engine { Object parseAndEval(Source sourceDesc, MaterializedFrame frame, boolean printResult) throws ParseException; /** - * Support for the {@code eval} {@code .Internal}. + * Support for the {@code eval} {@code .Internal}. If the {@code caller} argument is null, it is + * taken from the environment's frame. */ Object eval(RExpression expr, REnvironment envir, RCaller caller); /** * Variant of {@link #eval(RExpression, REnvironment, RCaller)} for a single language element. + * If the {@code caller} argument is null, it is taken from the environment's frame. */ Object eval(RLanguage expr, REnvironment envir, RCaller caller); diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R index f74c7dce9e87076fa28e95d4f7281f5001495bf2..cf85ab25b37bee4c3d962a1907f945a09187c62d 100644 --- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R +++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/tests/simpleTests.R @@ -45,6 +45,21 @@ promiseInfo <- foo(tmp) stopifnot('some_unique_name' %in% ls(promiseInfo[[2]])) eval(promiseInfo[[1]], promiseInfo[[2]]) +# parent.frame call in Rf_eval. Simulates pattern from rlang package +getCurrEnv <- function(r = parent.frame()) r +fn <- function(eval_fn) { + list(middle(eval_fn), getCurrEnv()) +} +middle <- function(eval_fn) { + deep(eval_fn, getCurrEnv()) +} +deep <- function(eval_fn, eval_env) { + # the result value of rffi.tryEval is list, first element is the actual result + eval_fn(quote(parent.frame()), eval_env)[[1]] +} +res <- fn(rffi.tryEval) +stopifnot(identical(res[[1]], res[[2]])) + # fiddling the pointers to the native arrays: we get data pointer to the first SEXP argument (vec), # then put value 42/TRUE directly into it at index 0, # value of symbol 'myvar' through Rf_eval at index 1, diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 1589d9a4709b19317a4c41ff9db479ca6ab967d2..cc7e4e4fea9a0a6c3a0e75245573104b2bb8a1ae 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -25299,6 +25299,13 @@ x #{ ne <- new.env(); evalq(x <- 1, ne); ls(ne) } [1] "x" +##com.oracle.truffle.r.test.builtins.TestBuiltin_eval.testEvalVisibility# +#eval(parse(text='1+1')) +[1] 2 + +##com.oracle.truffle.r.test.builtins.TestBuiltin_eval.testEvalVisibility# +#eval(parse(text='x<-1')) + ##com.oracle.truffle.r.test.builtins.TestBuiltin_eval.testReturnInEvalExpr# #f1 <- function(x) { eval(quote(if(x>2){return()}else 1)); 10 };f1(5);f1(0) [1] 10 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eval.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eval.java index 55adc7d42e2b2566e2abe645d2fab23070a85a6c..fc2a2d8923fec2e133c1af559ba429a42d54e5e9 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eval.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/builtins/TestBuiltin_eval.java @@ -68,4 +68,10 @@ public class TestBuiltin_eval extends TestBase { public void testReturnInEvalExpr() { assertEval("f1 <- function(x) { eval(quote(if(x>2){return()}else 1)); 10 };f1(5);f1(0)"); } + + @Test + public void testEvalVisibility() { + assertEval("eval(parse(text='x<-1'))"); + assertEval("eval(parse(text='1+1'))"); + } }