I am reading the jdk 19(support the m1 chip when compile) source code, in the refactor source code in reflection.cpp, the function look like this:
oop Reflection::invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS) {
oop mirror = java_lang_reflect_Method::clazz(method_mirror);
int slot = java_lang_reflect_Method::slot(method_mirror);
bool override = java_lang_reflect_Method::override(method_mirror) != 0;
}
when I tracing this clazz function java_lang_reflect_Method::clazz:
oop java_lang_reflect_Method::clazz(oop reflect) {
return reflect->obj_field(_clazz_offset);
}
the obj_field function get the oop data from heap. This makes me a little confusing, the heap store the all object instance, why the reflection get data from heap? I think it will get the metadata from Method Area because in there store the class metadata, using the metadata, could construct the class info. the obj_field look like this:
inline oop oopDesc::obj_field(int offset) const { return HeapAccess<>::oop_load_at(as_oop(), offset); }
This reads the clazz field of a java.lang.reflect.Method object.
java.lang.reflect.Method is a regular Java class (with some support from native helpers). Why do you expect it not to be stored on the heap?
Note that java.lang.reflect.Method is not the same as a hotspot-internal C++ class Method.
The class Method is an implementation detail of the hotspot JVM engine and instances of this internal C++ class are never stored on the heap.
The following is a hypothetical problem. I'm purely interested if the effect is SOMEHOW achievable, by any obscure means imaginable (unsafe API, JNI, ASM etc). It is not an XY problem and I don't ever plan to write code like that! I'm just curious about internals.
Let's assume that we have this very simple hierarchy in Java:
class Cupcake {
public String kind;
// ...
}
class WholeRealityItself extends Cupcake {
public Object[] wholeMatterOfUniverse;
// transform internal state because reasons
public performBigBangAndFluctuateACupcake() {
// ... chaotic spacetime fluctuations produce a cupcake
this.kind = "quantum_with_sprinkles";
}
}
Our process is as follows:
WholeRealityItself reality = new WholeRealityItself();
reality.performBigBangAndFluctuateACupcake();
Cupcake cupcake = (Cupcake) reality; // upcast
// from now on the object will be only accessed via it's supertype and never downcast
Putting it into words:
We create an object of subtype, that has a lot of memory allocated.
We perform some internal state transformation on this subtype object.
We upcast the object to it's supertype and from now on we will ONLY refer to it by it's supertype and never downcast
So now our JVM holds a Cupcake reference to an internal WholeRealityItself object with memory that (the programmer knows) will never again be accessed. Yes, I know that references and actual allocated objects are two different things and upcasts/downcasts make the program just "reinterpret" an object.
Completely ignoring the fact that this abomination of a code is unusable and should be replaced with a sane builder/factory/copy or whatever, just assume for the sake of argument that we want it that way. The point is not how to achieve the same effect but if the following is possible:.
Can you force a narrowing of the actual allocated OBJECT to covert it's internals to a Cupcake from WholeRealityItself and force deallocation of wholeMatterOfUniverse?
AKA - can you SOMEHOW slice an underlying allocated OBJECT? Last questions about object slicing are from ~10 years ago.
AKA - can you SOMEHOW slice an underlying allocated OBJECT?
No you can't.
The object is represented by a heap node. If you did anything to interfere with the size or type (class) of the heap node, you are liable to crash the garbage collector.
I guess, you could use abstraction breaking (nasty!) reflection to identify and assign null to all of the fields added by the subclass. But the problem is that you can't do anything about methods of the superclass that the subclass has overloaded. If those methods refer to any of the fields that you have assigned null to, and something calls them, you have a potentially broken (smashed) object.
My advice: create a brand new Cupcake object using the relevant state from your WholeRealityItself object. It will have a different reference. Deal with that.
This David Wheeler quotation may be relevant ...
"All problems in computer science can be solved by another level of indirection."
Neither upcasts nor downcasts change the object itself - they only influence how the compiler treats the reference to the object.
One example are overriden methods: what method is called depends entirely on the runtime type of the object, not on the reference type that the compiler uses:
class Cupcake {
public String kind;
// ...
public void printMeOut() {
System.out.println("Cupcake");
}
}
class WholeRealityItself extends Cupcake {
public Object[] wholeMatterOfUniverse;
#Override
public void printMeOut() {
System.out.println("WholeRealityItself");
}
public performBigBangAndFluctuateACupcake() {
//...
}
}
After your sample code
WholeRealityItself reality = new WholeRealityItself();
reality.performBigBangAndFluctuateACupcake();
Cupcake cupcake = (Cupcake) reality; // upcast
// from now on the object will be only accessed via it's supertype and never downcast
the call cupcake.printMeOut(); will print out "WholeRealityItself" every time now matter how much time passed since the upcast.
You are talking about upcasting and nothing happens to your object. Only way to free would be to have a constructor in cupecake that would take another cupecake as input and would only use the needed parts. After you would release wholeworld.
It is known that using sun.misc.Unsafe#allocateInstance one can create an object without calling any class constructors.
Is it possible to do the opposite: given an existing instance, invoke a constructor on it?
Clarification: this is not the question about something I'd do in production code. I'm curious about JVM internals and crazy things that can still be done. Answers specific to some JVM version are welcome.
JVMS §2.9 forbids invocation of constructor on already initialized objects:
Instance initialization methods may be invoked only within the Java
Virtual Machine by the invokespecial instruction, and
they may be invoked only on uninitialized class instances.
However, it is still technically possible to invoke constructor on initialized object with JNI. CallVoidMethod function does not make difference between <init> and ordinary Java methods. Moreover, JNI specification hints that CallVoidMethod may be used to call a constructor, though it does not say whether an instance has to be initialized or not:
When these functions are used to call private methods and constructors, the method ID must be derived from the real class of obj, not from one of its superclasses.
I've verified that the following code works both in JDK 8 and JDK 9. JNI allows you to do unsafe things, but you should not rely on this in production applications.
ConstructorInvoker.java
public class ConstructorInvoker {
static {
System.loadLibrary("constructorInvoker");
}
public static native void invoke(Object instance);
}
constructorInvoker.c
#include <jni.h>
JNIEXPORT void JNICALL
Java_ConstructorInvoker_invoke(JNIEnv* env, jclass self, jobject instance) {
jclass cls = (*env)->GetObjectClass(env, instance);
jmethodID constructor = (*env)->GetMethodID(env, cls, "<init>", "()V");
(*env)->CallVoidMethod(env, instance, constructor);
}
TestObject.java
public class TestObject {
int x;
public TestObject() {
System.out.println("Constructor called");
x++;
}
public static void main(String[] args) {
TestObject obj = new TestObject();
System.out.println("x = " + obj.x); // x = 1
ConstructorInvoker.invoke(obj);
System.out.println("x = " + obj.x); // x = 2
}
}
It seems that with some (very dubious) tricks this is possible, even without going through a custom native library, by (ab)using method handles.
This method essentially tricks the JVM into thinking it is currently invoking a regular method instead of a constructor.
I just have to add a mandatory "this is probably not a good idea", but this is the only way I found for doing this. I also can't attest to how this behaves on different JVMs.
Prerequisites
To do this, an instance of sun.misc.Unsafe is needed. I will not go into detail about how to obtain this here since you already seem to have one, but this guide explains the process.
Step 1: Obtaining a trusted MethodHandles.Lookup
Next, a java.lang.invoke.MethodHandles$Lookup is needed to get the actual method handle for the constructor.
This class has a permission system which works through the allowedModes property in Lookup, which is set to a bunch of Flags. There is a special TRUSTED flag that circumvents all permission checks.
Unfortunately, the allowedModes field is filtered from reflection, so we cannot simply bypass the permissions by setting that value through reflection.
Even though reflecion filters can be circumvented aswell, there is a simpler way: Lookup contains a static field IMPL_LOOKUP, which holds a Lookup with those TRUSTED permissions. We can get this instance by using reflection and Unsafe:
var field = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
var fieldOffset = unsafe.staticFieldOffset(field);
var lookup = (MethodHandles.Lookup) unsafe.getObject(MethodHandles.Lookup.class, fieldOffset);
We use Unsafe here instead of setAccessible and get, because going through reflection will cause issues with the module system in the newer java versions.
Step 2: Finding the constructor
Now we can get a MethodHandle for the constructor we want to invoke. We do this by using the Lookup we just obtained, just like a Lookup would be used normally.
var type = MethodType.methodType(Void.TYPE, <your constructor argument types>);
var constructor = lookup.findConstructor(<your class>, type);
Step 3: Getting the MemberName
While the signature of findConstructor only specifies that it returns a MethodHandle, it actuall returns a java.lang.invoke.DirectMethodHandle$Constructor. This type declares a initMethod field, which contains the java.lang.invoke.MemberName referencing our constructor. The MemberName type is not accessible from the outside, so all interaction with it happens through Unsafe.
We can obtain this MemberName in the same way we also obtained the Lookup:
var constructorClass = Class.forName("java.lang.invoke.DirectMethodHandle$Constructor");
val initMethodField = constructorClass.getDeclaredField("initMethod");
val initMethodFieldOffset = unsafe.objectFieldOffset(initMethodField);
var initMemberName = unsafe.getObject(constructor, initMethodFieldOffset)
Step 4: Tricking Java
The next step is the important part. While there are no physical barriers from the JVM that prevent you from invoking a constructor like any other method, MethodHandle has some checks in place to ensure that you are not doing something fishy.
Most of the checks are circumvented by using the TRUSTED Lookup, and there remains one final check:
The MemberName instance contains a bunch of flags that, among other things, tell the system what kind of member the MemberName is referring to. These flags are checked.
To circumvent this, we can simply change the flags using Unsafe:
var memberNameClass = Class.forName("java.lang.invoke.MemberName");
var flagsField = memberNameClass.getDeclaredField("flags");
var flagsFieldOffset = unsafe.objectFieldOffset(flagsField);
var flags = unsafe.getInt(initMemberName, flagsFieldOffset);
flags &= ~0x00020000; // remove "is constructor"
flags |= 0x00010000; // add "is (non-constructor) method"
unsafe.putInt(initMemberName, flagsFieldOffset, flags);
The values for the flags come from java.lang.invoke.MethodHandleNatives.Constants#MN_IS_METHOD and java.lang.invoke.MethodHandleNatives.Constants#MN_IS_CONSTRUCTOR.
Step 5: Obtaining a REF_invokeVirtual method handle
Now that we have a totally legit method that is not at all a constructor, we just need to obtain a regular method handle for invoking it. Luckly, MethodHandles.Lookup.class has a private method for turning a MemberName into a (Direct)MethodHandle for all kinds of invocations: getDirectMethod.
Ironically, we actually call this method using our all-powerful lookup.
First, we obtain the MethodHandle for getDirectMethod:
var getDirectMethodMethodHandle = lookup.findVirtual(
MethodHandles.Lookup.class,
"getDirectMethod",
MethodType.methodType(
MethodHandle.class,
byte.class,
Class.class,
memberNameClass,
MethodHandles.Lookup.class
)
);
we can now use this with our lookup, to obtain a MethodHandle for our MemberName:
var handle = (MethodHandle) getDirectMethod.invoke(lookup, (byte) 5, Test.class, member, lookup);
The (byte) 5 argument stands for "invoke virtual", and comes from java.lang.invoke.MethodHandleNatives.Constants#REF_invokeVirtual.
Step 6: Profit?
We can now use this handle like a regular MethodHandle, to invoke the constructor on any existing instance of that class:
handle.invoke(<instance>, <constructor arguments...>);
With this handle, the constructor can also be called multiple times, and the instance doesn't actually have to come from Unsafe#allocateInstance - an instance that was created just by using new works aswell.
A constructor is not an instance method, so no you can't invoke a constructor on an instance.
If you look at the reflection library, you'll see that the return type of Class.getConstructor() is Constructor, which doesn't have any methods that can accept a instance - its only relevant method is newInstance(), which doesn't accept a target instance; it creates one.
On the other hand, the return type of Class.getMethod() is Method, whose first parameter is the instance.
A Constructor is not a Method.
In the JVM spec for invokespecial:
An invokespecial instruction is type safe iff all of the following are true:
... (Stuff about non-init methods)
MethodName is <init>.
Descriptor specifies a void return type.
One can validly pop types matching the argument types given in Descriptor and an uninitialized type, UninitializedArg, off the incoming operand stack, yielding OperandStack.
...
If you've already initialized the instance, it's not an uninitialized type, so this will fail.
Note that other invoke* instructions (invokevirtual, invokeinterface, invokestatic, invokedynamic) explicitly preclude invocation of <init> methods, so invokespecial is the only way to invoke them.
From JLS Sec 8.8
Constructors are invoked by class instance creation expressions (§15.9), by the conversions and concatenations caused by the string concatenation operator +(§15.18.1), and by explicit constructor invocations from other constructors (§8.8.7).
...
Constructors are never invoked by method invocation expressions (§15.12).
So no, it's not possible.
If there is some common action you want to take in the constructor and elsewhere, put it into a method, and invoke that from the constructor.
I'm a little confused what happens to an object created in a native function and is then returned to the calling Java method. For example, I have the following Java POJO:
public class Thing{
private int valueOne = 0;
public int getValueOne(){
return valueOne;
}
public void setValueOne(int value){
valueOne = value;
}
}
And I have a native method that creates a Thing object and returns it :
JNIEXPORT jobject JNICALL
create_thing(JNIEnv *env, jobject jobj){
/*
Code ommitted that gets methodID of Thing's default constructor.
*/
jobject result = (*env)->NewObject(env, thingClass, constructorID);
return result;
}
An finally I have some Java method that calls create_thing():
public Thing createThing(){
Thing thing = create_thing();
thing.setValueOne = 2;
return thing;
}
According to the JNI specification a call to NewObject (made in create_thing()) will return a LocalReference to an object, in this case a Thing. The create_thing() function returns the object immediately and in the case where it's called by a Java method as done in createThing() the LocalReference is deleted.
My question is, although the LocalReference is deleted does the object Thing still exist (because it is assigned to thing in the createThing() method)?
Am I correct in my understanding that the LocalReference is automatically deleted yet the object, provided it is assigned to a filed in the Java code remains in existence?
Furthermore, if the returned Thing were not assigned to a field then it would be marked for garbage collection?
Yes, you have it about right.
There is a difference between an object and a JNI local reference. The JNI framework deletes all local references when a method returns. (You can delete any earlier if you wish.) Deleting a reference does not delete the object it references.
In a garbage collected system, objects are not marked for collection. Instead, during a sweep, they are marked for retention. So, any created Thing is retained if it is referenced by a live object. Sweeping begins at one or more live "roots", which include JNI local and global references.
env->CallVoidMethod is returning java/lang/Class when using
env->GetObjectClass(aobject); //aobject was the argument sent by JNI to C++
aobject is a Java object that implements an interface.
jobject obj = env->GetObjectClass(aobject)
is supposed to return the Java object but instead is returning java/lang/Class
I encountered this error and had to ask around at work before I got a real answer.
The problem is that when you designate your native method as static, it supplies an instance of the jclass, not a jobject instance of that class, as it's called from a static context. (If you call getCanonicalName() on that jclass, it will return your class's name.)
If the native method needs to be static, then you should pass in the instance as an argument if you need it. Otherwise, just make it not static and you should be all fixed.
You haven't regenerated your .h/.c file since you removed 'static' so your JNI method signature doesn't match the Java one. You have an extra jclass in the argument list that is only there for static methods. So you're going to get some very strange execution.
The answer to my problem was described in "The Java Native Interface - Programmer's Guide and Specification" by Shen Liang.
"You can use Call< Type >Method family of functions to invoke interface methods as well. You must derive the method ID from the interface type"