diff --git a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c index 61431ad1d6d0b6c2717a6d7d17d8babc84c26456..af38cfcc846d04ece15ebe0120913ee60a101c23 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rembedded.c @@ -406,14 +406,19 @@ void setupOverrides(void) { } static void REmbed_nativeWriteConsole(JNIEnv *jniEnv, jclass c, jstring string, int otype) { - int len = (*jniEnv)->GetStringUTFLength(jniEnv, string); - const char *cbuf = (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL); - if (ptr_R_WriteConsole == NULL) { - (*ptr_R_WriteConsoleEx)(cbuf, len, otype); - } else { - (*ptr_R_WriteConsole)(cbuf, len); + jmp_buf error_jmpbuf; + callEnter(jniEnv, &error_jmpbuf); + if (!setjmp(error_jmpbuf)) { + int len = (*jniEnv)->GetStringUTFLength(jniEnv, string); + const char *cbuf = (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL); + if (ptr_R_WriteConsole == NULL) { + (*ptr_R_WriteConsoleEx)(cbuf, len, otype); + } else { + (*ptr_R_WriteConsole)(cbuf, len); + } + (*jniEnv)->ReleaseStringUTFChars(jniEnv, string, cbuf); } - (*jniEnv)->ReleaseStringUTFChars(jniEnv, string, cbuf); + callExit(jniEnv); } JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeWriteConsole(JNIEnv *jniEnv, jclass c, jstring string) { @@ -425,22 +430,37 @@ JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nat } JNIEXPORT jstring JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeReadConsole(JNIEnv *jniEnv, jclass c, jstring prompt) { - const char *cprompt = (*jniEnv)->GetStringUTFChars(jniEnv, prompt, NULL); - unsigned char cbuf[1024]; - int n = (*ptr_R_ReadConsole)(cprompt, cbuf, 1024, 0); - jstring result; - result = (*jniEnv)->NewStringUTF(jniEnv, (const char *)cbuf); - (*jniEnv)->ReleaseStringUTFChars(jniEnv, prompt, cprompt); + jmp_buf error_jmpbuf; + jstring result = NULL; + callEnter(jniEnv, &error_jmpbuf); + if (!setjmp(error_jmpbuf)) { + const char *cprompt = (*jniEnv)->GetStringUTFChars(jniEnv, prompt, NULL); + unsigned char cbuf[1024]; + int n = (*ptr_R_ReadConsole)(cprompt, cbuf, 1024, 0); + result = (*jniEnv)->NewStringUTF(jniEnv, (const char *)cbuf); + (*jniEnv)->ReleaseStringUTFChars(jniEnv, prompt, cprompt); + } + callExit(jniEnv); return result; } JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeCleanUp(JNIEnv *jniEnv, jclass c, jint x, jint y, jint z) { + jmp_buf error_jmpbuf; + callEnter(jniEnv, &error_jmpbuf); + if (!setjmp(error_jmpbuf)) { (*ptr_R_CleanUp)(x, y, z); + } + callExit(jniEnv); } JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1REmbed_nativeSuicide(JNIEnv *jniEnv, jclass c, jstring string) { - const char *cbuf = (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL); - (*ptr_R_Suicide)(cbuf); + jmp_buf error_jmpbuf; + callEnter(jniEnv, &error_jmpbuf); + if (!setjmp(error_jmpbuf)) { + const char *cbuf = (*jniEnv)->GetStringUTFChars(jniEnv, string, NULL); + (*ptr_R_Suicide)(cbuf); + } + callExit(jniEnv); } void uR_PolledEvents(void) { @@ -582,7 +602,7 @@ CTXT R_getGlobalFunctionContext() { jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getGlobalFunctionContext", "()Ljava/lang/Object;", 1); CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID); result = checkRef(jniEnv, result); - return result == R_NilValue ? NULL : result; + return result == R_NilValue ? NULL : addGlobalRef(jniEnv, result, 0); } CTXT R_getParentFunctionContext(CTXT c) { @@ -590,7 +610,7 @@ CTXT R_getParentFunctionContext(CTXT c) { jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_getParentFunctionContext", "(Ljava/lang/Object;)Ljava/lang/Object;", 1); CTXT result = (*jniEnv)->CallStaticObjectMethod(jniEnv, CallRFFIHelperClass, methodID, c); result = checkRef(jniEnv, result); - return result == R_NilValue ? NULL : result; + return result == R_NilValue ? NULL : addGlobalRef(jniEnv, result, 0); } SEXP R_getContextEnv(CTXT context) { @@ -627,3 +647,15 @@ int R_insideBrowser() { jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_insideBrowser", "()I", 1); return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID); } + +int R_isGlobal(CTXT context) { + JNIEnv *jniEnv = getEnv(); + jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_isGlobal", "(Ljava/lang/Object;)I", 1); + return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID, context); +} + +int R_isEqual(void* x, void* y) { + JNIEnv *jniEnv = getEnv(); + jmethodID methodID = checkGetMethodID(jniEnv, CallRFFIHelperClass, "R_isEqual", "(Ljava/lang/Object;Ljava/lang/Object;)I", 1); + return (*jniEnv)->CallStaticIntMethod(jniEnv, CallRFFIHelperClass, methodID, x, y); +} 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 14227cbd329b3acd95354e84d88609a379ecbaee..5c701bef8db98b376449c6192b9b8b8491e476c1 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/Rinternals.c @@ -350,6 +350,7 @@ SEXP Rf_dimnamesgets(SEXP x, SEXP y) { SEXP Rf_eval(SEXP expr, SEXP env) { TRACE(TARGpp, expr, env); JNIEnv *thisenv = getEnv(); + updateNativeArrays(thisenv); SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, Rf_evalMethodID, expr, env); return checkRef(thisenv, result); } @@ -849,7 +850,7 @@ SEXP CADR(SEXP e) { } SEXP CDDR(SEXP e) { - TRACE(TARG1, e); + TRACE(TARGp, e); JNIEnv *thisenv = getEnv(); SEXP result = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, CDDR_MethodID, e); return checkRef(thisenv, result); @@ -1455,6 +1456,7 @@ SEXP Rf_asS4(SEXP x, Rboolean b, int i) { static SEXP R_tryEvalInternal(SEXP x, SEXP y, int *ErrorOccurred, jboolean silent) { JNIEnv *thisenv = getEnv(); + updateNativeArrays(thisenv); jobject tryResult = (*thisenv)->CallStaticObjectMethod(thisenv, CallRFFIHelperClass, R_tryEvalMethodID, x, y, silent); // If tryResult is NULL, an error occurred if (ErrorOccurred) { @@ -1609,12 +1611,13 @@ int R_check_class_etc (SEXP x, const char **valid) { return (int) unimplemented("R_check_class_etc"); } -void R_PreserveObject(SEXP x) { - // Not applicable +SEXP R_PreserveObject(SEXP x) { + // convert to a JNI global ref until explicitly released + return createGlobalRef(getEnv(), x, 0); } void R_ReleaseObject(SEXP x) { - // Not applicable + releaseGlobalRef(getEnv(), x); } void R_dot_Last(void) { diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c index a8d153d4a0c39265d82c94e63c739c61e1c7a777..9b2a545370781553d0f7157366b688ea3dae1496 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/rfficall.c @@ -42,8 +42,6 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_nativeSetTempDir(JNIEnv setTempDir(env, tempDir); } -static jmp_buf error_jmpbuf; - // Boilerplate methods for the actual calls typedef SEXP (*call0func)(); @@ -343,6 +341,7 @@ typedef SEXP (*call64func)(SEXP arg1, SEXP arg2, SEXP arg3, SEXP arg4, SEXP arg5 JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call0(JNIEnv *env, jclass c, jlong address) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -355,6 +354,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call0(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call1(JNIEnv *env, jclass c, jlong address, jobject arg1) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -367,6 +367,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call1(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call2(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -380,6 +381,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call2(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call3(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -393,6 +395,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call3(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call4(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -406,6 +409,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call4(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call5(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4, jobject arg5) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -419,6 +423,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call5(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call6(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4, jobject arg5, jobject arg6) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -432,6 +437,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call6(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call7(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4, jobject arg5, jobject arg6, jobject arg7) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -445,6 +451,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call7(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call8(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4, jobject arg5, jobject arg6, jobject arg7, jobject arg8) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -458,6 +465,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call8(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call9(JNIEnv *env, jclass c, jlong address, jobject arg1, jobject arg2, jobject arg3, jobject arg4, jobject arg5, jobject arg6, jobject arg7, jobject arg8, jobject arg9) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { @@ -470,6 +478,7 @@ Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call9(JNIEnv *env, jclas JNIEXPORT jobject JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_call(JNIEnv *env, jclass c, jlong address, jobjectArray args) { + jmp_buf error_jmpbuf; jobject result = NULL; callEnter(env, &error_jmpbuf); jsize len = (*env)->GetArrayLength(env, args); @@ -1214,6 +1223,7 @@ typedef void (*callVoid1func)(SEXP arg1); JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_callVoid1(JNIEnv *env, jclass c, jlong address, jobject arg1) { + jmp_buf error_jmpbuf; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { callVoid1func call1 = (callVoid1func) address; @@ -1226,6 +1236,7 @@ typedef void (*callVoid0func)(); JNIEXPORT void JNICALL Java_com_oracle_truffle_r_runtime_ffi_jnr_JNI_1CallRFFI_callVoid0(JNIEnv *env, jclass c, jlong address) { + jmp_buf error_jmpbuf; callEnter(env, &error_jmpbuf); if (!setjmp(error_jmpbuf)) { callVoid0func call1 = (callVoid0func) address; diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c index 43f13021a505226076c73c73e19162c98ce54186..5f9425d8a7ffd68d8607ad2c3cc9864671065fb9 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c @@ -43,14 +43,18 @@ jmethodID createSymbolMethodID; static jmethodID validateMethodID; static JNIEnv *curenv = NULL; -jmp_buf *callErrorJmpBuf; // default for trace output when enabled FILE *traceFile = NULL; -static int alwaysUseGlobal = 0; +typedef struct globalRefTable_struct { + int permanent; + SEXP gref; // The jobject (SEXP) global ref +} GlobalRefElem; + #define CACHED_GLOBALREFS_INITIAL_SIZE 64 -static SEXP *cachedGlobalRefs; +static GlobalRefElem *cachedGlobalRefs; +static int cachedGlobalRefsHwm; static int cachedGlobalRefsLength; // Data structure for managing the required copying of @@ -71,7 +75,7 @@ static NativeArrayElem *nativeArrayTable; // hwm of nativeArrayTable static int nativeArrayTableHwm; static int nativeArrayTableLength; -static void releaseNativeArray(JNIEnv *env, int index); +static void releaseNativeArray(JNIEnv *env, int index, int freedata); static int isEmbedded = 0; void setEmbedded() { @@ -79,10 +83,14 @@ void setEmbedded() { } // native down call depth, indexes nativeArrayTableHwmStack -int callDepth; +int callDepth = 0; + +#define CALLDEPTH_STACK_SIZE 16 +static int nativeArrayTableHwmStack[CALLDEPTH_STACK_SIZE]; + +// stack of jmp_buf ptrs for non-local control transfer on error +static jmp_buf* callErrorJmpBufTable[CALLDEPTH_STACK_SIZE]; -#define NATIVE_ARRAY_TABLE_HWM_STACK_SIZE 16 -int nativeArrayTableHwmStack[NATIVE_ARRAY_TABLE_HWM_STACK_SIZE] ; void init_utils(JNIEnv *env) { curenv = env; @@ -113,8 +121,9 @@ void init_utils(JNIEnv *env) { unimplementedMethodID = checkGetMethodID(env, RInternalErrorClass, "unimplemented", "(Ljava/lang/String;)Ljava/lang/RuntimeException;", 1); createSymbolMethodID = checkGetMethodID(env, RDataFactoryClass, "createSymbolInterned", "(Ljava/lang/String;)Lcom/oracle/truffle/r/runtime/data/RSymbol;", 1); validateMethodID = checkGetMethodID(env, CallRFFIHelperClass, "validate", "(Ljava/lang/Object;)Ljava/lang/Object;", 1); - cachedGlobalRefs = calloc(CACHED_GLOBALREFS_INITIAL_SIZE, sizeof(SEXP)); + cachedGlobalRefs = calloc(CACHED_GLOBALREFS_INITIAL_SIZE, sizeof(GlobalRefElem)); cachedGlobalRefsLength = CACHED_GLOBALREFS_INITIAL_SIZE; + cachedGlobalRefsHwm = 0; nativeArrayTable = calloc(NATIVE_ARRAY_TABLE_INITIAL_SIZE, sizeof(NativeArrayElem)); nativeArrayTableLength = NATIVE_ARRAY_TABLE_INITIAL_SIZE; nativeArrayTableHwm = 0; @@ -134,8 +143,9 @@ const char *stringToChars(JNIEnv *jniEnv, jstring string) { void callEnter(JNIEnv *env, jmp_buf *jmpbuf) { setEnv(env); - callErrorJmpBuf = jmpbuf; - if (callDepth >= NATIVE_ARRAY_TABLE_HWM_STACK_SIZE) { + //printf("callEnter: callDepth %d, jmpbufptr %p\n", callDepth, jmpbuf); + callErrorJmpBufTable[callDepth] = jmpbuf; + if (callDepth >= CALLDEPTH_STACK_SIZE) { fatalError("call stack overflow\n"); } nativeArrayTableHwmStack[callDepth] = nativeArrayTableHwm; @@ -143,27 +153,27 @@ void callEnter(JNIEnv *env, jmp_buf *jmpbuf) { } jmp_buf *getErrorJmpBuf() { - return callErrorJmpBuf; + // printf("getErrorJmpBuf: callDepth %d, jmpbufptr %p\n", callDepth, callErrorJmpBufTable[callDepth - 1]); + return callErrorJmpBufTable[callDepth - 1]; } void callExit(JNIEnv *env) { int oldHwm = nativeArrayTableHwmStack[callDepth - 1]; for (int i = oldHwm; i < nativeArrayTableHwm; i++) { - releaseNativeArray(env, i); + releaseNativeArray(env, i, 1); } nativeArrayTableHwm = oldHwm; callDepth--; } void invalidateNativeArray(JNIEnv *env, SEXP oldObj) { - int i; - for (i = 0; i < nativeArrayTableHwm; i++) { + for (int i = 0; i < nativeArrayTableHwm; i++) { NativeArrayElem cv = nativeArrayTable[i]; if ((*env)->IsSameObject(env, cv.obj, oldObj)) { #if TRACE_NATIVE_ARRAYS fprintf(traceFile, "invalidateNativeArray(%p): found\n", oldObj); #endif - releaseNativeArray(env, &cv); + releaseNativeArray(env, i, 1); nativeArrayTable[i].obj = NULL; } } @@ -172,6 +182,14 @@ void invalidateNativeArray(JNIEnv *env, SEXP oldObj) { #endif } +void updateNativeArrays(JNIEnv *env) { + int oldHwm = nativeArrayTableHwmStack[callDepth - 1]; + for (int i = oldHwm; i < nativeArrayTableHwm; i++) { + releaseNativeArray(env, i, 0); + } +} + + static void *findNativeArray(JNIEnv *env, SEXP x) { int i; for (i = 0; i < nativeArrayTableHwm; i++) { @@ -270,16 +288,16 @@ void *getNativeArray(JNIEnv *thisenv, SEXP x, SEXPTYPE type) { return data; } -static void releaseNativeArray(JNIEnv *env, int i) { +static void releaseNativeArray(JNIEnv *env, int i, int freedata) { NativeArrayElem cv = nativeArrayTable[i]; #if TRACE_NATIVE_ARRAYS - fprintf(traceFile, "releaseNativeArray(x=%p, ix=%d)\n", cv.obj, i); + fprintf(traceFile, "releaseNativeArray(x=%p, ix=%d, freedata=%d)\n", cv.obj, i, freedata); #endif if (cv.obj != NULL) { switch (cv.type) { case INTSXP: { jintArray intArray = (jintArray) cv.jArray; - (*env)->ReleaseIntArrayElements(env, intArray, (jint *)cv.data, 0); + (*env)->ReleaseIntArrayElements(env, intArray, (jint *)cv.data, freedata ? 0 : JNI_COMMIT); break; } @@ -293,78 +311,109 @@ static void releaseNativeArray(JNIEnv *env, int i) { internalData[i] = data[i] == NA_INTEGER ? 255 : (jbyte) data[i]; } (*env)->ReleaseByteArrayElements(env, byteArray, internalData, 0); - free(data); // was malloc'ed in addNativeArray + if (freedata){ + free(data); // was malloc'ed in addNativeArray + } break; } case REALSXP: { jdoubleArray doubleArray = (jdoubleArray) cv.jArray; - (*env)->ReleaseDoubleArrayElements(env, doubleArray, (jdouble *)cv.data, 0); + (*env)->ReleaseDoubleArrayElements(env, doubleArray, (jdouble *)cv.data, freedata ? 0 : JNI_COMMIT); break; } case RAWSXP: { jbyteArray byteArray = (jbyteArray) cv.jArray; - (*env)->ReleaseByteArrayElements(env, byteArray, (jbyte *)cv.data, 0); + (*env)->ReleaseByteArrayElements(env, byteArray, (jbyte *)cv.data, freedata ? 0 : JNI_COMMIT); break; } default: fatalError("releaseNativeArray type"); } - // free up the slot - cv.obj = NULL; + if (freedata) { + // free up the slot + cv.obj = NULL; + } } } -static SEXP checkCachedGlobalRef(JNIEnv *env, SEXP obj, int useGlobal) { - int i; - for (i = 0; i < cachedGlobalRefsLength; i++) { - SEXP ref = cachedGlobalRefs[i]; - if (ref == NULL) { - break; +static SEXP findCachedGlobalRef(JNIEnv *env, SEXP obj) { + for (int i = 0; i < cachedGlobalRefsHwm; i++) { + GlobalRefElem elem = cachedGlobalRefs[i]; + if (elem.gref == NULL) { + continue; } - if ((*env)->IsSameObject(env, ref, obj)) { + if ((*env)->IsSameObject(env, elem.gref, obj)) { #if TRACE_REF_CACHE fprintf(traceFile, "gref: cache hit: %d\n", i); #endif - return ref; + return elem.gref; } } - SEXP result; - if (useGlobal) { - if (i >= cachedGlobalRefsLength) { - int newLength = cachedGlobalRefsLength * 2; + return NULL; +} + +SEXP addGlobalRef(JNIEnv *env, SEXP obj, int permanent) { + SEXP gref; + if (cachedGlobalRefsHwm >= cachedGlobalRefsLength) { + int newLength = cachedGlobalRefsLength * 2; #if TRACE_REF_CACHE - fprintf(traceFile, "gref: extending table to %d\n", newLength); + fprintf(traceFile, "gref: extending table to %d\n", newLength); #endif - SEXP newCachedGlobalRefs = calloc(newLength, sizeof(SEXP)); - if (newCachedGlobalRefs == NULL) { - fatalError("FFI global refs table expansion failure"); - } - memcpy(newCachedGlobalRefs, cachedGlobalRefs, cachedGlobalRefsLength * sizeof(SEXP)); - free(cachedGlobalRefs); - cachedGlobalRefs = newCachedGlobalRefs; - cachedGlobalRefsLength = newLength; + SEXP newCachedGlobalRefs = calloc(newLength, sizeof(GlobalRefElem)); + if (newCachedGlobalRefs == NULL) { + fatalError("FFI global refs table expansion failure"); } - result = (*env)->NewGlobalRef(env, obj); - cachedGlobalRefs[i] = result; - } else { - result = obj; + memcpy(newCachedGlobalRefs, cachedGlobalRefs, cachedGlobalRefsLength * sizeof(GlobalRefElem)); + free(cachedGlobalRefs); + cachedGlobalRefs = newCachedGlobalRefs; + cachedGlobalRefsLength = newLength; } - return result; + gref = (*env)->NewGlobalRef(env, obj); + cachedGlobalRefs[cachedGlobalRefsHwm].gref = gref; + cachedGlobalRefs[cachedGlobalRefsHwm].permanent = permanent; +#if TRACE_REF_CACHE + fprintf(traceFile, "gref: add: index %d, ref %p\n", cachedGlobalRefsHwm), gref; +#endif + cachedGlobalRefsHwm++; + return gref; } SEXP checkRef(JNIEnv *env, SEXP obj) { - SEXP result = checkCachedGlobalRef(env, obj, alwaysUseGlobal); - TRACE(TARGp, result); - return result; + SEXP gref = findCachedGlobalRef(env, obj); + TRACE(TARGpp, obj, global); + if (gref == NULL) { + return obj; + } else { + return gref; + } } -SEXP mkNamedGlobalRef(JNIEnv *env, SEXP obj) { - SEXP result = checkCachedGlobalRef(env, obj, 1); - return result; +SEXP createGlobalRef(JNIEnv *env, SEXP obj, int permanent) { + SEXP gref = findCachedGlobalRef(env, obj); + if (gref == NULL) { + gref = addGlobalRef(env, obj, permanent); + } + return gref; +} + +void releaseGlobalRef(JNIEnv *env, SEXP obj) { + for (int i = 0; i < cachedGlobalRefsHwm; i++) { + GlobalRefElem elem = cachedGlobalRefs[i]; + if (elem.gref == NULL || elem.permanent) { + continue; + } + if ((*env)->IsSameObject(env, elem.gref, obj)) { +#if TRACE_REF_CACHE + fprintf(traceFile, "gref: release: index %d, gref: %p\n", i, elem.gref); +#endif + (*env)->DeleteGlobalRef(env, elem.gref); + cachedGlobalRefs[i].gref = NULL; + } + } } void validateRef(JNIEnv *env, SEXP x, const char *msg) { diff --git a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h index 62da16cdcf08af4579691d82e5b5d7b427c627f7..78bbe21b9fe3c27f7113b2f213ac5500e5721929 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h +++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h @@ -46,10 +46,14 @@ void *unimplemented(char *msg); void fatalError(char *msg); // makes a call to the VM with x as an argument (for debugger validation) void validate(SEXP x); -// checks x against the list of canonical (named) refs, returning the canonical version if a match +// checks x against the list of global JNI refs, returning the global version if x matches (IsSameObject) SEXP checkRef(JNIEnv *env, SEXP x); -// creates a canonical (named) JNI global ref from x -SEXP mkNamedGlobalRef(JNIEnv *env, SEXP x); +// creates a global JNI global ref from x. If permanent is non-zero, calls to +// releaseGlobalRef are ignored and the global ref persists for the entire execution +// (used for the R global variables such as R_NilValue). +SEXP createGlobalRef(JNIEnv *env, SEXP x, int permanent); +// release a previously created JNI global ref +void releaseGlobalRef(JNIEnv *env, SEXP x); // validate a JNI reference void validateRef(JNIEnv *env, SEXP x, const char *msg); @@ -60,6 +64,7 @@ void callExit(JNIEnv *env); // called by callExit to deallocate transient memory void allocExit(); +// returns the jmp_buf at the current call depth jmp_buf *getErrorJmpBuf(); // Given the x denotes an R vector type, return a pointer to @@ -68,6 +73,9 @@ void *getNativeArray(JNIEnv *env, SEXP x, SEXPTYPE type); // Rare case where an operation changes the internal // data and thus the old C array should be invalidated void invalidateNativeArray(JNIEnv *env, SEXP oldObj); +void updateNativeArrays(JNIEnv *env); + +SEXP addGlobalRef(JNIEnv *env, SEXP obj, int permanent); void init_rmath(JNIEnv *env); void init_variables(JNIEnv *env, jobjectArray initialValues); diff --git a/com.oracle.truffle.r.native/fficall/src/jni/variables.c b/com.oracle.truffle.r.native/fficall/src/jni/variables.c index 328b067bd7ec76b0c201480912bc57097a77b9ae..ca381df5e2e84d8b6568bca259034d09d8227244 100644 --- a/com.oracle.truffle.r.native/fficall/src/jni/variables.c +++ b/com.oracle.truffle.r.native/fficall/src/jni/variables.c @@ -61,7 +61,8 @@ SEXP FASTR_NamespaceRegistry() { CTXT FASTR_GlobalContext() { JNIEnv *env = getEnv(); - return (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getGlobalContextMethodID); + CTXT res = (*env)->CallStaticObjectMethod(env, CallRFFIHelperClass, getGlobalContextMethodID); + return addGlobalRef(env, res, 0); } void init_variables(JNIEnv *env, jobjectArray initialValues) { @@ -104,7 +105,7 @@ void init_variables(JNIEnv *env, jobjectArray initialValues) { } else if (strcmp(nameChars, "R_NaInt") == 0) { R_NaInt = (*env)->CallIntMethod(env, value, intValueMethodID); } else { - SEXP ref = mkNamedGlobalRef(env, value); + SEXP ref = createGlobalRef(env, value, 1); if (strcmp(nameChars, "R_EmptyEnv") == 0) { R_EmptyEnv = ref; } else if (strcmp(nameChars, "R_NilValue") == 0) { diff --git a/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx b/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx index f9cf0613c24ce9f66f6d1c864deb23a289a24224..88fe94a62a6d39d815458b68669f08a7f1c49529 100644 --- a/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx +++ b/com.oracle.truffle.r.native/include/ed_Rinterface_gcntx @@ -12,6 +12,8 @@ extern SEXP R_getContextFun(CTXT); extern SEXP R_getContextCall(CTXT); extern SEXP R_getContextSrcRef(CTXT); extern int R_insideBrowser(); +extern int R_isGlobal(CTXT); +extern int R_isEqual(void*, void*); #else . +1 diff --git a/com.oracle.truffle.r.native/include/ed_Rinternals b/com.oracle.truffle.r.native/include/ed_Rinternals index 7aaafb1cd67144dfa7bfab280f75ba96bc8861f8..e4be8532d85dbe199c91ab944fd300e2f46ed299 100644 --- a/com.oracle.truffle.r.native/include/ed_Rinternals +++ b/com.oracle.truffle.r.native/include/ed_Rinternals @@ -64,4 +64,14 @@ LibExtern SEXP FASTR_NamespaceRegistry(); a #endif . +/R_PreserveObject/ +i +#ifdef FASTR +SEXP R_PreserveObject(SEXP); +#else +. ++1 +a +#endif +. w Rinternals.h diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java index 408009cdde54b9733d2917ab6f83e63f7cd56fa1..0cac8ae1caf25989e975c4cf4876315e0741de98 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/helpers/BrowserInteractNode.java @@ -26,8 +26,11 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.r.nodes.RASTBuilder; +import com.oracle.truffle.r.nodes.access.variables.ReadVariableNode; import com.oracle.truffle.r.runtime.JumpToTopLevelException; import com.oracle.truffle.r.runtime.RArguments; +import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RRuntime; import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.RSrcref; @@ -44,6 +47,7 @@ import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; import com.oracle.truffle.r.runtime.instrument.InstrumentationState.BrowserState; import com.oracle.truffle.r.runtime.nodes.RNode; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** * The interactive component of the {@code browser} function. @@ -58,6 +62,9 @@ import com.oracle.truffle.r.runtime.nodes.RNode; */ public abstract class BrowserInteractNode extends RNode { + // it's never meant to be executed + private static final RSyntaxNode browserCall = new RASTBuilder().call(RSyntaxNode.INTERNAL, ReadVariableNode.create("browser")); + public static final int STEP = 0; public static final int NEXT = 1; public static final int CONTINUE = 2; @@ -75,8 +82,13 @@ public abstract class BrowserInteractNode extends RNode { // we may be at top level where there is not caller boolean callerIsDebugged = callerFunction == null ? false : DebugHandling.isDebugged(callerFunction); int exitMode = NEXT; + RCaller currentCaller = RArguments.getCall(mFrame); + if (currentCaller == null) { + currentCaller = RCaller.topLevel; + } + RCaller browserCaller = RCaller.create(null, currentCaller, browserCall); try { - browserState.setInBrowser(true); + browserState.setInBrowser(browserCaller); LW: while (true) { String input = ch.readLine(); if (input != null) { @@ -145,7 +157,7 @@ public abstract class BrowserInteractNode extends RNode { } } finally { ch.setPrompt(savedPrompt); - browserState.setInBrowser(false); + browserState.setInBrowser(null); } return exitMode; } diff --git a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java index 8b1ae9741ca36934671297541093e59ed73e8074..c838d1a4caea37d395247dce3386331281fde0d5 100644 --- a/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java +++ b/com.oracle.truffle.r.runtime.ffi/src/com/oracle/truffle/r/runtime/ffi/jnr/CallRFFIHelper.java @@ -902,18 +902,19 @@ public class CallRFFIHelper { if (expr instanceof RPromise) { result = RContext.getRRuntimeASTAccess().forcePromise(null, expr); } else if (expr instanceof RExpression) { - result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, topLevel); + result = RContext.getEngine().eval((RExpression) expr, (REnvironment) env, RCaller.topLevel); } else if (expr instanceof RLanguage) { - result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, topLevel); + result = RContext.getEngine().eval((RLanguage) expr, (REnvironment) env, RCaller.topLevel); } else if (expr instanceof RPairList) { RPairList l = (RPairList) expr; RFunction f = (RFunction) l.car(); Object args = l.cdr(); if (args == RNull.instance) { - result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, null, new Object[0]); + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, null, new Object[0]); } else { RList argsList = ((RPairList) args).toRList(); - result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), topLevel, argsList.getNames(), argsList.getDataNonShared()); + result = RContext.getEngine().evalFunction(f, env == REnvironment.globalEnv() ? null : ((REnvironment) env).getFrame(), RCaller.topLevel, argsList.getNames(), + argsList.getDataNonShared()); } } else { @@ -1165,18 +1166,20 @@ public class CallRFFIHelper { return x; } - private static RCaller topLevel = RCaller.createInvalid(null); - public static Object getGlobalContext() { + Utils.warn("Potential memory leak (global context object)"); if (RFFIUtils.traceEnabled()) { RFFIUtils.traceUpCall("getGlobalContext"); } Frame frame = Utils.getActualCurrentFrame(); if (frame == null) { - return topLevel; + return RCaller.topLevel; + } + if (RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser()) { + return RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller(); } RCaller rCaller = RArguments.getCall(frame); - return rCaller == null ? topLevel : rCaller; + return rCaller == null ? RCaller.topLevel : rCaller; } public static Object getGlobalEnv() { @@ -1249,6 +1252,7 @@ public class CallRFFIHelper { // Checkstyle: stop method name check public static Object R_getGlobalFunctionContext() { + Utils.warn("Potential memory leak (global function context object)"); if (RFFIUtils.traceEnabled()) { RFFIUtils.traceUpCall("getGlobalFunctionContext"); } @@ -1258,26 +1262,28 @@ public class CallRFFIHelper { } RCaller currentCaller = RArguments.getCall(frame); while (currentCaller != null) { - if (!currentCaller.isPromise() && currentCaller.isValidCaller()) { + if (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller()) { break; } currentCaller = currentCaller.getParent(); } - return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller; + return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller; } public static Object R_getParentFunctionContext(Object c) { + Utils.warn("Potential memory leak (parent function context object)"); if (RFFIUtils.traceEnabled()) { RFFIUtils.traceUpCall("getParentFunctionContext"); } RCaller currentCaller = guaranteeInstanceOf(c, RCaller.class); while (true) { currentCaller = currentCaller.getParent(); - if (currentCaller == null || (!currentCaller.isPromise() && currentCaller.isValidCaller())) { + if (currentCaller == null || + (!currentCaller.isPromise() && currentCaller.isValidCaller() && currentCaller != RContext.getInstance().stateInstrumentation.getBrowserState().getInBrowserCaller())) { break; } } - return currentCaller == null || currentCaller == topLevel ? RNull.instance : currentCaller; + return currentCaller == null || currentCaller == RCaller.topLevel ? RNull.instance : currentCaller; } public static Object R_getContextEnv(Object c) { @@ -1285,7 +1291,7 @@ public class CallRFFIHelper { RFFIUtils.traceUpCall("getContextEnv", c); } RCaller rCaller = guaranteeInstanceOf(c, RCaller.class); - if (rCaller == topLevel) { + if (rCaller == RCaller.topLevel) { return RContext.getInstance().stateREnvironment.getGlobalEnv(); } Frame frame = Utils.getActualCurrentFrame(); @@ -1313,7 +1319,7 @@ public class CallRFFIHelper { RFFIUtils.traceUpCall("getContextEnv", c); } RCaller rCaller = guaranteeInstanceOf(c, RCaller.class); - if (rCaller == topLevel) { + if (rCaller == RCaller.topLevel) { return RNull.instance; } Frame frame = Utils.getActualCurrentFrame(); @@ -1341,27 +1347,10 @@ public class CallRFFIHelper { RFFIUtils.traceUpCall("getContextEnv", c); } RCaller rCaller = guaranteeInstanceOf(c, RCaller.class); - if (rCaller == topLevel) { + if (rCaller == RCaller.topLevel) { return RNull.instance; } - Frame frame = Utils.getActualCurrentFrame(); - if (RArguments.getCall(frame) == rCaller) { - return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller); - } else { - Object result = Utils.iterateRFrames(FrameAccess.READ_ONLY, new Function<Frame, Object>() { - - @Override - public Object apply(Frame f) { - RCaller currentCaller = RArguments.getCall(f); - if (currentCaller == rCaller) { - return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller); - } else { - return null; - } - } - }); - return result; - } + return RContext.getRRuntimeASTAccess().getSyntaxCaller(rCaller); } public static Object R_getContextSrcRef(Object c) { @@ -1384,4 +1373,21 @@ public class CallRFFIHelper { public static int R_insideBrowser() { return RContext.getInstance().stateInstrumentation.getBrowserState().inBrowser() ? 1 : 0; } + + public static int R_isGlobal(Object c) { + if (RFFIUtils.traceEnabled()) { + RFFIUtils.traceUpCall("isGlobal", c); + } + RCaller rCaller = guaranteeInstanceOf(c, RCaller.class); + + return rCaller == RCaller.topLevel ? 1 : 0; + } + + public static int R_isEqual(Object x, Object y) { + if (RFFIUtils.traceEnabled()) { + RFFIUtils.traceUpCall("isEqual", x, y); + } + return x == y ? 1 : 0; + } + } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java index a8dd3a444a1376e122400b57b0f2698e5a64728f..6de384ca59ac9e204f606368dfef7b05be3b566d 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RCaller.java @@ -33,6 +33,8 @@ import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; */ public final class RCaller { + public static final RCaller topLevel = RCaller.createInvalid(null); + private static final Object PROMISE_MARKER = new Object(); private final int depth; @@ -96,6 +98,11 @@ public final class RCaller { return new RCaller(callingFrame, node); } + public static RCaller create(Frame callingFrame, RCaller parent, RSyntaxNode node) { + assert node != null; + return new RCaller(depthFromFrame(callingFrame), parent, node); + } + public static RCaller create(Frame callingFrame, Supplier<RSyntaxNode> supplier) { assert supplier != null; return new RCaller(callingFrame, supplier); diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java index 065806b2fccacffc006817fc0a33d1f2d6b0e08c..5084d3acdce63c75618129a4a0b5e6385ce5de66 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RDeparse.java @@ -1064,7 +1064,7 @@ public class RDeparse { root = list.getDataAtAsObject(0); } } - return new DeparseVisitor(false, 80, true, 0, -1, constants).process(root).getContents(); + return new DeparseVisitor(false, 80, true, SHOWATTRIBUTES, -1, constants).process(root).getContents(); } @TruffleBoundary diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java index b76b2d347e9f4a5cbea64068bd04acec3bf89e6e..b1a55172ce2f496442b27013b8366f929c0f189e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/instrument/InstrumentationState.java @@ -35,6 +35,7 @@ import com.oracle.truffle.api.instrumentation.ExecutionEventListener; import com.oracle.truffle.api.instrumentation.Instrumenter; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.vm.PolyglotEngine; +import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RCleanUp; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.tools.Profiler; @@ -134,16 +135,16 @@ public final class InstrumentationState implements RContext.ContextState { } } - private boolean inBrowser; + private RCaller caller; private String lastEmptyLineCommand = "n"; private ArrayList<HelperState> helperStateList = new ArrayList<>(); - public void setInBrowser(boolean state) { - this.inBrowser = state; + public void setInBrowser(RCaller caller) { + this.caller = caller; } public boolean inBrowser() { - return inBrowser; + return caller != null; } public void setLastEmptyLineCommand(String s) { @@ -154,6 +155,10 @@ public final class InstrumentationState implements RContext.ContextState { return lastEmptyLineCommand; } + public RCaller getInBrowserCaller() { + return caller; + } + @TruffleBoundary public void push(HelperState helperState) { helperStateList.add(helperState); diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R index 767a8c3cbcd9b43a42eed4a917dcaba28353adaf..6f53923b5377add006be17e501fd321463e2ffff 100644 --- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R +++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/R/testrffi.R @@ -30,8 +30,8 @@ rffi.TYPEOF <- function(x) { .Call("invoke_TYPEOF", x, PACKAGE = "testrffi") } -rffi.error <- function() { - .Call("invoke_error", PACKAGE = "testrffi") +rffi.error <- function(msg = "invoke_error in testrffi") { + .Call("invoke_error", msg, PACKAGE = "testrffi") } rffi.dotExternalAccessArgs <- function(...) { @@ -95,3 +95,18 @@ rffi.iterate_iptr <- function(x) { .Call("iterate_iptr", x, PACKAGE = "testrffi") } +rffi.preserve_object <- function() { + .Call("preserve_object", PACKAGE = "testrffi") +} + +rffi.release_object <- function(x) { + invisible(.Call("release_object", x, PACKAGE = "testrffi")) +} + +rffi.findvar <- function(x, env) { + if (is.character(x)) { + x = as.symbol(x) + } + .Call("findvar", x, env, PACKAGE = "testrffi") +} + diff --git a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c index 0d6d6674ffcd3812a1b859494df934aebf536b1c..61f4862f88ee9e9ae9ea2f93e8c919517571f6c5 100644 --- a/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c +++ b/com.oracle.truffle.r.test.native/packages/testrffi/testrffi/src/testrffi.c @@ -89,8 +89,8 @@ SEXP invoke_TYPEOF(SEXP x) { return ScalarInteger(TYPEOF(x)); } -SEXP invoke_error() { - error("invoke_error in testrffi"); +SEXP invoke_error(SEXP msg) { + error(R_CHAR(STRING_ELT(msg, 0))); } // returns a @@ -258,3 +258,25 @@ SEXP iterate_iptr(SEXP x) { UNPROTECT(1); return v; } + +SEXP preserve_object(void) { + SEXP v; + v = allocVector(INTSXP, 1); + R_PreserveObject(v); + return v; +} + +SEXP release_object(SEXP x) { + R_ReleaseObject(x); + return R_NilValue; +} + +SEXP findvar(SEXP x, SEXP env) { + SEXP v = Rf_findVar(x, env); + if (v == R_UnboundValue) { + Rf_error("'%s' not found", R_CHAR(PRINTNAME(x))); + } else { + return v; + } +} +