diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c index 27531805427a24841acc3bd6dfa20d5e5cb46178..00d867ef647012ad9d64979ae8439eee20f83783 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -52,6 +52,7 @@ static jmethodID Rf_getAttribMethodID; static jmethodID Rf_setAttribMethodID; static jmethodID Rf_isStringMethodID; static jmethodID Rf_isNullMethodID; +static jmethodID Rf_installCharMethodID; static jmethodID Rf_installMethodID; static jmethodID Rf_warningcallMethodID; static jmethodID Rf_warningMethodID; @@ -158,6 +159,7 @@ void init_internals(JNIEnv *env) { Rf_isStringMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isString", "(Ljava/lang/Object;)I", 0); Rf_isNullMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_isNull", "(Ljava/lang/Object;)I", 0); Rf_installMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_install", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); + Rf_installCharMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_installChar", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); Rf_warningMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warning", "(Ljava/lang/Object;)V", 0); Rf_warningcallMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_warningcall", "(Ljava/lang/Object;Ljava/lang/Object;)V", 0); Rf_errorMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_error", "(Ljava/lang/Object;)V", 0); @@ -166,7 +168,7 @@ void init_internals(JNIEnv *env) { Rf_allocateArrayMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_allocateArray", "(ILjava/lang/Object;)Ljava/lang/Object;", 0); Rf_duplicateMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_duplicate", "(Ljava/lang/Object;I)Ljava/lang/Object;", 0); Rf_anyDuplicatedMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_anyDuplicated", "(Ljava/lang/Object;I)I", 0); - R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;I)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 0); + R_NewHashedEnvMethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_NewHashedEnv", "(Lcom/oracle/truffle/r/runtime/env/REnvironment;Ljava/lang/Object;)Lcom/oracle/truffle/r/runtime/env/REnvironment;", 0); Rf_classgetsMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rf_classgets", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;", 0); RprintfMethodID = checkGetMethodID(env, UpCallsRFFIClass, "Rprintf", "(Ljava/lang/Object;)V", 0); R_do_MAKE_CLASS_MethodID = checkGetMethodID(env, UpCallsRFFIClass, "R_do_MAKE_CLASS", "(Ljava/lang/Object;)Ljava/lang/Object;", 0); @@ -497,8 +499,7 @@ SEXP Rf_install(const char *name) { SEXP Rf_installChar(SEXP charsxp) { TRACE(TARGp, charsxp); JNIEnv *thisenv = getEnv(); - jstring string = stringFromCharSXP(thisenv, charsxp); - SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_installMethodID, string); + SEXP result = (*thisenv)->CallObjectMethod(thisenv, UpCallsRFFIObject, Rf_installCharMethodID, charsxp); return checkRef(thisenv, result); } diff --git a/com.oracle.truffle.r.native/version.source b/com.oracle.truffle.r.native/version.source index 78c24caea0d6432c6894a971ae42532768cc80d4..60d3b2f4a4cd5f1637eba020358bfe5ecb5edcf2 100644 --- a/com.oracle.truffle.r.native/version.source +++ b/com.oracle.truffle.r.native/version.source @@ -1 +1 @@ -2/10/17 +15 diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java index a12d923fd9d1eac96a6a53f5fe799a458d3abb74..87aa0607ff6c2d7ff6b0499cc3015c63b38d9642 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/JavaUpCallsRFFIImpl.java @@ -315,6 +315,12 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { return RDataFactory.createSymbolInterned((String) name); } + @Override + public Object Rf_installChar(Object name) { + CharSXPWrapper charSXP = guaranteeInstanceOf(name, CharSXPWrapper.class); + return RDataFactory.createSymbolInterned(charSXP.getContents()); + } + @Override public Object Rf_lengthgets(Object x, int newSize) { RAbstractVector vec = (RAbstractVector) RRuntime.asAbstractVector(x); @@ -1146,8 +1152,9 @@ public abstract class JavaUpCallsRFFIImpl implements UpCallsRFFI { } @Override - public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) { - REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, initialSize); + public REnvironment R_NewHashedEnv(REnvironment parent, Object initialSize) { + // We know this is an RIntVector from use site in gramRd.c + REnvironment env = RDataFactory.createNewEnv(REnvironment.UNNAMED, true, ((RIntVector) initialSize).getDataAt(0)); RArguments.initializeEnclosingFrame(env.getFrame(), parent.getFrame()); return env; } diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java index a998220115fb7fa4aec65f56d40e8c6087f704ce..d475cc1f9e2aff4845c5d0f9a7a576b581042186 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/RFFIUpCallMethod.java @@ -69,7 +69,7 @@ public enum RFFIUpCallMethod { R_Interactive("() : sint32"), R_MakeExternalPtr("(object, object, object) : object"), R_NamespaceRegistry("() : object"), - R_NewHashedEnv("(object, sint32) : object"), + R_NewHashedEnv("(object, object) : object"), R_ParseVector("(object, sint32, object) : object"), R_PromiseExpr("(object) : object"), R_SetExternalPtrAddr("(object, object) : void"), @@ -77,7 +77,7 @@ public enum RFFIUpCallMethod { R_SetExternalPtrTag("(object, object) : void"), R_ToplevelExec("() : object"), R_computeIdentical("(object, object, sint32) : sint32"), - R_do_MAKE_CLASS("(pointer) : object"), + R_do_MAKE_CLASS("(string) : object"), R_getContextCall("(object) : object"), R_getContextEnv("(object) : object"), R_getContextFun("(object) : object"), @@ -110,7 +110,7 @@ public enum RFFIUpCallMethod { Rf_copyMatrix("(object, object, sint32) : void"), Rf_defineVar("(object, object, object) : void"), Rf_duplicate("(object, sint32) : object"), - Rf_error("(pointer) : void"), + Rf_error("(string) : void"), Rf_eval("(object, object) : object"), Rf_findVar("(object, object) : object"), Rf_findVarInFrame("(object, object) : object"), @@ -118,8 +118,9 @@ public enum RFFIUpCallMethod { Rf_findfun("(object, object) : object"), Rf_getAttrib("(object, object) : object"), Rf_gsetVar("(object, object, object) : void"), - Rf_inherits("(pointer, object) : sint32"), - Rf_install("(pointer) : object"), + Rf_inherits("(string, object) : sint32"), + Rf_install("(string) : object"), + Rf_installChar("(object) : object"), Rf_isNull("(object) : sint32"), Rf_isString("(object) : sint32"), Rf_lengthgets("(object, sint32) : object"), @@ -127,9 +128,9 @@ public enum RFFIUpCallMethod { Rf_ncols("(object) : sint32"), Rf_nrows("(object) : sint32"), Rf_setAttrib("(object, object, object) : void"), - Rf_warning("(pointer) : void"), - Rf_warningcall("(object, pointer) : void"), - Rprintf("(pointer) : void"), + Rf_warning("(string) : void"), + Rf_warningcall("(object, string) : void"), + Rprintf("(string) : void"), SETCADR("(object, object) : object"), SETCAR("(object, object) : object"), SETCDR("(object, object) : object"), diff --git a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java index fd78becb64849ad60a065a0da30db451b4d4ad15..2943d37a769df0466e31d754da376a8dbd37b543 100644 --- a/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java +++ b/com.oracle.truffle.r.nodes/src/com/oracle/truffle/r/nodes/ffi/TracingUpCallsRFFIImpl.java @@ -159,6 +159,12 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { return delegate.Rf_install(name); } + @Override + public Object Rf_installChar(Object name) { + RFFIUtils.traceUpCall("Rf_installChar", name); + return delegate.Rf_installChar(name); + } + @Override public Object Rf_lengthgets(Object x, int newSize) { RFFIUtils.traceUpCall("Rf_lengthgets", x, newSize); @@ -700,7 +706,7 @@ final class TracingUpCallsRFFIImpl implements UpCallsRFFI { } @Override - public REnvironment R_NewHashedEnv(REnvironment parent, int initialSize) { + public REnvironment R_NewHashedEnv(REnvironment parent, Object initialSize) { RFFIUtils.traceUpCall("R_NewHashedEnv", parent, initialSize); return delegate.R_NewHashedEnv(parent, initialSize); } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java index c8dbee39e12f83ea246b81d120268560bb150ae7..5d50ed6f2cca867aa9ec80826bf7746e350cf17c 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFICstring.java @@ -28,10 +28,11 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Tags an upcall argument as being (on the native side) a C string. + * Tags an upcall argument as being (on the native side) a C string. By default the C string is + * converted to a {@link String}, which requires it to be null-terminated. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.PARAMETER) public @interface RFFICstring { - + boolean convert() default true; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java index 35fdd63dac7b346cfd6cdcb1f1b73c76c890b90c..963d98cc59c51098f153ed6e59bfb49bed90735b 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/RFFIFactory.java @@ -33,8 +33,22 @@ import com.oracle.truffle.r.runtime.context.RContext.ContextState; * must support the {@link #newContextState()} method. */ public abstract class RFFIFactory { - private static final String FACTORY_CLASS_PROPERTY = "fastr.ffi.factory.class"; - private static final String DEFAULT_FACTORY_CLASS = "com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory"; + private enum Factory { + JNI("com.oracle.truffle.r.runtime.ffi.jni.JNI_RFFIFactory"), + LLVM("com.oracle.truffle.r.engine.interop.ffi.llvm.TruffleLLVM_RFFIFactory"), + NFI("com.oracle.truffle.r.engine.interop.ffi.nfi.TruffleNFI_RFFIFactory"); + + private final String klassName; + + Factory(String klassName) { + this.klassName = klassName; + } + } + + private static final String FACTORY_CLASS_PROPERTY = "fastr.rffi.factory.class"; + private static final String FACTORY_CLASS_NAME_PROPERTY = "fastr.rffi.factory"; + private static final String FACTORY_CLASS_ENV = "FASTR_RFFI_FACTORY"; + private static final Factory DEFAULT_FACTORY = Factory.JNI; /** * Singleton instance of the factory. @@ -45,20 +59,43 @@ public abstract class RFFIFactory { public static RFFIFactory initialize() { if (instance == null) { - String prop = System.getProperty(FACTORY_CLASS_PROPERTY); + String klassName = getFactoryClassName(); try { - if (prop == null) { - prop = DEFAULT_FACTORY_CLASS; - } - instance = (RFFIFactory) Class.forName(prop).newInstance(); + instance = (RFFIFactory) Class.forName(klassName).newInstance(); theRFFI = instance.createRFFI(); } catch (Exception ex) { - throw Utils.rSuicide("Failed to instantiate class: " + prop + ": " + ex); + throw Utils.rSuicide("Failed to instantiate class: " + klassName + ": " + ex); } } return instance; } + private static String getFactoryClassName() { + String prop = System.getProperty(FACTORY_CLASS_PROPERTY); + if (prop != null) { + return prop; + } + prop = System.getProperty(FACTORY_CLASS_NAME_PROPERTY); + if (prop != null) { + return checkFactoryName(prop); + } + prop = System.getenv(FACTORY_CLASS_ENV); + if (prop != null) { + return checkFactoryName(prop); + } + return DEFAULT_FACTORY.klassName; + } + + private static String checkFactoryName(String prop) { + try { + Factory factory = Factory.valueOf(prop.toUpperCase()); + return factory.klassName; + } catch (IllegalArgumentException ex) { + throw Utils.rSuicide("No RFFI factory: " + prop); + } + + } + public static RFFIFactory getInstance() { assert instance != null; return instance; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java index 3d96124a1cae1cfce8e8af31608e92dd60bbc9a6..1bd2e8efe24c900f096dc0cb84e43f412e0fee51 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/ffi/StdUpCallsRFFI.java @@ -65,7 +65,7 @@ public interface StdUpCallsRFFI { Object Rf_coerceVector(Object x, int mode); - Object Rf_mkCharLenCE(@RFFICstring Object bytes, int len, int encoding); + Object Rf_mkCharLenCE(@RFFICstring(convert = false) Object bytes, int len, int encoding); Object Rf_cons(Object car, Object cdr); @@ -90,6 +90,8 @@ public interface StdUpCallsRFFI { Object Rf_install(@RFFICstring Object name); + Object Rf_installChar(Object name); + Object Rf_lengthgets(Object x, int newSize); int Rf_isString(Object x); @@ -240,7 +242,7 @@ public interface StdUpCallsRFFI { void R_CleanUp(int sa, int status, int runlast); - REnvironment R_NewHashedEnv(REnvironment parent, int initialSize); + REnvironment R_NewHashedEnv(REnvironment parent, Object initialSize); int PRSEEN(Object x); diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java index 85f600102edbe908fc920d4cf39986245b44a250..b538c5c44d84568c7d05d22e628a71157a386667 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tools/RFFIUpCallMethodGenerate.java @@ -28,6 +28,7 @@ import java.util.Arrays; import java.util.Comparator; import com.oracle.truffle.r.nodes.ffi.RFFIUpCallMethod; +import com.oracle.truffle.r.runtime.ffi.RFFICstring; import com.oracle.truffle.r.runtime.ffi.UpCallsRFFI; /** @@ -73,12 +74,24 @@ public class RFFIUpCallMethodGenerate { return sb.toString(); } - static String nfiParamName(Class<?> paramType, Annotation[] annotation) { + static String nfiParamName(Class<?> paramType, Annotation[] annotations) { String paramName = paramType.getSimpleName(); - Class<?> klass = annotation.length == 0 ? null : annotation[0].annotationType(); + RFFICstring rffiCstring = null; + if (annotations.length > 0) { + for (Annotation annotation : annotations) { + if (annotation instanceof RFFICstring) { + rffiCstring = (RFFICstring) annotation; + break; + } + } + } switch (paramName) { case "Object": - return klass == null ? "object" : "pointer"; + if (rffiCstring == null) { + return "object"; + } else { + return rffiCstring.convert() ? "string" : "pointer"; + } case "int": return "sint32"; case "double":