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

Node.load() implementation #91

Merged
merged 4 commits into from
Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
11 changes: 0 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ stages:
- name: release
if: tag IS present


jobs:
include:
- name: 'All tests'
stage: test
if: tag IS present # TODO(bzz): enable on PRs as soon as migrated to V2
install: &test_setup_anchor
- docker run --privileged -d -p 9432:9432 --name bblfsh bblfsh/bblfshd
- docker exec -it bblfsh bblfshctl driver install --recommended
Expand All @@ -34,15 +32,6 @@ jobs:
after_failure: &failure_logs_anchor
- docker logs bblfsh

- name: 'V2: passing tests' # TODO(#83): remove, after both tests sets converge
install: *test_setup_anchor
script:
- sudo apt-get install -y binutils
- ./sbt assembly
- ./sbt "testOnly *Close* *ClientVersion* *SupportedLanguages* *BblfshClientParseTest"

after_failure: *failure_logs_anchor

- name: 'Cross-compile, release & publish to Sonatype'
stage: release
before_install:
Expand Down
162 changes: 142 additions & 20 deletions src/main/native/jni_utils.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#include "jni_utils.h"
#include <string>

// Class fully qualified names
const char *CLS_NODE = "org/bblfsh/client/v2/Node";
const char *CLS_CTX = "org/bblfsh/client/v2/Context";

extern JavaVM *jvm; // FIXME(bzz): double-check and document
// TODO(bzz): double-check and document. Suggestion and more context at
// https://github.com/bblfsh/client-scala/pull/84#discussion_r288347756
extern JavaVM *jvm;

JNIEnv *getJNIEnv() {
JNIEnv *pEnv = NULL;
Expand All @@ -21,38 +20,161 @@ JNIEnv *getJNIEnv() {
return pEnv;
}

const char CLS_NODE[] = "org/bblfsh/client/v2/Node";
const char CLS_CTX[] = "org/bblfsh/client/v2/Context";
const char CLS_OBJ[] = "java/lang/Object";
const char CLS_RE[] = "java/lang/RuntimeException";
const char CLS_JNODE[] = "org/bblfsh/client/v2/JNode";
const char CLS_JNULL[] = "org/bblfsh/client/v2/JNull";
const char CLS_JSTR[] = "org/bblfsh/client/v2/JString";
const char CLS_JINT[] = "org/bblfsh/client/v2/JInt";
const char CLS_JFLT[] = "org/bblfsh/client/v2/JFloat";
const char CLS_JBOOL[] = "org/bblfsh/client/v2/JBool";
const char CLS_JUINT[] = "org/bblfsh/client/v2/JUint";
const char CLS_JARR[] = "org/bblfsh/client/v2/JArray";
const char CLS_JOBJ[] = "org/bblfsh/client/v2/JObject";

const char METHOD_JNODE_KEY_AT[] = "(I)Ljava/lang/String;";
const char METHOD_JNODE_VALUE_AT[] = "(I)Lorg/bblfsh/client/v2/JNode;";
const char METHOD_JOBJ_ADD[] =
"(Ljava/lang/String;Lorg/bblfsh/client/v2/JNode;)Lscala/collection/"
"mutable/Buffer;";
const char METHOD_JARR_ADD[] =
"(Lorg/bblfsh/client/v2/JNode;)Lscala/collection/mutable/Buffer;";

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

// TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
void checkJvmException(std::string msg) {
bzz marked this conversation as resolved.
Show resolved Hide resolved
JNIEnv *env = getJNIEnv();
auto err = env->ExceptionOccurred();
if (err) {
env->ExceptionClear();

auto exceptionCls = env->FindClass(CLS_RE);
if (env->ExceptionCheck()) {
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()) {
env->ExceptionClear();
env->ThrowNew(exceptionCls,
msg.append(" - failed to find method toString").data());
return;
}

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

const char *utf = env->GetStringUTFChars(s, 0);
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);

env->Throw(exception);
}
}

jobject NewJavaObject(JNIEnv *env, const char *className, const char *initSign,
...) {
jclass cls = env->FindClass(className);
if (env->ExceptionOccurred() || !cls) {
return NULL;
}
checkJvmException(std::string("failed to find a class ").append(className));

jmethodID initId = env->GetMethodID(cls, "<init>", initSign);
if (env->ExceptionOccurred() || !initId) {
return NULL;
}
checkJvmException(std::string("failed to call a constructor with signature ")
.append(initSign)
.append(" for the class name ")
.append(className));

va_list varargs;
va_start(varargs, initSign);
jobject instance = env->NewObjectV(cls, initId, varargs);
va_end(varargs);
if (env->ExceptionOccurred() || !instance) {
return NULL;
}
checkJvmException(
std::string("failed get varargs for constructor of ").append(className));

return instance;
}

jfieldID getField(JNIEnv *env, jobject obj, const char *name) {
jclass cls = env->GetObjectClass(obj);
if (env->ExceptionOccurred() || !cls) {
return nullptr;
}
checkJvmException("failed get the class of an object");

jfieldID jfid = env->GetFieldID(cls, name, "J");
if (env->ExceptionOccurred() || !jfid) {
return nullptr;
}
checkJvmException(std::string("failed get a field ").append(name));

return jfid;
}

static jmethodID MethodID(JNIEnv *env, const char *method,
const char *signature, const char *className) {
jclass cls = env->FindClass(className);
checkJvmException(std::string("failed to find a class ").append(className));

jmethodID mId = env->GetMethodID(cls, method, signature);
checkJvmException(std::string("failed to get method ")
.append(className)
.append(".")
.append(method));

return mId;
}

jint IntMethod(JNIEnv *env, const char *method, const char *signature,
const char *className, const jobject *object) {
jmethodID mId = MethodID(env, method, signature, className);
checkJvmException(std::string("failed to get method ")
.append(className)
.append(".")
.append(method));

jint res = env->CallIntMethod(*object, mId);
checkJvmException(std::string("failed to call method ")
.append(className)
.append(".")
.append(method)
.append(" using signature ")
.append(signature));

return res;
}

jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
const char *className, const jobject *object, ...) {
jmethodID mId = MethodID(env, method, signature, className);
checkJvmException(std::string("failed to get method ")
.append(className)
.append(".")
.append(method));

va_list varargs;
va_start(varargs, object);
jobject res = env->CallObjectMethodV(*object, mId, varargs);
va_end(varargs);
checkJvmException(std::string("failed get varargs for ")
.append(className)
.append(".")
.append(method));

return res;
}
40 changes: 37 additions & 3 deletions src/main/native/jni_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,46 @@
#define _Included_org_bblfsh_client_libuast_Libuast_jni_utils

#include <jni.h>
#include <string>

extern const char *CLS_NODE;
extern const char *CLS_CTX;
// Fully qualified Java class names
extern const char CLS_NODE[];
extern const char CLS_CTX[];
extern const char CLS_OBJ[];
extern const char CLS_RE[];

// Fully qualified class names for Bablefish UAST types
extern const char CLS_JNODE[];
extern const char CLS_JNULL[];
extern const char CLS_JSTR[];
extern const char CLS_JINT[];
extern const char CLS_JFLT[];
extern const char CLS_JBOOL[];
extern const char CLS_JUINT[];
extern const char CLS_JARR[];
extern const char CLS_JOBJ[];

// Method signatures
extern const char METHOD_JNODE_KEY_AT[];
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[];

// Checks though JNI, if there is a pending excption on JVM side.
//
// Throws new RuntimeExpection to JVM in case there is,
// uses the origial one as a cause and the given string as a message.
void checkJvmException(std::string);

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

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

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

#endif
21 changes: 21 additions & 0 deletions src/main/native/org_bblfsh_client_v2_Context__.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading