diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
index 1992cc31b81f12cf2c5b3f7301c5be0a32834590..b981424ae510db9e3aca3b7dabacd3ab249fc86f 100644
--- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
+++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/REnvVars.java
@@ -35,6 +35,7 @@ import java.util.HashMap;
 import java.util.Map;
 
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.vm.PolyglotEngine;
 import com.oracle.truffle.r.runtime.context.RContext;
 import com.oracle.truffle.r.runtime.ffi.RFFIFactory;
 
@@ -67,8 +68,7 @@ public final class REnvVars implements RContext.ContextState {
         envVars.put("R_SHARE_DIR", fileSystem.getPath(rHome, "share").toString());
         String rLibsUserProperty = envVars.get("R_LIBS_USER");
         if (rLibsUserProperty == null) {
-            String os = System.getProperty("os.name");
-            if (os.contains("Mac OS")) {
+            if (isMacOS()) {
                 rLibsUserProperty = "~/Library/R/%v/library";
             } else {
                 rLibsUserProperty = "~/R/%p-library/%v";
@@ -139,6 +139,11 @@ public final class REnvVars implements RContext.ContextState {
         return val != null ? val : envVars.get(var.toUpperCase());
     }
 
+    private static boolean isMacOS() {
+        String os = System.getProperty("os.name");
+        return os.contains("Mac OS");
+    }
+
     private static final String R_HOME = "R_HOME";
 
     /**
@@ -146,6 +151,13 @@ public final class REnvVars implements RContext.ContextState {
      */
     private static String rHome;
 
+    /**
+     * Returns a file that only exists in a FastR {@code R_HOME}.
+     */
+    private static String markerFile() {
+        return "libjniboot." + (isMacOS() ? "dylib" : "so");
+    }
+
     /**
      * Returns the value of the {@code R_HOME} environment variable (setting it in the unusual case
      * where it it is not set by the initiating shell scripts. This is called very early in the
@@ -157,17 +169,11 @@ public final class REnvVars implements RContext.ContextState {
             rHome = System.getenv(R_HOME);
             Path rHomePath;
             if (rHome == null) {
-                /*
-                 * The only time this can happen legitimately is when run under the graalvm shell,
-                 * which does not execute the shell script that normally sets R_HOME.
-                 */
                 rHomePath = getRHomePath();
             } else {
                 rHomePath = Paths.get(rHome);
             }
-            // Sanity check on the expected structure of an R_HOME
-            Path bin = rHomePath.resolve("bin");
-            if (!(Files.exists(bin) && Files.isDirectory(bin) && Files.exists(bin.resolve("R")))) {
+            if (!validateRHome(rHomePath, markerFile())) {
                 Utils.rSuicide("R_HOME is not set correctly");
             }
             rHome = rHomePath.toString();
@@ -175,8 +181,36 @@ public final class REnvVars implements RContext.ContextState {
         return rHome;
     }
 
+    /**
+     * In the case where {@code R_HOME} is not set, which should only occur when FastR is invoked
+     * from a {@link PolyglotEngine} created by another language, we try to locate the
+     * {@code R_HOME} dynamically by using the location of this class. The logic varies depending on
+     * whether this class was stored in a {@code .jar} file or in a {@code .class} file in a
+     * directory.
+     *
+     * @return either a valid {@code R_HOME} or {@code null}
+     */
     private static Path getRHomePath() {
-        return Paths.get(REnvVars.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParent();
+        Path path = Paths.get(REnvVars.class.getProtectionDomain().getCodeSource().getLocation().getPath()).getParent();
+        String markerFile = markerFile();
+        while (path != null) {
+            if (validateRHome(path, markerFile)) {
+                return path;
+            }
+            path = path.getParent();
+        }
+        return path;
+    }
+
+    /**
+     * Sanity check on the expected structure of an {@code R_HOME}.
+     */
+    private static boolean validateRHome(Path path, String markerFile) {
+        if (path == null) {
+            return false;
+        }
+        Path lib = path.resolve("lib");
+        return Files.exists(lib) && Files.isDirectory(lib) && Files.exists(lib.resolve(markerFile));
     }
 
     private void checkRHome() {