Description of the problem:
We found a method where redefineClasses doesn't work as expected.
If we instrument a method during the ClassFileLoadHook, the transformed method is used. After we uninstrumented the method using redefineClasses and call the method, the old(instrumented) method is used.
We first thought that there are problems unjitting the method, but the problem occurred with -Xint too. All 1.6.0 VMs are affected, even jdk 1.6.0_11 (1.5 VMs haven't been tested).
A simple reproducer with a launch script for linux is attached.
The reproducer exchange the
org.hibernate.persister.entity.AbstractEntityPersister class during the ClassFileLoadHook with a version where the isVersioned method print its name.
Methods from this class get called every two seconds. After 5 seconds the class is redefined with a version where another method print its name, and the isVersioned method is uninstrumented. If these methods are called, hasCascades prints hasCascades - as expected - but isVersioned also prints isVersioned.
I added support to the TraceRedefineClasses option to catch
the case where an obsolete method is being called. Here are
snippets of the info gathered:
RedefineClasses-0x1000: calling obsolete method 'org.hibernate.persister.entity.AbstractEntityPersister.isVersioned()Z'
# Internal Error (src/share/vm/runtime/sharedRuntime.cpp:413)
# Error: guarantee(false,"should never call an obsolete method.")
Here is the stack trace from a decoded hs_err_pid file:
V [libjvm.so+0x92812f];; __1cNSharedRuntimeVrc_trace_method_entry6FpnKJavaThread_pnNmethodOopDesc__i_+0x263
j org.hibernate.persister.entity.AbstractEntityPersister.isVersioned()Z+0
j org.hibernate.event.def.AbstractSaveEventListener.substituteValuesIfNecessary(Ljava/lang/Object;Ljava/io/Serializable;[Ljava/lang/Object;Lorg/hibernate/persister/entity/EntityPersister;Lorg/hibernate/engine/SessionImplementor;)Z+33
j org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(Ljava/lang/Object;Lorg/hibernate/engine/EntityKey;Lorg/hibernate/persister/entity/EntityPersister;ZLjava/lang/Object;Lorg/hibernate/event/EventSource;Z)Ljava/io/Serializable;+155
j org.hibernate.event.def.AbstractSaveEventListener.performSave(Ljava/lang/Object;Ljava/io/Serializable;Lorg/hibernate/persister/entity/EntityPersister;ZLjava/lang/Object;Lorg/hibernate/event/EventSource;Z)Ljava/io/Serializable;+202
j org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Object;Lorg/hibernate/event/EventSource;Z)Ljava/io/Serializable;+193
j org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(Lorg/hibernate/event/PersistEvent;Ljava/util/Map;)V+55
j org.hibernate.event.def.DefaultPersistEventListener.onPersist(Lorg/hibernate/event/PersistEvent;Ljava/util/Map;)V+180
j org.hibernate.event.def.DefaultPersistEventListener.onPersist(Lorg/hibernate/event/PersistEvent;)V+7
j org.hibernate.impl.SessionImpl.firePersist(Lorg/hibernate/event/PersistEvent;)V+28
j org.hibernate.impl.SessionImpl.persist(Ljava/lang/String;Ljava/lang/Object;)V+11
j org.hibernate.impl.SessionImpl.persist(Ljava/lang/Object;)V+3
j Misc.urks(Lorg/hibernate/Session;)V+15
j Misc.main([Ljava/lang/String;)V+77
v ~StubRoutines::call_stub
V [libjvm.so+0x4821c7];; __1cJJavaCallsLcall_helper6FpnJJavaValue_pnMmethodHandle_pnRJavaCallArguments_pnGThread__v_+0x6c3
I'll take a look at org.hibernate.event.def.AbstractSaveEventListener.
substituteValuesIfNecessary() to see how it is calling
org.hibernate.persister.entity.AbstractEntityPersister.isVersioned().
That might tell me if we missed something during redefinition.
The call in org.hibernate.event.def.AbstractSaveEventListener.
substituteValuesIfNecessary() looks like this:
31: aload 4
33: invokeinterface #488, 1; //InterfaceMethod org/hibernate/persister/entity/EntityPersister.isVersioned:()Z
38: ifeq 76
I remember that TraceRedefineClasses output told me that there
were itable updates for isVersioned(), but I need to take a
closer look.
I've attached the reproducer.tgz file provided by the customer.
I've attached my initial draft of RedefineAbstractClass.sh to
this bug. This version of the test was written relative to
JDK6 so I'll have to tweak it for JDK7.