Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6805864

Problem with jvmti->redefineClasses: some methods don't get redefined

XMLWordPrintable

    • rc
    • 5.0
    • b03
    • generic, x86
    • generic, linux, solaris_10
    • Verified

        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.

              dcubed Daniel Daugherty
              ndcosta Nelson Dcosta (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: