Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Iterator implementation #106

Merged
merged 17 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 100 additions & 21 deletions src/main/native/jni_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ const char METHOD_JARR_ADD[] =

const char METHOD_OBJ_TO_STR[] = "()Ljava/lang/String;";

const char MERHOD_RE_INIT[] = "(Ljava/lang/String;)V";
const char MERHOD_RE_INIT_CAUSE[] =
"(Ljava/lang/String;Ljava/lang/Throwable;)V";

// Field signatures
const char FIELD_ITER_NODE[] = "Ljava/lang/Object;";

// TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
void checkJvmException(std::string msg) {
JNIEnv *env = getJNIEnv();
Expand All @@ -58,23 +65,15 @@ void checkJvmException(std::string msg) {
env->ExceptionClear();

auto exceptionCls = env->FindClass(CLS_RE);
if (env->ExceptionCheck()) {
if (env->ExceptionCheck() || !exceptionCls) {
env->ExceptionClear();
env->Throw(env->ExceptionOccurred());
return;
}

jclass cls = env->FindClass(CLS_OBJ);
if (env->ExceptionCheck()) {
env->ExceptionClear();
env->ThrowNew(
exceptionCls,
msg.append(" - failed to find class ").append(CLS_OBJ).data());
return;
}

jmethodID toString = env->GetMethodID(cls, "toString", METHOD_OBJ_TO_STR);
if (env->ExceptionCheck()) {
jmethodID toString =
env->GetMethodID(exceptionCls, "toString", METHOD_OBJ_TO_STR);
if (env->ExceptionCheck() || !toString) {
env->ExceptionClear();
env->ThrowNew(exceptionCls,
msg.append(" - failed to find method toString").data());
Expand All @@ -83,19 +82,39 @@ void checkJvmException(std::string msg) {

jstring s = (jstring)env->CallObjectMethod(err, toString);
if (env->ExceptionCheck() || !s) {
env->ExceptionClear();
env->ThrowNew(exceptionCls,
msg.append(" - failed co call method toString").data());
return;
}

const char *utf = env->GetStringUTFChars(s, 0);
jstring jmsg = env->NewStringUTF(msg.append(": ").append(utf).c_str());
env->ReleaseStringUTFChars(s, utf);

// new RuntimeException(msg.data(), err)
jmethodID initId = env->GetMethodID(
cls, "<init>", "(Ljava/lang/String;Ljava/lang/Throwable;)V");
jthrowable exception = (jthrowable)env->NewObject(
exceptionCls, initId, msg.append(": ").append(utf).data(), err);
// new RuntimeException(jmsg, err)
jmethodID initId =
env->GetMethodID(exceptionCls, "<init>", MERHOD_RE_INIT_CAUSE);
if (env->ExceptionCheck() || !initId) {
env->ExceptionClear();
env->ThrowNew(exceptionCls,
msg.append(" - failed to get method id for signature ")
.append(MERHOD_RE_INIT_CAUSE)
.c_str());
return;
}

jthrowable exception =
(jthrowable)env->NewObject(exceptionCls, initId, jmsg, err);
if (env->ExceptionCheck() || !exception) {
env->ExceptionClear();
env->ThrowNew(exceptionCls,
msg.append(" - failed to create a new instance of ")
.append(CLS_RE)
.append(MERHOD_RE_INIT_CAUSE)
.c_str());
return;
}

env->Throw(exception);
}
Expand All @@ -122,14 +141,67 @@ jobject NewJavaObject(JNIEnv *env, const char *className, const char *initSign,
return instance;
}

jfieldID getField(JNIEnv *env, jobject obj, const char *name) {
jfieldID FieldID(JNIEnv *env, jobject obj, const char *field,
const char *typeSignature) {
jclass cls = env->GetObjectClass(obj);
checkJvmException("failed get the class of an object");

jfieldID jfid = env->GetFieldID(cls, name, "J");
checkJvmException(std::string("failed get a field ").append(name));
// Note: printing the type from Scala to find the type needed for GetFieldID
// third argument using getClass.getName sometimes return objects different
// from the ones needed for the signature. To find the right type to use do
// this from Scala: (instance).getClass.getDeclaredField("fieldName")
jfieldID fId = env->GetFieldID(cls, field, typeSignature);
checkJvmException(std::string("failed get a field ID '")
.append(field)
.append("' for type signature '")
.append(typeSignature)
.append("'"));

return fId;
}
jobject ObjectField(JNIEnv *env, jobject obj, const char *name,
const char *signature) {
jfieldID fId = FieldID(env, obj, name, signature);
if (!fId) {
jstring jmsg =
env->NewStringUTF(std::string("failed to get field ID for field name '")
.append(name)
.append("' with signature '")
.append(signature)
.append("'")
.c_str());
jthrowable re =
(jthrowable)NewJavaObject(env, CLS_RE, MERHOD_RE_INIT, jmsg);
env->Throw(re);
return nullptr;
}
jobject fld = env->GetObjectField(obj, fId);
checkJvmException(std::string("failed get an object from field '")
.append(name)
.append("'"));
return fld;
}

return jfid;
jint IntField(JNIEnv *env, jobject obj, const char *name,
const char *signature) {
jfieldID fId = FieldID(env, obj, name, signature);
if (!fId) {
jstring jmsg =
env->NewStringUTF(std::string("failed to get field ID for field name '")
.append(name)
.append("' with signature '")
.append(signature)
.append("'")
.c_str());
jthrowable re =
(jthrowable)NewJavaObject(env, CLS_RE, MERHOD_RE_INIT, jmsg);
env->Throw(re);
return -1;
}
jint fld = env->GetIntField(obj, fId);
checkJvmException(
std::string("failed get an Int from field '").append(name).append("'"));
return fld;
}

jmethodID MethodID(JNIEnv *env, const char *method, const char *signature,
Expand Down Expand Up @@ -184,3 +256,10 @@ jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,

return res;
}

void ThrowByName(JNIEnv *env, const char *className, const char *msg) {
jclass cls = env->FindClass(className);
if (cls) {
env->ThrowNew(cls, msg);
}
}
13 changes: 11 additions & 2 deletions src/main/native/jni_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ extern const char METHOD_JNODE_VALUE_AT[];
extern const char METHOD_JOBJ_ADD[];
extern const char METHOD_JARR_ADD[];
extern const char METHOD_OBJ_TO_STR[];
extern const char MERHOD_RE_INIT[];
extern const char MERHOD_RE_INIT_CAUSE[];

// Field signatures
extern const char FIELD_ITER_NODE[];

// Checks though JNI, if there is a pending excption on JVM side.
//
Expand All @@ -36,13 +41,17 @@ void checkJvmException(std::string);

JNIEnv *getJNIEnv();
jobject NewJavaObject(JNIEnv *, const char *, const char *, ...);
jfieldID getField(JNIEnv *env, jobject obj, const char *name);
jfieldID FieldID(JNIEnv *, jobject, const char *, const char *);

jint IntField(JNIEnv *, jobject, const char *, const char *);
jobject ObjectField(JNIEnv *, jobject, const char *, const char *);

jint IntMethod(JNIEnv *, const char *, const char *, const char *,
const jobject *);

jobject ObjectMethod(JNIEnv *, const char *, const char *, const char *,
const jobject *, ...);

jmethodID MethodID(JNIEnv *, const char *, const char *, const char *);

void ThrowByName(JNIEnv *, const char *, const char *);
#endif
Loading