From 2f1ca723dfae85a3fa8e890d2b264cbcea299e33 Mon Sep 17 00:00:00 2001 From: stepan <stepan.sindelar@oracle.com> Date: Wed, 3 Jan 2018 16:44:34 +0100 Subject: [PATCH] Fixes in eval, Rf_eval and implement R_tryEval --- .../ffi/impl/common/JavaUpCallsRFFIImpl.java | 14 +----- .../truffle/r/ffi/impl/nodes/RfEvalNode.java | 4 +- .../r/ffi/impl/nodes/TryRfEvalNode.java | 44 +++++++++++++++++++ .../r/ffi/impl/upcalls/StdUpCallsRFFI.java | 3 ++ .../Rinternals_truffle_common.h | 2 +- .../truffle/r/nodes/builtin/base/Eval.java | 13 +++++- .../truffle/r/runtime/VirtualEvalFrame.java | 7 ++- .../truffle/r/runtime/context/Engine.java | 4 +- .../testrffi/testrffi/tests/simpleTests.R | 15 +++++++ .../truffle/r/test/ExpectedTestOutput.test | 7 +++ .../r/test/builtins/TestBuiltin_eval.java | 6 +++ 11 files changed, 99 insertions(+), 20 deletions(-) create mode 100644 com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/TryRfEvalNode.java 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 eeb5dd0ceb..7a2924577a 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 da3d249e0d..ae738c977a 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 0000000000..64d544f386 --- /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 90dba617d4..1f85756b25 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 c305453c28..7a7193a66c 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 01d7eaa017..906f67906e 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 7eae87ef38..336a2cf0b0 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 b31e710df2..fda95437eb 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 f74c7dce9e..cf85ab25b3 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 1589d9a470..cc7e4e4fea 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 55adc7d42e..fc2a2d8923 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'))"); + } } -- GitLab