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

Commit

Permalink
Merge pull request #91 from bzz/load-impl
Browse files Browse the repository at this point in the history
Node.load() implementation
  • Loading branch information
bzz authored Jul 4, 2019
2 parents 2bc2167 + c8091e6 commit 5b81fbb
Show file tree
Hide file tree
Showing 15 changed files with 833 additions and 94 deletions.
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) {
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

0 comments on commit 5b81fbb

Please sign in to comment.