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

Commit d7cd8f0

Browse files
committed
v2: native .decode() and .root() implementations
Many tests are Ignored or are expected to fail, due to rest of the native API not implemented yet. Signed-off-by: Alexander Bezzubov <[email protected]>
1 parent 80a7a9e commit d7cd8f0

14 files changed

+338
-22
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ before_install:
2121
- docker run --privileged -d -p 9432:9432 --name bblfsh bblfsh/bblfshd
2222
- docker exec -it bblfsh bblfshctl driver install --recommended
2323
- sudo apt-get update
24-
- sudo apt-get install -y --no-install-recommends clang g++ gcc gcc-multilib libc6-dev libc6-dev-i386 mingw-w64 patch xz-utils libxml2-dev
24+
- sudo apt-get install -y --no-install-recommends clang g++ gcc gcc-multilib libc6-dev libc6-dev-i386 mingw-w64 patch xz-utils
2525

2626
env:
2727
global:

build.sbt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ getLibuast := {
121121
s"mv ${os}-amd64 libuast" #&&
122122
"rm -rf src/main/resources/libuast" #&&
123123
"mv libuast src/main/resources" #&&
124+
"rm src/main/resources/libuast.so" #&&
124125
"rm -rf libuast" #&&
125126
"rm libuast-bin.tar.gz" !
126127
}
@@ -133,10 +134,8 @@ compileScalaLibuast := {
133134

134135
"mkdir -p ./src/main/resources/lib/" !
135136

136-
val nativeSourceFiles = "src/main/native/org_bblfsh_client_libuast_Libuast.cc "
137-
// "src/main/native/jni_utils.cc " +
138-
// "src/main/scala/org/bblfsh/client/libuast/nodeiface.cc " +
139-
// "src/main/scala/org/bblfsh/client/libuast/memtracker.cc " +
137+
val nativeSourceFiles = "src/main/native/org_bblfsh_client_v2_libuast_Libuast.cc " +
138+
"src/main/native/jni_utils.cc "
140139

141140
compileUnix(nativeSourceFiles)
142141
crossCompileMacOS(nativeSourceFiles)
@@ -151,12 +150,14 @@ def compileUnix(sourceFiles: String) = {
151150
}
152151

153152
val osName = System.getProperty("os.name").toLowerCase()
154-
if (osName.contains("mac os x")) {
155-
val cmd:String = "g++ -shared -Wall -fPIC -O2 -std=c++11 " +
153+
if (osName.contains("mac os x")) { // TODO(bzz): change to '-fPIC -O2' for release
154+
val cmd:String = "g++ -shared -Wall -g -std=c++11 " +
156155
"-I/usr/include " +
157156
"-I" + javaHome + "/include/ " +
158157
"-I" + javaHome + "/include/darwin " +
159158
"-Isrc/main/resources/libuast " +
159+
"-Lsrc/main/resources/libuast " +
160+
"-l uast " +
160161
"-o src/main/resources/lib/libscalauast.dylib " +
161162
sourceFiles + " "
162163

@@ -167,6 +168,8 @@ def compileUnix(sourceFiles: String) = {
167168
"-I" + javaHome + "/include/ " +
168169
"-I" + javaHome + "/include/linux " +
169170
"-Isrc/main/resources/libuast " +
171+
"-Lsrc/main/resources/libuast " +
172+
"-l uast " +
170173
"-o src/main/resources/lib/libscalauast.so " +
171174
sourceFiles + " "
172175

@@ -194,6 +197,8 @@ def crossCompileMacOS(sourceFiles: String): Unit = {
194197
"-I/usr/lib/jvm/java-8-openjdk-amd64/include " +
195198
"-I/usr/lib/jvm/java-8-openjdk-amd64/include/linux " +
196199
"-Isrc/libuast-native/ " +
200+
"-Lsrc/main/resources/libuast " +
201+
"-l uast " +
197202
"-o src/main/resources/lib/libscalauast.dylib " +
198203
sourceFiles
199204

src/main/native/jni_handle.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#ifndef _JNI_HANDLE_H_INCLUDED_
2+
#define _JNI_HANDLE_H_INCLUDED_
3+
4+
#include <jni.h>
5+
6+
jfieldID getHandleField(JNIEnv *env, jobject obj, const char *name) {
7+
jclass cls = env->GetObjectClass(obj);
8+
if (env->ExceptionOccurred() || !cls) {
9+
return nullptr;
10+
}
11+
12+
jfieldID jfid = env->GetFieldID(cls, name, "J");
13+
if (env->ExceptionOccurred() || !jfid) {
14+
return nullptr;
15+
}
16+
return jfid;
17+
}
18+
19+
template <typename T>
20+
T *getHandle(JNIEnv *env, jobject obj, const char *name) {
21+
jlong handle = env->GetLongField(obj, getHandleField(env, obj, name));
22+
if (env->ExceptionOccurred() || !handle) {
23+
return nullptr;
24+
}
25+
return reinterpret_cast<T *>(handle);
26+
}
27+
28+
template <typename T>
29+
void setHandle(JNIEnv *env, jobject obj, T *t, const char *name) {
30+
jlong handle = reinterpret_cast<jlong>(t);
31+
env->SetLongField(obj, getHandleField(env, obj, name), handle);
32+
}
33+
34+
#endif

src/main/native/jni_utils.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#include "jni_utils.h"
2+
3+
// Class fully qualified names
4+
const char *CLS_NODE = "org/bblfsh/client/v2/Node";
5+
const char *CLS_CTX = "org/bblfsh/client/v2/Context";
6+
7+
extern JavaVM *jvm; // FIXME(bzz): double-check and document
8+
9+
JNIEnv *getJNIEnv() {
10+
JNIEnv *pEnv = NULL;
11+
12+
switch (jvm->GetEnv((void **)&pEnv, JNI_VERSION_1_8)) {
13+
case JNI_OK: // Thread is ready to use, nothing to do
14+
break;
15+
16+
case JNI_EDETACHED: // Thread is detached, need to attach
17+
jvm->AttachCurrentThread((void **)&pEnv, NULL);
18+
break;
19+
}
20+
21+
return pEnv;
22+
}
23+
24+
jobject NewJavaObject(JNIEnv *env, const char *className, const char *initSign,
25+
...) {
26+
jclass cls = env->FindClass(className);
27+
if (env->ExceptionOccurred() || !cls) {
28+
return NULL;
29+
}
30+
31+
jmethodID initId = env->GetMethodID(cls, "<init>", initSign);
32+
if (env->ExceptionOccurred() || !initId) {
33+
return NULL;
34+
}
35+
36+
va_list varargs;
37+
va_start(varargs, initSign);
38+
jobject instance = env->NewObjectV(cls, initId, varargs);
39+
va_end(varargs);
40+
if (env->ExceptionOccurred() || !instance) {
41+
return NULL;
42+
}
43+
44+
return instance;
45+
}
46+
47+
jfieldID getField(JNIEnv *env, jobject obj, const char *name) {
48+
jclass cls = env->GetObjectClass(obj);
49+
if (env->ExceptionOccurred() || !cls) {
50+
return nullptr;
51+
}
52+
53+
jfieldID jfid = env->GetFieldID(cls, name, "J");
54+
if (env->ExceptionOccurred() || !jfid) {
55+
return nullptr;
56+
}
57+
return jfid;
58+
}

src/main/native/jni_utils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#ifndef _Included_org_bblfsh_client_libuast_Libuast_jni_utils
2+
#define _Included_org_bblfsh_client_libuast_Libuast_jni_utils
3+
4+
#include <jni.h>
5+
6+
extern const char *CLS_NODE;
7+
extern const char *CLS_CTX;
8+
9+
JNIEnv *getJNIEnv();
10+
jobject NewJavaObject(JNIEnv *, const char *, const char *, ...);
11+
jfieldID getField(JNIEnv *env, jobject obj, const char *name);
12+
13+
#endif

src/main/native/org_bblfsh_client_v2_Context.h

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/native/org_bblfsh_client_v2_Node.h

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 132 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,136 @@
11
#include "org_bblfsh_client_v2_libuast_Libuast.h"
2+
#include "jni_handle.h"
3+
#include "jni_utils.h"
4+
#include "org_bblfsh_client_v2_Context.h"
25

3-
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_decode
4-
(JNIEnv *, jobject, jobject) {
5-
return NULL;
6+
#include "libuast.h"
7+
#include "libuast.hpp"
8+
9+
JavaVM *jvm; // FIXME(bzz): double-check and document
10+
11+
jobject asJvmBuffer(uast::Buffer buf) {
12+
JNIEnv *env = getJNIEnv();
13+
return env->NewDirectByteBuffer(buf.ptr, buf.size);
14+
}
15+
16+
class ContextExt {
17+
private:
18+
uast::Context<NodeHandle> *ctx;
19+
20+
jobject toJ(NodeHandle node) {
21+
if (node == 0) return nullptr;
22+
23+
JNIEnv *env = getJNIEnv();
24+
jobject jObj = NewJavaObject(env, CLS_NODE, "(JJ)V", this, node);
25+
return jObj;
26+
}
27+
28+
// toHandle casts an object to NodeExt and returns its handle.
29+
// Borrows the reference.
30+
NodeHandle toHandle(jobject obj) {
31+
if (!obj) return 0;
32+
33+
JNIEnv *env = getJNIEnv();
34+
jclass cls = env->FindClass(CLS_NODE);
35+
if (env->ExceptionOccurred() || !cls) {
36+
return 0;
37+
}
38+
39+
if (!env->IsInstanceOf(obj, cls)) {
40+
const char *err = "ContextExt.toHandle() called not on Node type";
41+
ctx->SetError(err);
42+
return 0;
43+
}
44+
45+
auto handle =
46+
(NodeHandle)env->GetLongField(obj, getField(env, obj, "handle"));
47+
if (env->ExceptionOccurred() || !handle) {
48+
return 0;
49+
}
50+
51+
return handle;
52+
}
53+
54+
public:
55+
friend class Context;
56+
57+
ContextExt(uast::Context<NodeHandle> *c) : ctx(c) {}
58+
59+
~ContextExt() { delete (ctx); }
60+
61+
jobject RootNode() {
62+
NodeHandle root = ctx->RootNode();
63+
return toJ(root);
64+
}
65+
66+
// Encode serializes existing-on-guest-side UAST.
67+
// Borrows the reference.
68+
jobject Encode(jobject node, UastFormat format) {
69+
NodeHandle h = toHandle(node);
70+
uast::Buffer data = ctx->Encode(h, format);
71+
return asJvmBuffer(data);
72+
}
73+
};
74+
75+
// v2.libuast.Libuast()
76+
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_decode(
77+
JNIEnv *env, jobject self, jobject directBuf) {
78+
UastFormat format = UAST_BINARY; // TODO: make it arg
79+
80+
// works only with ByteBuffer.allocateDirect()
81+
void *buf = env->GetDirectBufferAddress(directBuf);
82+
if (env->ExceptionCheck() == JNI_TRUE) {
83+
return nullptr;
84+
}
85+
jlong len = env->GetDirectBufferCapacity(directBuf);
86+
if (env->ExceptionCheck() == JNI_TRUE) {
87+
return nullptr;
88+
}
89+
90+
// another option (instead of XXX) is to use
91+
// GetPrimitiveArrayCritical
92+
uast::Buffer ubuf(buf, (size_t)(len));
93+
uast::Context<NodeHandle> *ctx = uast::Decode(ubuf, format);
94+
// ReleasePrimitiveArrayCritical
95+
96+
auto p = new ContextExt(ctx);
97+
98+
jobject jCtxExt = NewJavaObject(env, CLS_CTX, "(J)V", p);
99+
if (env->ExceptionCheck() == JNI_TRUE || !jCtxExt) {
100+
jCtxExt = nullptr;
101+
delete (ctx);
102+
env->ExceptionDescribe();
103+
throw std::runtime_error("failed to instantiate Context class");
104+
}
105+
106+
return jCtxExt;
6107
}
7108

8-
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_filter
9-
(JNIEnv *, jobject, jobject, jstring) {
10-
return NULL;
11-
}
109+
JNIEXPORT void JNICALL Java_org_bblfsh_client_v2_Context_dispose(JNIEnv *env,
110+
jobject self) {
111+
ContextExt *p = getHandle<ContextExt>(env, self, "nativeContext");
112+
setHandle<ContextExt>(env, self, 0, "nativeContext");
113+
delete p;
114+
}
115+
116+
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_libuast_Libuast_filter(
117+
JNIEnv *, jobject, jobject, jstring) {
118+
return NULL; // TODO(bzz): implement
119+
}
120+
121+
// v2.Context()
122+
JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_root(JNIEnv *env,
123+
jobject self) {
124+
ContextExt *p = getHandle<ContextExt>(env, self, "nativeContext");
125+
return p->RootNode();
126+
}
127+
128+
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
129+
JNIEnv *env;
130+
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_8) != JNI_OK) {
131+
return -1;
132+
}
133+
jvm = vm;
134+
135+
return JNI_VERSION_1_8;
136+
}

src/main/native/org_bblfsh_client_v2_libuast_Libuast.h

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)