1
1
#include < cassert>
2
+ #include < unordered_map>
2
3
3
4
#include " jni_utils.h"
4
5
#include " org_bblfsh_client_v2_Context.h"
@@ -363,6 +364,7 @@ class Node : public uast::Node<Node *> {
363
364
JNIEnv *env = getJNIEnv ();
364
365
jobject val =
365
366
ObjectMethod (env, " valueAt" , METHOD_JNODE_VALUE_AT, CLS_JNODE, obj, i);
367
+ // TODO(#113) investigate, it looks like a potential memory leak
366
368
return lookupOrCreate (env->NewGlobalRef (val)); // new ref
367
369
}
368
370
@@ -399,11 +401,25 @@ class Node : public uast::Node<Node *> {
399
401
}
400
402
};
401
403
404
+ struct EqByObj {
405
+ bool operator ()(jobject a, jobject b) const {
406
+ return getJNIEnv ()->IsSameObject (a, b);
407
+ }
408
+ };
409
+
410
+ struct HashByObj {
411
+ std::size_t operator ()(jobject obj) const noexcept {
412
+ auto hash = IntMethod (getJNIEnv (), " hashCode" , " ()I" , CLS_OBJ, obj);
413
+ checkJvmException (" failed to call hashCode()" );
414
+ return hash;
415
+ }
416
+ };
417
+
402
418
class Context ;
403
419
404
420
class Interface : public uast ::NodeCreator<Node *> {
405
421
private:
406
- std::map <jobject, Node *> obj2node;
422
+ std::unordered_map <jobject, Node *, HashByObj, EqByObj > obj2node;
407
423
408
424
// lookupOrCreate either creates a new object or returns existing one.
409
425
// In the second case it creates a new reference.
@@ -414,15 +430,15 @@ class Interface : public uast::NodeCreator<Node *> {
414
430
if (node) return node;
415
431
416
432
node = new Node (this , obj);
417
- obj2node[obj] = node;
433
+ obj2node[node-> obj ] = node;
418
434
return node;
419
435
}
420
436
421
437
// create makes a new object with a specified kind.
422
438
// Steals the reference.
423
439
Node *create (NodeKind kind, jobject obj) {
424
440
Node *node = new Node (this , kind, obj);
425
- obj2node[obj] = node;
441
+ obj2node[node-> obj ] = node;
426
442
return node;
427
443
}
428
444
@@ -440,9 +456,9 @@ class Interface : public uast::NodeCreator<Node *> {
440
456
}
441
457
442
458
// toJ returns a JVM object associated with a node.
443
- // Returns a new reference.
444
459
jobject toJ (Node *node) {
445
460
if (!node) return nullptr ;
461
+ // TODO(#113) investigate, it looks like a potential memory leak
446
462
jobject obj = getJNIEnv ()->NewGlobalRef (node->obj );
447
463
return obj;
448
464
}
@@ -633,7 +649,7 @@ Java_org_bblfsh_client_v2_libuast_Libuast_00024UastIter_nativeInit(
633
649
}
634
650
635
651
// global ref will be deleted by Interface destructor on ctx deletion
636
- auto it = ctx->Iterate (env-> NewGlobalRef ( jnode) , (TreeOrder)order);
652
+ auto it = ctx->Iterate (jnode, (TreeOrder)order);
637
653
638
654
// this.iter = it;
639
655
setHandle<uast::Iterator<Node *>>(env, self, it, " iter" );
@@ -754,8 +770,7 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_Context_filter(
754
770
755
771
uast::Iterator<Node *> *it = nullptr ;
756
772
try {
757
- // global ref will be deleted by Interface destructor on ctx deletion
758
- it = ctx->Filter (env->NewGlobalRef (jnode), query);
773
+ it = ctx->Filter (jnode, query);
759
774
} catch (const std::exception &e) {
760
775
ThrowByName (env, CLS_RE, e.what ());
761
776
return nullptr ;
@@ -819,8 +834,10 @@ JNIEXPORT jobject JNICALL Java_org_bblfsh_client_v2_ContextExt_encode(
819
834
JNIEXPORT void JNICALL
820
835
Java_org_bblfsh_client_v2_ContextExt_dispose (JNIEnv *env, jobject self) {
821
836
ContextExt *p = getHandle<ContextExt>(env, self, nativeContext);
822
- setHandle<ContextExt>(env, self, 0 , nativeContext);
823
- delete p;
837
+ if (!p) {
838
+ delete p;
839
+ setHandle<ContextExt>(env, self, 0 , nativeContext);
840
+ }
824
841
}
825
842
826
843
// ==========================================
0 commit comments