So I decided that the "easiest" way to answer my other question is to "simply" look at the implementation of the unsafe in C/C++.
(
In a nutshell, I have an Object base
and a long offset
in Java, that I'm passing to C/C++ by means of the Java Native Interface (JNI), from where I want to execute the C/C++ equivalent of
unsafe.setInt(base,offset,1)
)
Such an implementation is provided, for example, by the OpenJDK: unsafe.cpp
I don't care about most that's in there, I just want a direct access to values.
So looking at the implementation, I see
#define SET_FIELD(obj, offset, type_name, x) \
oop p = JNIHandles::resolve(obj); \
*(type_name*)index_oop_from_field_offset_long(p, offset) = x
Which I hope does what I expect it to do.
So looking at inline oop JNIHandles::resolve(jobject handle)
in jniHandles.hpp, the first line translates to
oop p = (handle == NULL ? (oop)NULL : *(oop*)handle);
The second line is casting the address to the proper pointer type and writing the value, so index_oop_from_field_offset_long(p,offset)
must be what produces the address. This one translates to
if (sizeof(char*) == sizeof(jint)) // (this constant folds!)
return (address)p + (jint) byte_offset;
else
return (address)p + byte_offset;
where byte_offset == offset
.
Combining the two, I believe this is the way to get the proper address (which I will have to cast to the proper type when reading/writing):
inline void* get_addr(jobject base, jlong offset){
oop p = (base == NULL ? (oop)NULL : *(oop*)base);
if (sizeof(char*) == sizeof(jint))
return (address)p + (jint) offset;
else
return (address)p + offset;
}
Great, now all I need to know is how to choose oop
and address
s.t. the address is properly created.
I don't necessarily need to care about what they are, exactly, I just need to do a
using oop = SOMETHING_MATCHING_OOP_IN_SIZE;
using address = SOMETHING_ELSE_THAT_MATCHES_ADDRESS;
But what? I've flipped through the files until I grew tired of missing what I'm looking for and downloaded the hotspot source files (links at the bottom of the navigation on the left side).
grep -r "typedef .* oop" .
executed from within the src
folder reveals
./share/vm/memory/classify.hpp:typedef enum oop_type {
./share/vm/oops/oopsHierarchy.hpp:typedef juint narrowOop; // Offset instead of address for an oop within a java object
./share/vm/oops/oopsHierarchy.hpp:typedef class klassOopDesc* wideKlassOop; // to keep SA happy and unhandled oop
./share/vm/oops/oopsHierarchy.hpp:typedef class oopDesc* oop;
so grep -r ".*class oopDesc.*" .
gives me
./share/vm/gc_implementation/parallelScavenge/parMarkBitMap.hpp:class oopDesc;
./share/vm/interpreter/bytecodeInterpreter.hpp: class oopDesc* r;
./share/vm/memory/universe.hpp: friend class oopDesc;
./share/vm/oops/oop.hpp:class oopDesc {
./share/vm/oops/oopsHierarchy.hpp:typedef class oopDesc* oop;
Opening oop.hpp, we find a 353 line class definition that I have no idea yet how to translate into a useful figure -- especially since at least on of the fields may or may not be there, depending on an #ifndef
There HAS to be an easier way to go about this. But I don't immediately see how. Any suggestions?