From 9f2d638b579033c45af8a308e9c6b878b2fc0eae Mon Sep 17 00:00:00 2001
From: Mick Jordan <mick.jordan@oracle.com>
Date: Mon, 8 Aug 2016 12:18:46 -0700
Subject: [PATCH] ffi: maintain stack of jmpbuf ptrs; run callEnter/callExit on
 Rembedded dowfalls

---
 .../fficall/src/jni/Rembedded.c               | 50 +++++++++++++------
 .../fficall/src/jni/rfficall.c                | 15 +++++-
 .../fficall/src/jni/rffiutils.c               | 19 ++++---
 .../fficall/src/jni/rffiutils.h               |  1 +
 .../packages/testrffi/testrffi/R/testrffi.R   | 10 +++-
 .../packages/testrffi/testrffi/src/testrffi.c | 14 +++++-
 6 files changed, 81 insertions(+), 28 deletions(-)

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 61431ad1d6..191cd77780 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) {
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 a8d153d4a0..9b2a545370 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 2ec1c0522e..30257753b7 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.c
@@ -43,7 +43,6 @@ jmethodID createSymbolMethodID;
 static jmethodID validateMethodID;
 
 static JNIEnv *curenv = NULL;
-jmp_buf *callErrorJmpBuf;
 
 // default for trace output when enabled
 FILE *traceFile = NULL;
@@ -84,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;
@@ -140,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;
@@ -149,7 +153,8 @@ 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) {
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 4311b0464a..8dad284ce3 100644
--- a/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
+++ b/com.oracle.truffle.r.native/fficall/src/jni/rffiutils.h
@@ -64,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
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 5f3f4ff8c3..6f53923b53 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(...) {
@@ -103,4 +103,10 @@ 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 21be9bc239..61f4862f88 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
@@ -270,3 +270,13 @@ 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;
+	}
+}
+
-- 
GitLab