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 7ecb06de9682124a077836b1834a817c7705bf77..ca2133ea918c645f2efcfcac3ae892d6972d27eb 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
@@ -371,10 +371,10 @@ final class REngine implements Engine, Engine.Timings {
             RContext.setThreadLocalInstance(newContext);
             try {
                 Object lastValue = RNull.instance;
-                for (int i = 0; i < statements.size(); i++) {
-                    RSyntaxNode node = statements.get(i);
+                for (int i = 0; i < calls.length; i++) {
                     if (calls[i] == null) {
                         CompilerDirectives.transferToInterpreterAndInvalidate();
+                        RSyntaxNode node = statements.get(i);
                         calls[i] = insert(Truffle.getRuntime().createDirectCallNode(doMakeCallTarget(node.asRNode(), RSource.Internal.REPL_WRAPPER.string, printResult, true)));
                     }
                     lastValue = calls[i].call(new Object[]{executionFrame != null ? executionFrame : newContext.stateREnvironment.getGlobalFrame()});
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java
index 82f194dcdc6c9aae2fd1b4a221be85eedfaa681e..c62c3b20335d81ad01044fb019e7a0433ef9c43f 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RArgsValuesAndNamesMR.java
@@ -45,6 +45,13 @@ public class RArgsValuesAndNamesMR {
         }
     }
 
+    @Resolve(message = "GET_SIZE")
+    public abstract static class RArgsValuesAndNamesGetSizeNode extends Node {
+        protected Object access(RArgsValuesAndNames receiver) {
+            return receiver.getLength();
+        }
+    }
+
     @Resolve(message = "IS_NULL")
     public abstract static class RArgsValuesAndNamesIsNullNode extends Node {
         protected Object access(@SuppressWarnings("unused") RArgsValuesAndNames receiver) {
@@ -52,6 +59,13 @@ public class RArgsValuesAndNamesMR {
         }
     }
 
+    @Resolve(message = "READ")
+    public abstract static class RArgsValuesAndNamesReadNode extends Node {
+        protected Object access(RArgsValuesAndNames receiver, int index) {
+            return receiver.getArgument(index);
+        }
+    }
+
     @CanResolve
     public abstract static class RArgsValuesAndNamesCheck extends Node {
 
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java
index 94e27017981917fb8c9f1b4dcf3b84dcbcc1e967..e8104c310ff3334ca899365ce8fd1c27a0a2b6a8 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/REnvironmentMR.java
@@ -97,6 +97,34 @@ public class REnvironmentMR {
         }
     }
 
+    @Resolve(message = "KEYS")
+    public abstract static class REnvironmentKeysNode extends Node {
+
+        protected Object access(REnvironment receiver) {
+            return receiver.ls(true, null, true);
+        }
+    }
+
+    @Resolve(message = "KEY_INFO")
+    public abstract static class REnvironmentKeyInfoNode extends Node {
+
+        private static final int READABLE = 1 << 1;
+        private static final int WRITABLE = 1 << 2;
+
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, REnvironment receiver, String identifier) {
+            Object val = receiver.get(identifier);
+            if (val == null) {
+                return 0;
+            }
+
+            int info = READABLE;
+            if (!receiver.isLocked() && !receiver.bindingIsLocked(identifier)) {
+                info += WRITABLE;
+            }
+            return info;
+        }
+    }
+
     @CanResolve
     public abstract static class REnvironmentCheck extends Node {
 
diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
index 269143e33d5aa41dd48a18f2aec5c30fb7c6d009..589fd7f8c78e1c4c3c5fbb4cb5bf2721d8832ea0 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/RPromiseMR.java
@@ -22,40 +22,125 @@
  */
 package com.oracle.truffle.r.engine.interop;
 
+import com.oracle.truffle.api.frame.VirtualFrame;
 import com.oracle.truffle.api.interop.CanResolve;
 import com.oracle.truffle.api.interop.MessageResolution;
 import com.oracle.truffle.api.interop.Resolve;
 import com.oracle.truffle.api.interop.TruffleObject;
+import com.oracle.truffle.api.interop.UnknownIdentifierException;
+import com.oracle.truffle.api.interop.UnsupportedTypeException;
 import com.oracle.truffle.api.nodes.Node;
+import com.oracle.truffle.r.engine.TruffleRLanguageImpl;
+import com.oracle.truffle.r.ffi.impl.interop.NativePointer;
+import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
+import com.oracle.truffle.r.runtime.RRuntime;
+import com.oracle.truffle.r.runtime.context.RContext;
+import com.oracle.truffle.r.runtime.context.RContext.RCloseable;
+import com.oracle.truffle.r.runtime.data.RDataFactory;
+import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RPromise;
 
 @MessageResolution(receiverType = RPromise.class)
 public class RPromiseMR {
+
+    private static final String PROP_VALUE = "value";
+    private static final String PROP_IS_EVALUATED = "isEvaluated";
+    private static final String PROP_IS_EAGER = "isEager";
+
     @Resolve(message = "IS_BOXED")
     public abstract static class RPromiseIsBoxedNode extends Node {
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
-            return true;
+            return false;
         }
     }
 
-    @Resolve(message = "HAS_SIZE")
-    public abstract static class RPromiseHasSizeNode extends Node {
+    @Resolve(message = "IS_NULL")
+    public abstract static class RPromiseIsNullNode extends Node {
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
             return false;
         }
     }
 
-    @Resolve(message = "IS_NULL")
-    public abstract static class RPromiseIsNullNode extends Node {
+    @Resolve(message = "READ")
+    public abstract static class RPromiseReadNode extends Node {
+
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, RPromise receiver, String field) {
+            if (PROP_IS_EAGER.equals(field)) {
+                return RRuntime.asLogical(RPromise.PromiseState.isEager(receiver.getState()));
+            }
+            if (PROP_IS_EVALUATED.equals(field)) {
+                return RRuntime.asLogical(receiver.isEvaluated());
+            }
+            if (PROP_VALUE.equals(field)) {
+                // only read value if evaluated
+                if (receiver.isEvaluated()) {
+                    return receiver.getValue();
+                }
+                return RNull.instance;
+            }
+            throw UnknownIdentifierException.raise(field);
+        }
+    }
+
+    @Resolve(message = "WRITE")
+    public abstract static class RPromiseWriteNode extends Node {
+
+        @SuppressWarnings("try")
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, RPromise receiver, String field, Object valueObj) {
+            if (PROP_IS_EVALUATED.equals(field)) {
+                if (!(valueObj instanceof Boolean)) {
+                    throw UnsupportedTypeException.raise(new Object[]{valueObj});
+                }
+
+                boolean newVal = (boolean) valueObj;
+
+                if (!receiver.isEvaluated() && newVal) {
+                    try (RCloseable c = RContext.withinContext(TruffleRLanguageImpl.getCurrentContext())) {
+                        PromiseHelperNode.evaluateSlowPath(receiver);
+                    }
+                } else if (receiver.isEvaluated() && !newVal) {
+                    try (RCloseable c = RContext.withinContext(TruffleRLanguageImpl.getCurrentContext())) {
+                        receiver.resetValue();
+                    }
+
+                }
+                return RRuntime.asLogical(receiver.isEvaluated());
+            }
+            throw UnknownIdentifierException.raise(field);
+        }
+    }
+
+    @Resolve(message = "KEYS")
+    public abstract static class RPromiseKeysNode extends Node {
+
         protected Object access(@SuppressWarnings("unused") RPromise receiver) {
-            return false;
+            return RDataFactory.createStringVector(new String[]{PROP_VALUE, PROP_IS_EVALUATED, PROP_IS_EAGER}, true);
+        }
+    }
+
+    @Resolve(message = "KEY_INFO")
+    public abstract static class RPromiseKeyInfoNode extends Node {
+
+        private static final int READABLE = 1 << 1;
+        private static final int WRITABLE = 1 << 2;
+
+        @SuppressWarnings("try")
+        protected Object access(@SuppressWarnings("unused") VirtualFrame frame, @SuppressWarnings("unused") RPromise receiver, String identifier) {
+            if (PROP_IS_EAGER.equals(identifier) || PROP_VALUE.equals(identifier)) {
+                return READABLE;
+            }
+
+            if (PROP_IS_EVALUATED.equals(identifier)) {
+                return READABLE + WRITABLE;
+            }
+            return 0;
         }
     }
 
-    @Resolve(message = "UNBOX")
-    public abstract static class RPromiseUnboxNode extends Node {
+    @Resolve(message = "TO_NATIVE")
+    public abstract static class RPromiseToNativeNode extends Node {
         protected Object access(RPromise receiver) {
-            return receiver.getValue();
+            return new NativePointer(receiver);
         }
     }
 
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
index 7d4472033f6520900409cbccebb4933a2633da1d..341d8f9acd9856a6af3435377f670126cf1796d7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java
@@ -423,6 +423,7 @@ public class BasePackage extends RBuiltinPackage {
         add(FastRInterop.IsExternal.class, FastRInteropFactory.IsExternalNodeGen::create);
         add(FastRInterop.JavaClass.class, FastRInteropFactory.JavaClassNodeGen::create);
         add(FastRInterop.JavaClassName.class, FastRInteropFactory.JavaClassNameNodeGen::create);
+        add(FastRInterop.JavaAddClasspathEntry.class, FastRInteropFactory.JavaAddClasspathEntryNodeGen::create);
         add(FastRInterop.IsForeignArray.class, FastRInteropFactory.IsForeignArrayNodeGen::create);
         add(FastRInterop.NewJavaArray.class, FastRInteropFactory.NewJavaArrayNodeGen::create);
         add(FastRInterop.ToJavaArray.class, FastRInteropFactory.ToJavaArrayNodeGen::create);
diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
index dfd0f56b4b0b838e32dd325082c79f321c61e51c..d87fd82091ed6cbb1fc7a5d44dc98354595db5a7 100644
--- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
+++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java
@@ -39,6 +39,7 @@ import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.Array;
+import java.net.MalformedURLException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -83,7 +84,6 @@ import com.oracle.truffle.r.runtime.data.RList;
 import com.oracle.truffle.r.runtime.data.RMissing;
 import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
-import com.oracle.truffle.r.runtime.data.RTypedValue;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractLogicalVector;
@@ -120,7 +120,7 @@ public class FastRInterop {
 
         @SuppressWarnings("unused")
         @Specialization(guards = {"cachedMimeType != null", "cachedMimeType.equals(mimeType)", "cachedSource != null", "cachedSource.equals(source)"})
-        protected Object evalCached(String mimeType, String source, @SuppressWarnings("unused") RMissing path,
+        protected Object evalCached(String mimeType, String source, RMissing path,
                         @Cached("mimeType") String cachedMimeType,
                         @Cached("source") String cachedSource,
                         @Cached("createCall(mimeType, source)") DirectCallNode call) {
@@ -133,9 +133,10 @@ public class FastRInterop {
             return parse(mimeType, source).call();
         }
 
+        @SuppressWarnings("unused")
         @Specialization()
         @TruffleBoundary
-        protected Object eval(@SuppressWarnings("unused") RMissing mimeType, String source, @SuppressWarnings("unused") RMissing path) {
+        protected Object eval(RMissing mimeType, String source, RMissing path) {
             throw RError.error(this, RError.Message.INVALID_ARG, "mimeType");
         }
 
@@ -440,7 +441,8 @@ public class FastRInterop {
         @TruffleBoundary
         public TruffleObject javaClass(String clazz, boolean silent) {
             try {
-                return JavaInterop.asTruffleObject(Class.forName(clazz.replaceAll("/", ".")));
+                ClassLoader interopClassLoader = RContext.getInstance().getInteropClassLoader();
+                return JavaInterop.asTruffleObject(interopClassLoader.loadClass(clazz.replaceAll("/", ".")));
             } catch (ClassNotFoundException | SecurityException | IllegalArgumentException e) {
                 if (silent) {
                     return RNull.instance;
@@ -450,6 +452,36 @@ public class FastRInterop {
         }
     }
 
+    @RBuiltin(name = "java.addClasspathEntry", visibility = OFF, kind = PRIMITIVE, parameterNames = {"value", "silent"}, behavior = COMPLEX)
+    public abstract static class JavaAddClasspathEntry extends RBuiltinNode.Arg2 {
+
+        static {
+            Casts casts = new Casts(JavaAddClasspathEntry.class);
+            casts.arg("value").mustBe(stringValue()).asStringVector();
+            casts.arg("silent").mapMissing(Predef.constant(RRuntime.LOGICAL_FALSE)).mustBe(logicalValue().or(Predef.nullValue())).asLogicalVector().mustBe(singleElement()).findFirst().mustBe(
+                            notLogicalNA()).map(Predef.toBoolean());
+        }
+
+        @Specialization
+        @TruffleBoundary
+        public TruffleObject addEntries(RAbstractStringVector value, boolean silent) {
+            try {
+                RContext ctx = RContext.getInstance();
+                String[] entriesArr = new String[value.getLength()];
+                for (int i = 0; i < value.getLength(); i++) {
+                    entriesArr[i] = value.getDataAt(i);
+                }
+                ctx.addInteropClasspathEntries(entriesArr);
+                return value;
+            } catch (MalformedURLException e) {
+                if (silent) {
+                    return RNull.instance;
+                }
+                throw error(RError.Message.GENERIC, "error while adding classpath entry: " + e.getMessage());
+            }
+        }
+    }
+
     @ImportStatic({RRuntime.class})
     @RBuiltin(name = "java.class", visibility = ON, kind = PRIMITIVE, parameterNames = {"class"}, behavior = COMPLEX)
     public abstract static class JavaClassName extends RBuiltinNode.Arg1 {
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
index b8f37f4b22ff8ed51c3e44747111c401049df864..d12bdff737d486141602d4b7d42c4a1d42bc3dae 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java
@@ -26,7 +26,11 @@ import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
 import java.io.Closeable;
 import java.lang.ref.WeakReference;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.TimeZone;
@@ -248,6 +252,9 @@ public final class RContext implements RTruffleObject {
 
     private PrimitiveMethodsInfo primitiveMethodsInfo;
 
+    /** Class loader for Java interop. */
+    private ClassLoader interopClassLoader = getClass().getClassLoader();
+
     /**
      * Set to {@code true} when in embedded mode to allow other parts of the system to determine
      * whether embedded mode is in effect, <b>before</b> the initial context is created.
@@ -809,4 +816,19 @@ public final class RContext implements RTruffleObject {
         }
     };
 
+    public ClassLoader getInteropClassLoader() {
+        return interopClassLoader;
+    }
+
+    /**
+     * Adds entries to the Java interop class loader. This will effectively create a new class
+     * loader with the previous one as parent.
+     */
+    public void addInteropClasspathEntries(String... entries) throws MalformedURLException {
+        URL[] urls = new URL[entries.length];
+        for (int i = 0; i < entries.length; i++) {
+            urls[i] = Paths.get(entries[i]).toUri().toURL();
+        }
+        interopClassLoader = URLClassLoader.newInstance(urls, interopClassLoader);
+    }
 }
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
index cdb65dbbb957235d9dfec9dc55625d5da653694b..d00b8e455b51a5c1f9798159a6c029ea78f64191 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/data/RPromise.java
@@ -203,6 +203,17 @@ public class RPromise implements RTypedValue {
         return value;
     }
 
+    /**
+     * Discards any previously evaluated value if this is not an eager promise. This is for
+     * debugging purposes only!
+     */
+    public final void resetValue() {
+        // Only non-eager promises can be reset.
+        if (!PromiseState.isEager(state)) {
+            value = null;
+        }
+    }
+
     /**
      * Used in case the {@link RPromise} is evaluated outside.
      *
diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/R2Foreign.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/R2Foreign.java
index 044a6e17d93da9ca5fc7e79a67f8846d6f870d44..84139962e0c9a827b4d07e0f93614741b74ea5e4 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/R2Foreign.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/interop/R2Foreign.java
@@ -24,15 +24,12 @@ package com.oracle.truffle.r.runtime.interop;
 
 import com.oracle.truffle.api.dsl.Fallback;
 import com.oracle.truffle.api.dsl.Specialization;
-import com.oracle.truffle.api.interop.TruffleObject;
-import com.oracle.truffle.api.interop.java.JavaInterop;
 import com.oracle.truffle.r.runtime.RRuntime;
 import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropByte;
 import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropChar;
 import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropFloat;
 import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropLong;
 import com.oracle.truffle.r.runtime.data.RInteropScalar.RInteropShort;
-import com.oracle.truffle.r.runtime.data.RNull;
 import com.oracle.truffle.r.runtime.data.RRaw;
 import com.oracle.truffle.r.runtime.data.model.RAbstractDoubleVector;
 import com.oracle.truffle.r.runtime.data.model.RAbstractIntVector;
@@ -91,7 +88,7 @@ public abstract class R2Foreign extends RBaseNode {
     }
 
     @Specialization(guards = "vec.getLength() == 1")
-    public String doStrignVector(RAbstractStringVector vec) {
+    public String doStringVector(RAbstractStringVector vec) {
         return vec.getDataAt(0);
     }
 
@@ -120,12 +117,6 @@ public abstract class R2Foreign extends RBaseNode {
         return obj.getValue();
     }
 
-    @Specialization
-    public TruffleObject doNull(@SuppressWarnings("unused") RNull obj) {
-        // TODO this is java interop specific
-        return JavaInterop.asTruffleObject(null);
-    }
-
     @Fallback
     public static Object doObject(Object obj) {
         return obj;
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
index 1254ab8c5d07ab638ac3f471ddafa3eec96652ee..6ac5634afde57abf29bc2ace4d80fa77dac4f8e5 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestJavaInterop.java
@@ -22,7 +22,6 @@
  */
 package com.oracle.truffle.r.test.library.fastr;
 
-import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter;
 import java.lang.reflect.Array;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
@@ -38,6 +37,7 @@ import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 
+import com.oracle.truffle.r.nodes.builtin.base.printer.DoubleVectorPrinter;
 import com.oracle.truffle.r.nodes.builtin.fastr.FastRInterop;
 import com.oracle.truffle.r.runtime.RType;
 import com.oracle.truffle.r.test.TestBase;
@@ -265,7 +265,7 @@ public class TestJavaInterop extends TestBase {
         assertEvalFastR("tc <- new.java.class('" + Long.class.getName() + "'); t <- new.external(tc, as.external.long(1)); t", "1");
         assertEvalFastR("tc <- new.java.class('" + Short.class.getName() + "'); t <- new.external(tc, as.external.short(1)); t", "1");
         assertEvalFastR("tc <- new.java.class('" + String.class.getName() + "'); t <- new.external(tc, 'abc'); t", "'abc'");
-        assertEvalFastR("tc <- new.java.class('" + TestNullClass.class.getName() + "'); t <- new.external(tc, NULL); class(t)", "'" + RType.TruffleObject.getName() + "'");
+        assertEvalFastR(Ignored.Unknown, "tc <- new.java.class('" + TestNullClass.class.getName() + "'); t <- new.external(tc, NULL); class(t)", "'" + RType.TruffleObject.getName() + "'");
     }
 
     @Test
@@ -647,7 +647,7 @@ public class TestJavaInterop extends TestBase {
     }
 
     @Test
-    public void testIf() throws IllegalArgumentException, IllegalAccessException {
+    public void testIf() throws IllegalArgumentException {
         TestClass t = new TestClass();
 
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + "if(to$fieldBoolean) print('OK')", "if(T) print('OK')");
@@ -671,7 +671,7 @@ public class TestJavaInterop extends TestBase {
     }
 
     @Test
-    public void testWhile() throws IllegalArgumentException, IllegalAccessException {
+    public void testWhile() throws IllegalArgumentException {
         TestClass t = new TestClass();
 
         assertEvalFastR(CREATE_TRUFFLE_OBJECT + "while(to$fieldBoolean) {print('OK'); break;}", "while(T) {print('OK'); break;}");
@@ -782,10 +782,11 @@ public class TestJavaInterop extends TestBase {
         StringBuilder sb = new StringBuilder();
         sb.append(asXXX);
         sb.append("(");
+        Object val = o;
         if (asXXX.equals("as.character") && (o instanceof Double || o instanceof Float)) {
-            o = DoubleVectorPrinter.encodeReal(((Number) o).doubleValue());
+            val = DoubleVectorPrinter.encodeReal(((Number) o).doubleValue());
         }
-        sb.append(getRValue(o));
+        sb.append(getRValue(val));
         sb.append(')');
         return sb.toString();
     }
@@ -802,7 +803,7 @@ public class TestJavaInterop extends TestBase {
         return sb.toString();
     }
 
-    private String getBooleanPrefix(Object value, int i) {
+    private static String getBooleanPrefix(Object value, int i) {
         if (value.getClass().getComponentType() == Boolean.TYPE && (boolean) Array.get(value, i)) {
             return " ";
         }
@@ -813,7 +814,7 @@ public class TestJavaInterop extends TestBase {
         return "";
     }
 
-    private String toArrayClassName(String className, int dims) {
+    private static String toArrayClassName(String className, int dims) {
         StringBuilder sb = new StringBuilder();
         sb.append("'");
         for (int i = 0; i < dims; i++) {
diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
index 134b0b01d3aeaa3f7ebe0ea709c59639fd178f46..ecc44d636bcc3f2e2f4b00347bacc0ddbbf2ee2f 100644
--- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
+++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java
@@ -38,6 +38,7 @@ import java.util.concurrent.atomic.AtomicInteger;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import com.oracle.truffle.api.debug.Breakpoint;
@@ -154,6 +155,39 @@ public class FastRDebugTest {
         assertEquals("Factorial computed OK", 2, n.intValue());
     }
 
+    /**
+     * Test is currently ignored because of missing functionality in Truffle.
+     */
+    @Test
+    @Ignore
+    public void testConditionalBreakpoint() throws Throwable {
+        final Source source = RSource.fromTextInternal("main <- function() {\n" +
+                        "  for(i in seq(10)) {\n" +
+                        "    print(i)\n" +
+                        "  }\n" +
+                        "}\n",
+                        RSource.Internal.DEBUGTEST_DEBUG);
+        engine.eval(source);
+
+        run.addLast(() -> {
+            assertNull(suspendedEvent);
+            assertNotNull(debuggerSession);
+            Breakpoint breakpoint = Breakpoint.newBuilder(source).lineIs(3).build();
+            breakpoint.setCondition("i == 5");
+            debuggerSession.install(breakpoint);
+        });
+
+        assertLocation(3, "print(i)", "i", "5");
+        continueExecution();
+
+        // Init before eval:
+        performWork();
+
+        final Source evalSrc = RSource.fromTextInternal("main()\n", RSource.Internal.DEBUGTEST_DEBUG);
+        engine.eval(evalSrc);
+        assertExecutedOK();
+    }
+
     @Test
     public void stepInStepOver() throws Throwable {
         final Source factorial = createFactorial();
diff --git a/documentation/tutorials/debugging/InteropDebugging/JS/main.js b/documentation/tutorials/debugging/InteropDebugging/JS/main.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1d81827fbda13ae1b5ee5f906f78c4f8a1ec3b3
--- /dev/null
+++ b/documentation/tutorials/debugging/InteropDebugging/JS/main.js
@@ -0,0 +1,5 @@
+var greeting = "Ahoy";
+var greet = function (x) {
+    console.log(x);
+}
+greet(greeting);
\ No newline at end of file
diff --git a/documentation/tutorials/debugging/InteropDebugging/R/main.r b/documentation/tutorials/debugging/InteropDebugging/R/main.r
new file mode 100644
index 0000000000000000000000000000000000000000..bff4979782d79865eb19346a5948be20224ec229
--- /dev/null
+++ b/documentation/tutorials/debugging/InteropDebugging/R/main.r
@@ -0,0 +1,40 @@
+#
+# 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.
+#
+
+print("Hello, World! (from file)")
+print("Creating a Java object in FastR")
+
+clazz <- .fastr.java.class("java.util.Date")
+obj <- .fastr.interop.new(clazz, .fastr.interop.toLong(as.integer(Sys.time())*1000))
+print(obj$toString())
+
+# add classpath entry to be able to use our class
+java.addClasspathEntry("build/classes")
+clazz <- .fastr.java.class("com.oracle.truffle.r.JavaMessage")
+obj <- .fastr.interop.new(clazz, "Hi there")
+print(obj$getMessage())
+
+JS_MIME_TYPE <- "application/javascript"
+.fastr.interop.eval(JS_MIME_TYPE, 'var s = "Hello from Javascript"; print(s)')
+.fastr.interop.evalFile("JS/main.js", JS_MIME_TYPE)
+
diff --git a/documentation/tutorials/debugging/InteropDebugging/manifest.mf b/documentation/tutorials/debugging/InteropDebugging/manifest.mf
new file mode 100644
index 0000000000000000000000000000000000000000..328e8e5bc3b7f1f7bad2bc0751a933e00c801983
--- /dev/null
+++ b/documentation/tutorials/debugging/InteropDebugging/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java
new file mode 100644
index 0000000000000000000000000000000000000000..a6ea29c3593eadf08671ee6bda744263f420bb97
--- /dev/null
+++ b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/JavaMessage.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.oracle.truffle.r;
+
+public class JavaMessage {
+
+    private String message;
+
+    public JavaMessage(String message) {
+        this.message = message;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    @Override
+    public String toString() {
+        return message;
+    }
+
+}
diff --git a/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java
new file mode 100644
index 0000000000000000000000000000000000000000..300a6e6390f598af2856a26f78a8fb2bfab53278
--- /dev/null
+++ b/documentation/tutorials/debugging/InteropDebugging/src/com/oracle/truffle/r/Main.java
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package com.oracle.truffle.r;
+
+import com.oracle.truffle.api.source.Source;
+import com.oracle.truffle.api.vm.PolyglotEngine;
+import java.io.File;
+import java.io.IOException;
+
+public class Main {
+
+    private static final String R_MIME_TYPE = "application/x-r";
+
+    /**
+     * @param args the command line arguments
+     * @throws java.io.IOException
+     */
+    public static void main(String[] args) throws IOException {
+        PolyglotEngine newVM = PolyglotEngine.newBuilder().config(R_MIME_TYPE, "debugContext", null).build();
+        newVM.eval(fromString("print('Hello, World! (from string)')"));
+        newVM.eval(fromFile("R/main.r"));
+    }
+    
+    private static Source fromString(String code) {
+        return Source.newBuilder(code).name("<shell_input>").mimeType(R_MIME_TYPE).interactive().build();
+    }
+    
+    private static Source fromFile(String path) throws IOException {
+        return Source.newBuilder(new File(path)).mimeType(R_MIME_TYPE).build();
+    }
+    
+}
diff --git a/documentation/tutorials/debugging/R/binSearch.r b/documentation/tutorials/debugging/R/binSearch.r
new file mode 100644
index 0000000000000000000000000000000000000000..4290216371d9b8f4725d7d2ee94d6cabf7dd1c5c
--- /dev/null
+++ b/documentation/tutorials/debugging/R/binSearch.r
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+# Returns the index of the value in the sorted vector.
+binSearch <- function(vec, value) {
+  low <- 1L
+  high <- length(vec)+1L
+  while(low < high) {
+    idx <- as.integer((low + high) / 2L)
+    if(vec[[idx]] == value) {
+      return (idx)
+    } else if(vec[[idx]] < value) {
+      low <- idx
+    } else { 
+      high <- idx
+    }
+  }
+}
diff --git a/documentation/tutorials/debugging/R/dummy.r b/documentation/tutorials/debugging/R/dummy.r
new file mode 100644
index 0000000000000000000000000000000000000000..a9904460ee5e673f58340dc3aca3f55eb169eee7
--- /dev/null
+++ b/documentation/tutorials/debugging/R/dummy.r
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+
+bar <- function(x) print(x)
+
+fun <- function(x) {
+	print("Hello")
+	for(i in seq(3)) print(i)
+	bar("World")
+	print(x)
+}
+
diff --git a/documentation/tutorials/debugging/R/dump.r b/documentation/tutorials/debugging/R/dump.r
new file mode 100644
index 0000000000000000000000000000000000000000..fc8a8b5b3c81dc6c8c6df58681101e4005e347e0
--- /dev/null
+++ b/documentation/tutorials/debugging/R/dump.r
@@ -0,0 +1,34 @@
+#
+# 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.
+#
+
+gen_data <- function() {
+    res <- list(rep(0, 100))
+    for(i in seq_along(res)) {
+        res[[i]] <- i %% 5
+    }
+    res
+}
+
+library(jsonlite)
+jsonStr <- toJSON(gen_data())
+cat(jsonStr)
diff --git a/documentation/tutorials/debugging/tutorial.md b/documentation/tutorials/debugging/tutorial.md
new file mode 100644
index 0000000000000000000000000000000000000000..6fb1eaf747af581308f67e0121c723adb071dac2
--- /dev/null
+++ b/documentation/tutorials/debugging/tutorial.md
@@ -0,0 +1,148 @@
+# FastR NetBeans Debugging Tutorial
+
+## Getting started
+
+Read the documentation in *documentation/debugging.md* in FastR's GitHub repository.
+In order to suppress annoying stack traces when you (accidentally) enter values in the variables view, start FastR with option `--J @-Dtruffle.nbdebug.supressLangErrs=true`.
+
+Let's start with a simple example.
+```R
+source("R/binSearch.r")
+binSearch(1:100, 1)
+binSearch(1:100, 100)
+binSearch(1:100, 50)
+binSearch(1:100, 67)
+binSearch(1:100, 0)
+binSearch(1:100, 101) # why does this not stop
+```
+
+Set a line breakpoint in function binSearch, step through the loop iterations and find the problem.
+
+## Debugging Packages 1
+Packages are usually loaded lazily from a binary file containing the serialized code and data of the package.
+Therefore, you can usually only install a function breakpoint to package code.
+However, FastR keeps the package source such that you can set a line breakpoint in the package's source files.
+
+Determine the path where packages are installed:
+```R
+.libPaths()
+```
+
+To demonstrate this, start FastR in debug mode and attach the NetBeans debugger. 
+Then enter `.libPaths()` to determine where your R packages are installed. 
+
+For example, let's debug package *jsonlite* (so, if you haven't installed it, do so by typing `install.packages("jsonlite")`). 
+This tutorial assumes *jsonlite* in version 1.5. 
+Go to the installation directory from package *jsonlite* and open the file *jsonlite/R/toJSON.R*. 
+Set a line breakpoint at line 32 which calls the generic `asJSON` function. 
+Now, run our script *dump.r* using `source("R/dump.r")`. 
+As soon as the debugging cursor stops at the line breakpoint, step into the call of function *asJSON* to find out which of the concrete implementations is actually executed.
+
+## Debugging Packages 2
+For some reason, it may be that packages do not have source code available.
+In this case installing line breakpoints is not straigt forward.
+Therefore, FastR provides a facility to query the source of an R function.
+As in GnuR, if the source is not available for the function, the function's body is deparsed and a string representation is generated.
+FastR then generates a temporary source file containing the deparsed source code.
+This temporary source file can be queried using function `.fastr.srcinfo`.
+
+Let's work through an example: 
+```R
+source("R/dummy.r")
+fun
+attributes(fun)
+```
+
+Actually, *fun* has just been sourced and we would expect that there is a *srcref* attribute.
+Let's have a look what function *source* is actually doing:
+
+```R
+> .fastr.srcinfo(source)
+[1] "/tmp/deparse/source-58f3b608a4.r#1"
+```
+
+This output means that FastR generated a temporary source file "/deparse/source-58f3b608a4.r" and function *source* starts at line 1.
+Open the file in NetBeans (File -> Open File ...) and set a breakpoint at line 62.
+
+```R
+source("R/dummy.r")
+```
+
+Open the __Evaluate Expression__ view under menu Debug -> Evaluate Expression.
+Type *isTRUE(keep.source)* and press <ctrl> + <enter>.
+The result of the evaluation should be TRUE. So, why there are no source reference attributes?
+Continue stepping until line 89 (*.Internal(parse(file, n = -1, NULL, "?", srcfile, encoding))*). 
+This line calls the internal parse function which we unfortunately cannot step into because internal functions do not have R code.
+They are implemented in Java or C.
+Now, step over line 89 and evaluate the expression: *attributes(exprs)*
+The results shows that the resulting expressions actually have source reference attributes.
+Now, keep stepping until line 132 (*ei <- exprs[i]*) which copies one of the elements of the parsed expression.
+Now, evaluate expression: *attributes(exprs)*
+It turns out that the subexpression does not have any attributes.
+The reason is that FastR does not create source reference attributes in the parser because the source information is stored differently.
+
+## Inspecting Promises
+Promises are in particular difficult to handle during debugging.
+The maxime of debugging is to not modify the program as it could change its behavior and make any debugging difficult.
+However, this means that you will often not be able to inspect a promise until it is too late since a promise is evaluated at the time it is used.
+FastR allows to inspect promises in the variables view.
+Every promise (a function parameter) has three fields: `value`, `isEvaluated`, and `isEager`
+If `isEager` is `true`, then you will immediately see the value of the promise. An eager promise is a special kind where FastR eagerly evaluated the value for performance reasons.
+In this case it is safe to have the value already available without changing the semantics of the program.
+If `isEager` is `FALSE`, then `isEvaluated` will initially also be `FALSE` and `value` will be `NULL`.
+As soon as the executed function uses the parameter, the promise will be evaluated and `isEvaluated` becomes `TRUE`.
+Since the function may never use the value, it is possible to inspect the promise's value by manually setting `isEvaluated` to `TRUE` in the variables view. 
+The promise is now evaluated and its value can be inspected. 
+In order to reset the promise to its state before, you can simply set `isEvaluated` to `FALSE` again.
+  
+## GraalVM-featured
+FastR is part of the Graal/Truffle world and it is therefore easily possible to write R applications that interact with other programming languages like Java. 
+FastR has its dedicated Java interoperability API that allows to create and use Java objects. 
+The NetBeans debugger is also capable of stepping over language boundaries. 
+
+### Preparation
+
+1. Download GraalVM from [Oracle Technology Network (OTN)](http://www.oracle.com/technetwork/oracle-labs/program-languages/downloads/index.html) and extract the archive.
+2. Open NetBeans and add GraalVM as Java Platform:
+  1. Tools -> Java Platforms
+  2. Add Platform ...
+  3. Java Standard Edition -> Next
+  4. Navigate to the extracted folder of GraalVM and select the __jdk__ subfolder and click *Next*.
+  5. Specify an appropriate platform name like __GraalVM JDK__ and click finish. 
+3. Open the NetBeans project *InteropDebugging* and ensure that it uses __GraalVM JDK__ as platform:
+  1. Right click on the project and select *Properties*.
+  2. Select *Libraries* and choose __GraalVM JDK__ in the dropdown menu labeled with *Java Platform:*. 
+4. To be able to build the project, ensure that the library *truffle-api.jar* is imported correctly.
+  * The easiest way is to copy or link the wohle GraalVM into the project's root folder using the folder name `graalvm`.
+  * Otherwise: 
+    1. Right click on the project and select *Properties*.
+    2. Then select entry *Libraries*, select the *Compile* tab and look for *Classpath*.
+    3. Click on *...* and add file *graalvm/lib/truffle/truffle-api.jar*, where *graalvm* is the folder where you extracted the downloaded GraalVM into.
+5. Clean and build project *InteropDebugging*.
+
+### Inter-language Debugging 
+
+File `Main.java` creates a `PolyglotEngine` object that can execute R code. This is basically the FastR engine. 
+The engine object can now run R code by creating a source object (representing R code) and submitting the source to the engine. 
+The expression `fromString("print('Hello, World! (from string)')")` creates a source code from a string. 
+Expression `fromFile("R/main.r")` creates source code from file *R/main.r*. 
+
+Now, set a line breakpoint at line 46 (the second eval expression), build the project and run the Java application using GraalVM on the command line:
+`graalvm-<version>/bin/graalvm -J:-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -cp build/classes com.oracle.truffe.r.Main` 
+Attach the NetBeans debugger as described in *documentation/debugging.md* via Debug -> Attach Debugger. 
+Once the debugger breaks at line 46, you can step into the R application (Debug -> Step Into). 
+The debugging cursor will next arrive in file *R/main.r*. 
+
+File *R/main.r* also uses language interoperability to create a Java object and to run JavaScript code.
+We can easily debug the executed Java code by setting a breakpoint in method `java.util.Date.toString`. 
+During stepping through the R program, you will also step into the Java code. 
+
+Next, lines 31 to 35 in *R/main.r* instantiate an object of a class in our NetBeans Java project. 
+Before we can use our class *JavaMessage*, we need to add this project to the class path for the Java interoperability. 
+This is done by statement `java.addClasspathEntry("build/classes")`. 
+You can now also set a breakpoint in the `getMessage()` method and the debugger will halt on this breakpoint if the R expression `obj$getMessage()` is evaluated. 
+
+Lines 38 and 39 further evaluate code of a different language, namely JavaScript.
+If you have stepped to this call, you will be able to step into the JavaScript program.
+You can then continue your debugging activities in the JavaScript program and you will return to the origin.
+