From a8659ed6bb5b1f30ab3d6ffa1581f09207abf0e1 Mon Sep 17 00:00:00 2001 From: Florian Angerer <florian.angerer@oracle.com> Date: Tue, 27 Jun 2017 17:36:31 +0200 Subject: [PATCH] Added builtin for adding classpath entries for Java interop. --- .../r/nodes/builtin/base/BasePackage.java | 1 + .../r/nodes/builtin/fastr/FastRInterop.java | 30 ++++++++++++++++++- .../truffle/r/runtime/context/RContext.java | 19 ++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) 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 6720e2f634..ff95db1dd7 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 @@ -420,6 +420,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 dfd0f56b4b..4aeffb07da 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; @@ -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,32 @@ public class FastRInterop { } } + @RBuiltin(name = ".fastr.java.addClasspathEntry", visibility = OFF, kind = PRIMITIVE, parameterNames = {"entry", "silent"}, behavior = COMPLEX) + public abstract static class JavaAddClasspathEntry extends RBuiltinNode.Arg2 { + + static { + Casts casts = new Casts(JavaAddClasspathEntry.class); + casts.arg("entry").mustBe(stringValue()).asStringVector().mustBe(Predef.singleElement()).findFirst(); + 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 javaClass(String entry, boolean silent) { + try { + RContext ctx = RContext.getInstance(); + ctx.addInteropClasspathEntry(entry); + return RNull.instance; + } 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 b8f37f4b22..801a51bd97 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 @@ -25,7 +25,11 @@ package com.oracle.truffle.r.runtime.context; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.Closeable; +import java.io.File; import java.lang.ref.WeakReference; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; import java.nio.file.Path; import java.util.EnumSet; import java.util.HashMap; @@ -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,16 @@ public final class RContext implements RTruffleObject { } }; + public ClassLoader getInteropClassLoader() { + return interopClassLoader; + } + + /** + * Adds an entry to the Java interop class loader. This will effectively create a new class + * loader with the previous one as parent. + */ + public void addInteropClasspathEntry(String entry) throws MalformedURLException { + URL url = new File(entry).toURI().toURL(); + interopClassLoader = URLClassLoader.newInstance(new URL[]{url}, interopClassLoader); + } } -- GitLab