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

Commit b7a9ef7

Browse files
authored
Merge pull request #115 from bzz/docs-and-leaks
Docs and leaks
2 parents e0fca9f + 79614f9 commit b7a9ef7

20 files changed

+186
-1100
lines changed

CONTRIBUTING.md

+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# Contribution Guidelines
2+
3+
As all source{d} projects, this project follows the
4+
[source{d} Contributing Guidelines](https://github.com/src-d/guide/blob/master/engineering/documents/CONTRIBUTING.md).
5+
6+
7+
# Developer documentation
8+
9+
This section has more extended documentation for a brave developer willing to
10+
contribute by diving into and debugging the native glue code in `src/main/native`.
11+
12+
## Build libuast with debug symbols
13+
This is not strictly necessary, but will help you to navigate though the stack-traces.
14+
15+
Clone [libuast](https://github.com/bblfsh/libuast) locally and from the project root do:
16+
```
17+
CGO_ENABLED=1 go build -buildmode=c-archive -gcflags "-N -l" -o=libuast.a ./src
18+
mv libuast.a ../scala-client/src/main/resources/libuast
19+
```
20+
21+
Sadly, on non-linux OSes you might still experience issues with CGO due to https://github.com/golang/go/issues/5221.
22+
23+
24+
## Build libscalauast with debug symbols
25+
Compiler flags need to be `-g -O0` used instead of `-fPIC -O2` that is used for releases:
26+
```
27+
$ g++ -shared -Wall -g -std=c++11 -O0 \
28+
-I/usr/include \
29+
"-I${JAVA_HOME}/include" \
30+
"-I${JAVA_HOME}/include/${platform}" \
31+
-Isrc/main/resources/libuast \
32+
-o "src/main/resources/lib/libscalauast${platform_ext}" \
33+
src/main/native/org_bblfsh_client_v2_libuast_Libuast.cc \
34+
src/main/native/jni_utils.cc src/main/resources/libuast/libuast.a
35+
```
36+
37+
## Run a single test under debugger
38+
To run a single test from CLI one can:
39+
40+
```
41+
./sbt 'testOnly org.bblfsh.client.v2.libuast.IteratorNativeTest -- -z "Native UAST iterator should return non-empty results on decoded objects"'
42+
```
43+
44+
When using `lldb`, the classpath needs to be manually set for the `java` executable:
45+
46+
```
47+
PATH="/usr/bin:$PATH" lldb -- java -ea -Xcheck:jni -Djava.library.path=src/main/resources -cp "target/classes:target/test-classes:src/main/resources:${HOME}/.ivy2/cache/org.scalatest/scalatest_2.11/bundles/scalatest_2.11-3.0.1.jar:${HOME}/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.11.jar:${HOME}/.ivy2/cache/org.scala-lang.modules/scala-xml_2.11/bundles/scala-xml_2.11-1.0.5.jar:${HOME}/.ivy2/cache/org.scalactic/scalactic_2.11/bundles/scalactic_2.11-3.0.1.jar:${HOME}/.ivy2/cache/commons-io/commons-io/jars/commons-io-2.5.jar:build/bblfsh-client-assembly-2.0.0-SNAPSHOT.jar:target/*" \
48+
org.scalatest.tools.Runner \
49+
-s org.bblfsh.client.v2.libuast.IteratorNativeTest \
50+
-z "Native UAST iterator" \
51+
-f iterator-native-test.txt
52+
```
53+
Actual test output will be saved in `iterator-native-test.txt`.
54+
55+
## When inside the debugger
56+
57+
These instructions are for `lldb`, but the steps should be similar in `gdb`.
58+
To load the debug symbols do:
59+
60+
```
61+
run
62+
continue
63+
continue
64+
target symbols add src/main/resources/lib/libscalauast.dylib.dSYM
65+
```
66+
67+
If that does not load the symbols, you have to make sure `libscalauast` library has
68+
already been loaded to the process by `target modules list`.
69+
If the library loads but symbols are not correctly displayed, it probably means
70+
the library is at the wrong filesystem path.
71+
Stop the debugger and do `rm -rf ./target/classes/lib/libscalauast.dylib*`
72+
73+
To actually debug, set a breakpoint like:
74+
```
75+
br s -r Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIter_nativeNext
76+
run
77+
c
78+
```
79+
80+
Check the stack trace and print values do:
81+
```
82+
bt
83+
p *node
84+
```
85+
86+
Check [official LLDB documentation](https://lldb.llvm.org/use/map.html) for more
87+
use cases and instructions.
88+
89+
## More tips on JNI debugging
90+
91+
A small curated list of really useful resources on Go&JNI debugging:
92+
- https://github.com/facebook/rocksdb/wiki/JNI-Debugging
93+
- https://gist.github.com/dwbuiten/c9865c4afb38f482702e#2-debugging-tips
94+
- Go and LLDB http://ribrdb.github.io/lldb/
95+
96+
## JNI details
97+
98+
Here are some resources to understand the JNI machinery and its best practices:
99+
- https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/design.html
100+
- https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html
101+
- https://developer.android.com/training/articles/perf-jni
102+
- https://www.artima.com/insidejvm/ed2/jvm9.html
103+
- http://blog.jamesdbloom.com/JVMInternals.html

README.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
## Babelfish Scala client [![Build Status](https://travis-ci.org/bblfsh/scala-client.svg?branch=master)](https://travis-ci.org/bblfsh/scala-client)
22

3-
This a Scala/JNI implementation of the [Babelfish](https://doc.bblf.sh/) client.
3+
This is a Scala/JNI implementation of the [Babelfish](https://doc.bblf.sh/) client.
44
It uses [ScalaPB](https://scalapb.github.io/grpc.html) for Protobuf/gRPC code
55
generation and [libuast](https://github.com/bblfsh/libuast) for XPath queries.
66

77
### Status
88

9-
Current `scala-client` v1.x only supports bblfsh protocol and UASTv1.
9+
The latest `scala-client` *v2.x* supports the [UASTv2 protocol](https://doc.bblf.sh/uast/uast-specification-v2.html).
1010

1111
### Installation
1212

13-
#### Manual
13+
#### Building from sources
1414
```
1515
git clone https://github.com/bblfsh/scala-client.git
1616
cd scala-client
@@ -32,12 +32,14 @@ If the build fails because it can't find the `jni.h` header file, run it with:
3232

3333
Changing the JDK directory to the one right for your system.
3434

35+
For more developer documentation please check our [CONTRIBUTING](./CONTRIBUTING.md) guideline.
36+
3537
#### Apache Maven
3638

3739
The `bblfsh-client` package is available thorugh [Maven
3840
central](http://search.maven.org/#search%7Cga%7C1%7Cbblfsh), so it can be easily
3941
added as a dependency in various package management systems. Examples of how to
40-
handle it for most commons systems are included below; for other systems just look
42+
handle it for most common systems are included below; for other systems just look
4143
at Maven central's dependency information.
4244

4345
```xml
@@ -73,7 +75,7 @@ docker run --privileged --rm -it -p 9432:9432 --name bblfsh bblfsh/bblfshd
7375
```
7476

7577
Please, read the [getting started](https://doc.bblf.sh/using-babelfish/getting-started.html)
76-
guide to learn more about how to use and deploy a bblfsh server.
78+
guide to learn more about how to use and deploy a bblfsh server, install language drivers, etc.
7779

7880
API
7981
```scala
@@ -103,7 +105,7 @@ java -jar build/bblfsh-client-assembly-*.jar -f <file.py>
103105
or if you want to use a XPath query:
104106

105107
```
106-
java -jar build/bblfsh-client-assembly-*.jar -f <file.py> -q "//Import[@roleImport]"
108+
java -jar build/bblfsh-client-assembly-*.jar -f <file.py> -q "//uast:Import"
107109
```
108110

109111
Please read the [Babelfish clients](https://doc.bblf.sh/user/language-clients.html)

build.sbt

+2-2
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,8 @@ def compileUnix(sourceFiles: String) = {
166166
}
167167

168168
val osName = System.getProperty("os.name").toLowerCase()
169-
if (osName.contains("mac os x")) { // TODO(bzz): change back to '-fPIC -O2' for release
170-
val cmd:String = "g++ -shared -Wall -g -std=c++11 " +
169+
if (osName.contains("mac os x")) {
170+
val cmd:String = "g++ -shared -Wall -fPIC -O2 -std=c++11 " +
171171
"-I/usr/include " +
172172
"-I" + javaHome + "/include/ " +
173173
"-I" + javaHome + "/include/darwin " +

src/main/native/jni_utils.cc

+5-5
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ const char METHOD_JITER_INIT[] = "(Lorg/bblfsh/client/v2/JNode;IJJ)V";
6262
// Field signatures
6363
const char FIELD_ITER_NODE[] = "Ljava/lang/Object;";
6464

65-
// TODO(bzz): cache classes&methods in JNI_OnLoad should speed this up
65+
// TODO(#114): cache classes&methods in JNI_OnLoad should speed this up
6666
void checkJvmException(std::string msg) {
6767
JNIEnv *env = getJNIEnv();
6868
auto err = env->ExceptionOccurred();
@@ -224,14 +224,14 @@ jmethodID MethodID(JNIEnv *env, const char *method, const char *signature,
224224
}
225225

226226
jint IntMethod(JNIEnv *env, const char *method, const char *signature,
227-
const char *className, const jobject *object) {
227+
const char *className, const jobject object) {
228228
jmethodID mId = MethodID(env, method, signature, className);
229229
checkJvmException(std::string("failed to get method ")
230230
.append(className)
231231
.append(".")
232232
.append(method));
233233

234-
jint res = env->CallIntMethod(*object, mId);
234+
jint res = env->CallIntMethod(object, mId);
235235
checkJvmException(std::string("failed to call method ")
236236
.append(className)
237237
.append(".")
@@ -243,7 +243,7 @@ jint IntMethod(JNIEnv *env, const char *method, const char *signature,
243243
}
244244

245245
jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
246-
const char *className, const jobject *object, ...) {
246+
const char *className, const jobject object, ...) {
247247
jmethodID mId = MethodID(env, method, signature, className);
248248
checkJvmException(std::string("failed to get method ")
249249
.append(className)
@@ -252,7 +252,7 @@ jobject ObjectMethod(JNIEnv *env, const char *method, const char *signature,
252252

253253
va_list varargs;
254254
va_start(varargs, object);
255-
jobject res = env->CallObjectMethodV(*object, mId, varargs);
255+
jobject res = env->CallObjectMethodV(object, mId, varargs);
256256
va_end(varargs);
257257
checkJvmException(std::string("failed to get varargs for ")
258258
.append(className)

src/main/native/jni_utils.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ jmethodID MethodID(JNIEnv *, const char *, const char *, const char *);
7171
// Calls a method of the given class or interface name that returns an Int.
7272
// The method is determined by its name and signature.
7373
jint IntMethod(JNIEnv *, const char *, const char *, const char *,
74-
const jobject *);
74+
const jobject);
7575

7676
// Calls a method of the given class or interface name that returns an Object.
7777
// The method is determined by its name and signature.
7878
jobject ObjectMethod(JNIEnv *, const char *, const char *, const char *,
79-
const jobject *, ...);
79+
const jobject, ...);
8080

8181
// Constructs new object the given class name and throws it to JVM.
8282
//

src/main/native/org_bblfsh_client_v2_libuast_Libuast.cc

+12-11
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ class Node : public uast::Node<Node *> {
276276
const char methodName[] = "str";
277277
JNIEnv *env = getJNIEnv();
278278
jstring jstr = (jstring)ObjectMethod(
279-
env, methodName, "()Ljava/lang/String;", CLS_JSTR, &obj);
279+
env, methodName, "()Ljava/lang/String;", CLS_JSTR, obj);
280280

281281
const char *utf = env->GetStringUTFChars(jstr, 0);
282282
str = new std::string(utf);
@@ -339,7 +339,7 @@ class Node : public uast::Node<Node *> {
339339
return value;
340340
}
341341
size_t Size() {
342-
jint size = IntMethod(getJNIEnv(), "size", "()I", CLS_JNODE, &obj);
342+
jint size = IntMethod(getJNIEnv(), "size", "()I", CLS_JNODE, obj);
343343
assert(int32_t(size) >= 0);
344344

345345
return size;
@@ -349,7 +349,7 @@ class Node : public uast::Node<Node *> {
349349

350350
JNIEnv *env = getJNIEnv();
351351
jstring key = (jstring)ObjectMethod(env, "keyAt", METHOD_JNODE_KEY_AT,
352-
CLS_JNODE, &obj, i);
352+
CLS_JNODE, obj, i);
353353

354354
const char *k = env->GetStringUTFChars(key, 0);
355355
std::string *s = new std::string(k);
@@ -362,7 +362,7 @@ class Node : public uast::Node<Node *> {
362362

363363
JNIEnv *env = getJNIEnv();
364364
jobject val =
365-
ObjectMethod(env, "valueAt", METHOD_JNODE_VALUE_AT, CLS_JNODE, &obj, i);
365+
ObjectMethod(env, "valueAt", METHOD_JNODE_VALUE_AT, CLS_JNODE, obj, i);
366366
return lookupOrCreate(env->NewGlobalRef(val)); // new ref
367367
}
368368

@@ -375,7 +375,7 @@ class Node : public uast::Node<Node *> {
375375
v = NewJavaObject(env, CLS_JNULL, "()V");
376376
}
377377

378-
ObjectMethod(getJNIEnv(), "add", METHOD_JARR_ADD, CLS_JARR, &obj, v);
378+
ObjectMethod(getJNIEnv(), "add", METHOD_JARR_ADD, CLS_JARR, obj, v);
379379
checkJvmException(std::string("failed to call ")
380380
.append(CLS_JARR)
381381
.append(".add() from Node::SetValue()"));
@@ -391,7 +391,7 @@ class Node : public uast::Node<Node *> {
391391

392392
jstring k = env->NewStringUTF(key.data());
393393

394-
ObjectMethod(env, "add", METHOD_JOBJ_ADD, CLS_JOBJ, &obj, k, v);
394+
ObjectMethod(env, "add", METHOD_JOBJ_ADD, CLS_JOBJ, obj, k, v);
395395
checkJvmException(
396396
std::string("failed to call JObject.add() from Node::SetKeyValue(")
397397
.append(key)
@@ -633,7 +633,7 @@ Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIter_nativeInit(
633633
}
634634

635635
// global ref will be deleted by Interface destructor on ctx deletion
636-
auto it = ctx->Iterate(env->NewGlobalRef(jnode), (TreeOrder)order);
636+
auto it = ctx->Iterate(jnode, (TreeOrder)order);
637637

638638
// this.iter = it;
639639
setHandle<uast::Iterator<Node *>>(env, self, it, "iter");
@@ -754,8 +754,7 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_filter(
754754

755755
uast::Iterator<Node *> *it = nullptr;
756756
try {
757-
// global ref will be deleted by Interface destructor on ctx deletion
758-
it = ctx->Filter(env->NewGlobalRef(jnode), query);
757+
it = ctx->Filter(jnode, query);
759758
} catch (const std::exception &e) {
760759
ThrowByName(env, CLS_RE, e.what());
761760
return nullptr;
@@ -819,8 +818,10 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_ContextExt_encode(
819818
JNIEXPORT void JNICALL
820819
Java_org_bblfsh_client_v2_ContextExt_dispose(JNIEnv *env, jobject self) {
821820
ContextExt *p = getHandle<ContextExt>(env, self, nativeContext);
822-
setHandle<ContextExt>(env, self, 0, nativeContext);
823-
delete p;
821+
if (!p) {
822+
delete p;
823+
setHandle<ContextExt>(env, self, 0, nativeContext);
824+
}
824825
}
825826

826827
// ==========================================

src/main/scala/org/bblfsh/client/cli/CLI.scala

-16
This file was deleted.

src/main/scala/org/bblfsh/client/cli/ScalaClientCLI.scala

-39
This file was deleted.

0 commit comments

Comments
 (0)