0

Given a java object A a = new A(), and a bunch of native instance methods, if I were to take the address of the jobject representing a passed into those methods, would the address always be the same?

I have multiple final fields in these classes that I want to store in a hashmap in my C code (so I don't have to continue fetching them with Get___Field), with the hash of a jobject being the address. If I can guarantee that the address of a passed in jobject representing a will always be the same, then the hash is deterministic, which means my program's behavior will not be inconsistent.

Mario Ishac
  • 5,060
  • 3
  • 21
  • 52
  • If you want to retain a reference to any object across multiple jni calls, you need to call NewGlobalRef. http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/refs.html. However, although that guarantees that the reference you hold remains valid, I don’t know if it guarantees that subsequent references passed in will match. – prl Nov 20 '18 at 00:16
  • @prl I've looked through that, but calling `NewGlobalRef` gives a global reference that can be assigned to a global variable, it doesn't seem to change whether the passed in `jobject` is global or local. Based on my current understanding, the passed in `jobject` is not something I construct and determine the locality of, the JVM constructs it and passes it in. – Mario Ishac Nov 20 '18 at 00:23
  • In a similar situation, I stored an “object id” (the hash) in the object. I had Java pass in the id as an additional parameter to the native method. – prl Nov 20 '18 at 00:27
  • @prl I might as well pass in the values of the final instance fields (and dropping the idea of a global hashmap in the C code) if I opt in for passing in additional parameters, would this be more performant than fetching the values within the C code through the JNI interface? – Mario Ishac Nov 20 '18 at 00:30
  • @prl If I made a static native method (which would be used in place of a constructor), that returns a global reference to a `jobject` (that represents the java instance), do you know if all the other `jobject`s that I would receive in my native instance methods would be equivalent to this global reference? – Mario Ishac Nov 20 '18 at 00:36
  • Thee, I don’t know. It seems likely to me. – prl Nov 20 '18 at 00:48
  • If you are going to use object references across JNI calls, you need NewGlobalRef (or NewWeakGlobalRef and then for each use, NewLocalRef). Otherwise, you won't be able to tell if your cached value is a still a valid object reference. And, no, a new reference is, well, a different reference, even for the same object. They are roots in the garbage collection system. – Tom Blodget Nov 25 '18 at 04:00
  • @TomBlodget so with this idea, I would still receive local references to the objects (through the method arguments), but I would just ignore them in favor of my cached global reference? – Mario Ishac Nov 25 '18 at 15:55
  • I'm just saying if you have a cache system it has to keep JNI global references. How you would do a lookup, I don't know. Perhaps a linear search using IsSameObject if you can't add an object identity field to each class. – Tom Blodget Nov 25 '18 at 17:27

1 Answers1

1

As comments have suggested, you cannot keep the passed-in jobject around beyond the current JNI call context because it is a local reference. The jobject values may be reused (leading to duplicate table entries) or become invalid. Furthermore, each call to CreateGlobalRef() will create a new, distinct jobject. The short answer is "you cannot do it this way". Such has been already addressed in this post. As an alternative approach, note that every Java Object has a hashCode() and equals() method. You can call those methods from your C/C++ code using JNI, and use them in your hash table. However, without knowing the details of when and how you are fetching the field values, calling JNI methods may not be any better than fetching the field values again.

Finally, as answered in this question, you can test jobject equality directly using env->IsSameObject(jobject1, jobject2). Presumably, jobject1 is the global reference that you have created and stored, whereas jobject2 is the passed-in local reference that you want to test against. Unfortunately this still doesn't help you probe into your hash table.

Wheezil
  • 3,157
  • 1
  • 23
  • 36
  • If I made a static native factory method that returns a global `jobject`, would that object still not be passed in to the instance native methods? – Mario Ishac Nov 27 '18 at 05:35
  • I don't think so. Anything passed *from* java *to* C/C++ is going to get a brand new local reference. – Wheezil Nov 27 '18 at 23:58