diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
index ac33e442961a5780f765c997ff903018c2a2e93e..283b32fc899b0684a18c908a201752c1837ec14d 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/REngine.java
@@ -106,7 +106,6 @@ import com.oracle.truffle.r.runtime.env.frame.ActiveBinding;
 import com.oracle.truffle.r.runtime.env.frame.FrameSlotChangeMonitor;
 import com.oracle.truffle.r.runtime.interop.R2Foreign;
 import com.oracle.truffle.r.runtime.interop.R2ForeignNodeGen;
-import com.oracle.truffle.r.runtime.nodes.RCodeBuilder;
 import com.oracle.truffle.r.runtime.nodes.RNode;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxElement;
 import com.oracle.truffle.r.runtime.nodes.RSyntaxNode;
@@ -616,7 +615,7 @@ final class REngine implements Engine, Engine.Timings {
                 if (printResult && result != null) {
                     assert topLevel;
                     if (visibility.execute(vf)) {
-                        printResultImpl(result);
+                        printResultImpl(RContext.getInstance(), result);
                     }
                 }
                 if (topLevel) {
@@ -684,19 +683,23 @@ final class REngine implements Engine, Engine.Timings {
     }
 
     @Override
-    public void printResult(Object originalResult) {
-        printResultImpl(originalResult);
+    public void printResult(RContext ctx, Object originalResult) {
+        printResultImpl(ctx, originalResult);
     }
 
     @TruffleBoundary
-    static void printResultImpl(Object originalResult) {
+    static void printResultImpl(RContext ctx, Object originalResult) {
         Object result = evaluatePromise(originalResult);
         result = RRuntime.asAbstractVector(result);
+        MaterializedFrame callingFrame = REnvironment.globalEnv(ctx).getFrame();
+        printValue(ctx, callingFrame, result);
+    }
+
+    private static void printValue(RContext ctx, MaterializedFrame callingFrame, Object result) {
         if (result instanceof RTypedValue || result instanceof TruffleObject) {
             Object resultValue = ShareObjectNode.share(evaluatePromise(result));
-            MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame();
             if (result instanceof RAttributable && ((RAttributable) result).isS4()) {
-                Object printMethod = REnvironment.getRegisteredNamespace("methods").get("show");
+                Object printMethod = REnvironment.getRegisteredNamespace(ctx, "methods").get("show");
                 RFunction function = (RFunction) evaluatePromise(printMethod);
                 CallRFunctionNode.executeSlowpath(function, RCaller.createInvalid(callingFrame), callingFrame, new Object[]{resultValue}, null);
             } else {
@@ -719,27 +722,6 @@ final class REngine implements Engine, Engine.Timings {
         }
     }
 
-    /*
-     * This abstracts the calling convention, etc. behind the RASTBuilder, but creating large
-     * amounts of CallTargets during testing is too much overhead at the moment.
-     */
-    @SuppressWarnings("unused")
-    private void printAlternative(Object result) {
-        Object printFunction;
-        if (result instanceof RAttributable && ((RAttributable) result).isS4()) {
-            printFunction = REnvironment.getRegisteredNamespace("methods").get("show");
-        } else {
-            printFunction = REnvironment.getRegisteredNamespace("base").get("print");
-        }
-        RFunction function = (RFunction) evaluatePromise(printFunction);
-
-        MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame();
-        // create a piece of AST to perform the call
-        RCodeBuilder<RSyntaxNode> builder = RContext.getASTBuilder();
-        RSyntaxNode call = builder.call(RSyntaxNode.LAZY_DEPARSE, builder.constant(RSyntaxNode.LAZY_DEPARSE, function), builder.constant(RSyntaxNode.LAZY_DEPARSE, result));
-        doMakeCallTarget(call.asRNode(), RSource.Internal.EVAL_WRAPPER.string, false, false).call(callingFrame);
-    }
-
     private static Object evaluatePromise(Object value) {
         return value instanceof RPromise ? PromiseHelperNode.evaluateSlowPath((RPromise) value) : value;
     }
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 ca17d26f435d74daa2f00e0468baf057a3d9dc08..4039b565c5716f0f804e4da332dcbbeb7095477c 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
@@ -1997,6 +1997,11 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI {
         return new VectorWrapper(guaranteeVectorOrNull(x, CharSXPWrapper.class));
     }
 
+    @Override
+    public void Rf_PrintValue(Object value) {
+        throw implementedAsNode();
+    }
+
     private static TruffleObject guaranteeVectorOrNull(Object obj, Class<? extends TruffleObject> clazz) {
         if (obj == RNull.instance) {
             return RNull.instance;
diff --git a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
index 79eecdc8078f5bff3db1aa1d48989e59ae8177eb..1b2b55205c58fd9e3de6a7f9463a2ea1a1d20cd1 100644
--- a/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
+++ b/com.oracle.truffle.r.ffi.impl/src/com/oracle/truffle/r/ffi/impl/nodes/MiscNodes.java
@@ -52,11 +52,13 @@ import com.oracle.truffle.r.nodes.attributes.SpecialAttributesFunctionsFactory.S
 import com.oracle.truffle.r.nodes.builtin.EnvironmentNodes.GetFunctionEnvironmentNode;
 import com.oracle.truffle.r.nodes.builtin.casts.fluent.CastNodeBuilder;
 import com.oracle.truffle.r.nodes.function.FunctionDefinitionNode;
+import com.oracle.truffle.r.nodes.function.call.RExplicitCallNode;
 import com.oracle.truffle.r.nodes.objects.NewObject;
 import com.oracle.truffle.r.nodes.objects.NewObjectNodeGen;
 import com.oracle.truffle.r.nodes.unary.CastNode;
 import com.oracle.truffle.r.nodes.unary.SizeToOctalRawNode;
 import com.oracle.truffle.r.runtime.RError;
+import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.data.CharSXPWrapper;
 import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames;
 import com.oracle.truffle.r.runtime.data.RFunction;
@@ -360,4 +362,12 @@ public final class MiscNodes {
             return OctSizeNodeGen.create();
         }
     }
+
+    public static final class RfPrintValueNode extends FFIUpCallNode.Arg1 {
+        @Override
+        public Object executeObject(Object value) {
+            RContext.getEngine().printResult(RContext.getInstance(), value);
+            return RNull.instance;
+        }
+    }
 }
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 3bb818f4b30721b643f928494f6f2f5dfa0ef0ce..b8a3e57d37d131c77f54c6958486d8965e12e4b5 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
@@ -455,4 +455,6 @@ public interface StdUpCallsRFFI {
     @RFFIUpCallNode(MiscNodes.OctSizeNode.class)
     Object octsize(Object size);
 
+    @RFFIUpCallNode(MiscNodes.RfPrintValueNode.class)
+    void Rf_PrintValue(Object value);
 }
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
index 673d871727f2ad590e1fc44bb8e17fe7cc4ca23e..f483086b448e76dfc39b4f18b41f8ebe5311de1b 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcalls.h
@@ -290,6 +290,7 @@ typedef SEXP (*call_R_ParseVector)(SEXP text, int n, SEXP srcFile);
 typedef SEXPTYPE (*call_Rf_str2type)(const char *s);
 typedef SEXP (*call_CLOENV)(SEXP closure);
 typedef SEXP (*call_octsize)(SEXP size);
+typedef void (*call_Rf_PrintValue)(SEXP x);
 
 // connections
 
diff --git a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
index be731d8ff016ecebcd73df8124bfd0222f8a4ce6..afa389d701d376db9b7f23622ef494ceddd381af 100644
--- a/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
+++ b/com.oracle.truffle.r.native/fficall/src/common/rffi_upcallsindex.h
@@ -1,4 +1,4 @@
-// GENERATED; DO NOT EDIT
+// GENERATED by com.oracle.truffle.r.ffi.processor.FFIProcessor class; DO NOT EDIT
 #ifndef RFFI_UPCALLSINDEX_H
 #define RFFI_UPCALLSINDEX_H
 
@@ -94,103 +94,104 @@
 #define Rf_GetOption1_x 89
 #define Rf_NonNullStringMatch_x 90
 #define Rf_PairToVectorList_x 91
-#define Rf_ScalarDouble_x 92
-#define Rf_ScalarInteger_x 93
-#define Rf_ScalarLogical_x 94
-#define Rf_ScalarString_x 95
-#define Rf_VectorToPairList_x 96
-#define Rf_allocArray_x 97
-#define Rf_allocMatrix_x 98
-#define Rf_allocVector_x 99
-#define Rf_any_duplicated_x 100
-#define Rf_asChar_x 101
-#define Rf_asCharacterFactor_x 102
-#define Rf_asInteger_x 103
-#define Rf_asLogical_x 104
-#define Rf_asReal_x 105
-#define Rf_classgets_x 106
-#define Rf_coerceVector_x 107
-#define Rf_cons_x 108
-#define Rf_copyListMatrix_x 109
-#define Rf_copyMatrix_x 110
-#define Rf_copyMostAttrib_x 111
-#define Rf_dchisq_x 112
-#define Rf_defineVar_x 113
-#define Rf_dnchisq_x 114
-#define Rf_dunif_x 115
-#define Rf_duplicate_x 116
-#define Rf_error_x 117
-#define Rf_errorcall_x 118
-#define Rf_eval_x 119
-#define Rf_findFun_x 120
-#define Rf_findVar_x 121
-#define Rf_findVarInFrame_x 122
-#define Rf_findVarInFrame3_x 123
-#define Rf_getAttrib_x 124
-#define Rf_gsetVar_x 125
-#define Rf_inherits_x 126
-#define Rf_install_x 127
-#define Rf_installChar_x 128
-#define Rf_isNull_x 129
-#define Rf_isString_x 130
-#define Rf_lengthgets_x 131
-#define Rf_match_x 132
-#define Rf_mkCharLenCE_x 133
-#define Rf_namesgets_x 134
-#define Rf_ncols_x 135
-#define Rf_nrows_x 136
-#define Rf_pchisq_x 137
-#define Rf_pnchisq_x 138
-#define Rf_protect_x 139
-#define Rf_punif_x 140
-#define Rf_qchisq_x 141
-#define Rf_qnchisq_x 142
-#define Rf_qunif_x 143
-#define Rf_rchisq_x 144
-#define Rf_rnchisq_x 145
-#define Rf_runif_x 146
-#define Rf_setAttrib_x 147
-#define Rf_str2type_x 148
-#define Rf_unprotect_x 149
-#define Rf_unprotect_ptr_x 150
-#define Rf_warning_x 151
-#define Rf_warningcall_x 152
-#define Rprintf_x 153
-#define SETCADR_x 154
-#define SETCAR_x 155
-#define SETCDR_x 156
-#define SET_BODY_x 157
-#define SET_CLOENV_x 158
-#define SET_FORMALS_x 159
-#define SET_NAMED_FASTR_x 160
-#define SET_RDEBUG_x 161
-#define SET_RSTEP_x 162
-#define SET_S4_OBJECT_x 163
-#define SET_STRING_ELT_x 164
-#define SET_SYMVALUE_x 165
-#define SET_TAG_x 166
-#define SET_TYPEOF_FASTR_x 167
-#define SET_VECTOR_ELT_x 168
-#define STRING_ELT_x 169
-#define SYMVALUE_x 170
-#define TAG_x 171
-#define TYPEOF_x 172
-#define UNSET_S4_OBJECT_x 173
-#define VECTOR_ELT_x 174
-#define forceSymbols_x 175
-#define getCCallable_x 176
-#define getConnectionClassString_x 177
-#define getOpenModeString_x 178
-#define getSummaryDescription_x 179
-#define isSeekable_x 180
-#define octsize_x 181
-#define registerCCallable_x 182
-#define registerRoutines_x 183
-#define restoreHandlerStacks_x 184
-#define setDotSymbolValues_x 185
-#define unif_rand_x 186
-#define useDynamicSymbols_x 187
+#define Rf_PrintValue_x 92
+#define Rf_ScalarDouble_x 93
+#define Rf_ScalarInteger_x 94
+#define Rf_ScalarLogical_x 95
+#define Rf_ScalarString_x 96
+#define Rf_VectorToPairList_x 97
+#define Rf_allocArray_x 98
+#define Rf_allocMatrix_x 99
+#define Rf_allocVector_x 100
+#define Rf_any_duplicated_x 101
+#define Rf_asChar_x 102
+#define Rf_asCharacterFactor_x 103
+#define Rf_asInteger_x 104
+#define Rf_asLogical_x 105
+#define Rf_asReal_x 106
+#define Rf_classgets_x 107
+#define Rf_coerceVector_x 108
+#define Rf_cons_x 109
+#define Rf_copyListMatrix_x 110
+#define Rf_copyMatrix_x 111
+#define Rf_copyMostAttrib_x 112
+#define Rf_dchisq_x 113
+#define Rf_defineVar_x 114
+#define Rf_dnchisq_x 115
+#define Rf_dunif_x 116
+#define Rf_duplicate_x 117
+#define Rf_error_x 118
+#define Rf_errorcall_x 119
+#define Rf_eval_x 120
+#define Rf_findFun_x 121
+#define Rf_findVar_x 122
+#define Rf_findVarInFrame_x 123
+#define Rf_findVarInFrame3_x 124
+#define Rf_getAttrib_x 125
+#define Rf_gsetVar_x 126
+#define Rf_inherits_x 127
+#define Rf_install_x 128
+#define Rf_installChar_x 129
+#define Rf_isNull_x 130
+#define Rf_isString_x 131
+#define Rf_lengthgets_x 132
+#define Rf_match_x 133
+#define Rf_mkCharLenCE_x 134
+#define Rf_namesgets_x 135
+#define Rf_ncols_x 136
+#define Rf_nrows_x 137
+#define Rf_pchisq_x 138
+#define Rf_pnchisq_x 139
+#define Rf_protect_x 140
+#define Rf_punif_x 141
+#define Rf_qchisq_x 142
+#define Rf_qnchisq_x 143
+#define Rf_qunif_x 144
+#define Rf_rchisq_x 145
+#define Rf_rnchisq_x 146
+#define Rf_runif_x 147
+#define Rf_setAttrib_x 148
+#define Rf_str2type_x 149
+#define Rf_unprotect_x 150
+#define Rf_unprotect_ptr_x 151
+#define Rf_warning_x 152
+#define Rf_warningcall_x 153
+#define Rprintf_x 154
+#define SETCADR_x 155
+#define SETCAR_x 156
+#define SETCDR_x 157
+#define SET_BODY_x 158
+#define SET_CLOENV_x 159
+#define SET_FORMALS_x 160
+#define SET_NAMED_FASTR_x 161
+#define SET_RDEBUG_x 162
+#define SET_RSTEP_x 163
+#define SET_S4_OBJECT_x 164
+#define SET_STRING_ELT_x 165
+#define SET_SYMVALUE_x 166
+#define SET_TAG_x 167
+#define SET_TYPEOF_FASTR_x 168
+#define SET_VECTOR_ELT_x 169
+#define STRING_ELT_x 170
+#define SYMVALUE_x 171
+#define TAG_x 172
+#define TYPEOF_x 173
+#define UNSET_S4_OBJECT_x 174
+#define VECTOR_ELT_x 175
+#define forceSymbols_x 176
+#define getCCallable_x 177
+#define getConnectionClassString_x 178
+#define getOpenModeString_x 179
+#define getSummaryDescription_x 180
+#define isSeekable_x 181
+#define octsize_x 182
+#define registerCCallable_x 183
+#define registerRoutines_x 184
+#define restoreHandlerStacks_x 185
+#define setDotSymbolValues_x 186
+#define unif_rand_x 187
+#define useDynamicSymbols_x 188
 
-#define UPCALLS_TABLE_SIZE 188
+#define UPCALLS_TABLE_SIZE 189
 
 #endif // RFFI_UPCALLSINDEX_H
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 aaf82384b184450d1e136097cbfa4b44f8dd95e1..7d361d1da12e6d16e81dedbe7b9541b8f5db11a4 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
@@ -490,7 +490,8 @@ Rboolean Rf_isObject(SEXP s) {
 
 void Rf_PrintValue(SEXP x) {
     TRACE0();
-    unimplemented("Rf_PrintValue");
+    ((call_Rf_PrintValue) callbacks[Rf_PrintValue_x])(x);
+    checkExitCall();
 }
 
 SEXP Rf_install(const char *name) {
diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source
index e373ee695f6e76d7d3f8f8c4e92d1d60995352e5..82cced27d7be32719d009707139bd949ad6263c9 100644
--- a/com.oracle.truffle.r.native/version.source
+++ b/com.oracle.truffle.r.native/version.source
@@ -1 +1 @@
-50
+51
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java
index 34c497312c3d81afee5bd7d0c35da9d39266736d..4df7b6905fc49ccf0a9c85da1bd25854a7a25507 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/AttributesPrinter.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2013,  The R Core Team
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -94,12 +94,13 @@ final class AttributesPrinter implements ValuePrinter<RAttributable> {
             int origLen = buff.length();
             buff.append(tag);
 
-            if (RContext.getInstance().isMethodTableDispatchOn() && utils.isS4(a.getValue())) {
+            RContext ctx = RContext.getInstance();
+            if (ctx.isMethodTableDispatchOn() && utils.isS4(a.getValue())) {
                 S4ObjectPrinter.printS4(printCtx, a.getValue());
                 // throw new UnsupportedOperationException("TODO");
             } else {
                 if (a.getValue() instanceof RAttributable && ((RAttributable) a.getValue()).isObject()) {
-                    RContext.getEngine().printResult(a.getValue());
+                    RContext.getEngine().printResult(ctx, a.getValue());
                 } else {
                     ValuePrinters.INSTANCE.print(a.getValue(), printCtx);
                 }
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
index 65694c0578f9cc5c94f3c3b15bddb268ab7e8056..4fa95a508ed285bc4b6c9a80ccd6183c0d5d2677 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/printer/ListPrinter.java
@@ -5,7 +5,7 @@
  *
  * Copyright (c) 1995, 1996  Robert Gentleman and Ross Ihaka
  * Copyright (c) 1997-2013,  The R Core Team
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates
  *
  * All rights reserved.
  */
@@ -203,7 +203,7 @@ final class ListPrinter extends AbstractValuePrinter<RAbstractListVector> {
                 out.println(tagbuf);
                 Object si = s.getDataAt(i);
                 if (si instanceof RAttributable && ((RAttributable) si).isObject()) {
-                    RContext.getEngine().printResult(si);
+                    RContext.getEngine().printResult(RContext.getInstance(), si);
                 } else {
                     ValuePrinters.INSTANCE.print(si, printCtx);
                     ValuePrinters.printNewLine(printCtx);
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 a3f5d4b98c8e8c6e2c16d0e21b4d104ae7c6390b..998f2e895d819e4bfaff297aaa4242f2361e9039 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
@@ -256,7 +256,7 @@ public interface Engine {
      * Used by Truffle debugger; invokes the internal "print" support in R for {@code value}.
      * Essentially this is equivalent to {@link #evalFunction} using the {@code "print"} function.
      */
-    void printResult(Object value);
+    void printResult(RContext ctx, Object value);
 
     /**
      * Return the "global" frame for this {@link Engine}, aka {@code globalEnv}.