Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 4514956
Votes 0
Synopsis Method.isObsolete() returns false for redefined method
Category hotspot:test
Reported Against merlin-beta3
Release Fixed 1.4.1(hopper)
State 11-Closed, Verified, bug
Priority: 4-Low
Related Bugs 4287595 , 4531511
Submit Date 15-OCT-2001
Description




This is the specification for Method.isObsolete():

    public boolean isObsolete()
     Determine if this method is obsolete. 
     Returns:
         true if this method has been replaced by 
         a non-equivalent method using
         VirtualMachine.redefineClasses(java.util.Map).

Although the specification doesn't define the meaning of 
the term "equivalent" in the context of the specification,
the meaning is in the specification for 
the JVMDI function Redefine Classes 
(http://java.sun.com/j2se/1.4/docs/guide/jpda/
jvmdi-spec.html#RedefineClasses):

    An original and a redefined method should be considered 
    equivalent if:
       their bytecodes are the same except for indicies into 
          the constant pool and 
       the referenced constants are equal.


However, the test against the Method.isObsolete()
developed on the basis of the above specifications shows
that isObsolete() being invoked on the Method  customer  
mirroring a method whose body has been fully replaced when
the method VirtualMachine.redefineClass had been invoked on 
the ReferenceType  customer  mirroring the class containing the method,
returns false.

This result is observed
when HS 1.4.0-beta3-b83 is runnning a test program 
on the following H/S configurations:

 - SUNW Ultra1: sparc 200MHz, RAM 128Mb;  
   OS: Solaris-8;            
   JVM: Client & Server
 -  customer : 2-processor i686 600MHz processor, RAM 512Mb;  
   OS: Solaris-8;            
   JVM: Client & Server
 -  customer : 2-processor i686 600MHz processor, RAM 512Mb;  
   OS: Linux/RedHat6.2;      
   JVM: Client & Server
 -  customer : Pentium-II 350MHz, RAM 128Mb;  
   OS: WinNT/4-Workstation;  
   JVM: Client & Server


Corresponding code fragments in a debugger and a debuggee
and corresponding log for the tested case are below.


Steps to reproduce the bug:
1. cd /net/sqesvr.sfbay/export/vsn/GammaBase/Bugs/{this bug ID}
2. sh doit.sh {JAVA_HOME}


This bug affects the following testbase_nsk tests:
    
    nsk/jdi/Method/isObsolete/isobsolete002

The tests will be in the next release of testbase_nsk;
the current release of testbase_nsk (1.4) is accessible through:

    /net/sqesvr.sfbay/export/vsn/VM/testbase/testbase_nsk.v14


///////////////////////////////////////////////////////////////////////

// code fragments in the debugger

        String className  = "nsk.jdi.Method.isObsolete.isobsolete002b";
        String methodName = "m2";

        ReferenceType redefClass = null;


          switch (i) {
              case 0:

                  log2("......getting: List classes = 
vm.classesByName(className);");
                  List          classes = vm.classesByName(className);
                  log2("......getting: redefClass = (ReferenceType) 
classes.get(0);");
                  redefClass = (ReferenceType) classes.get(0);

                  log2("......getting: Method method = (Method) 
redefClass.methodsByName(methodName).get(0);");
                  Method method = (Method) 
redefClass.methodsByName(methodName).get(0);
                  log2("......getting: boolean isObs = method.isObsolete();");
                  boolean isObs = method.isObsolete();
                  
                  if (isObs) {
                      log3("ERROR: method.isObsolete() == true");
                      testExitCode = FAILED;
                  } else
                      log2("     : method.isObsolete() == false");

                  try {
                      log2("......vm.redefineClasses(mapClassToBytes());");
                      vm.redefineClasses(mapClassToBytes());
                  } catch ( Exception e ) {
                      log3("ERROR:  Exception: " + e);
                      testExitCode = FAILED;
                      throw e;
                  } catch ( Error e ) {
                      log3("ERROR:  Error: " + e);
                      testExitCode = FAILED;
                      throw e;
                  }

                  log2("......getting: isObs = method.isObsolete();");
                  isObs = method.isObsolete();
                  if (isObs) {
                      log2("     : method.isObsolete() == true");
                  } else {
                      log3("ERROR: method.isObsolete() == false");
                      testExitCode = FAILED;
                  }
                  break;

              default:
                  throw new JDITestRuntimeException ("** default case **");
            }


=======================================================================
// code fragments in the debuggee


// --------------------file isobsolete002b.jav

public class isobsolete002b {

    isobsolete002b() {
        isobsolete002a.log1("   This is the class to be redefined");
    }

    static int i1 = 0;
    static int i2 = 0;

    static void m2() {
        i1 = 1;
        i2 = 1;
    }
     
    static void m1() {
        isobsolete002a.log1("method m1: before   m2()");
        m2();
        isobsolete002a.log1("method m1: after    m2()");
    }         
}


// --------------------file isobsolete002b.ja

public class isobsolete002b {

    isobsolete002b() {
        isobsolete002a.log1("   This is the class to redefine");
    }

    static int i1 = 0;
    static int i2 = 0;

    static void m2() {
        boolean b1 = true;
        isobsolete002a.log1("redefining method: b1 " + b1);
    }
     
    static void m1() {
        isobsolete002a.log1("method m1: before   m2()");
        m2();
        isobsolete002a.log1("method m1: after    m2()");
    } 

}

=======================================================================
// log with comments


==> nsk/jdi/Method/isObsolete/isobsolete002      TESTING BEGINS
--> debugger: breakpointForCommunication
debugee.stderr> **> debuggee: debuggee started!
debugee.stderr> **> debuggee:    This is the class to be redefined
debugee.stderr> **> debuggee: method m1: before   m2()
debugee.stderr> **> debuggee: method m1: after    m2()
                              ^^^^^^^^^^^^^^^^^^^^^^^^
                              no message between before and after
                              because m1() prints nothing

==> nsk/jdi/Method/isObsolete/isobsolete002 :::::: case: # 0
--> debugger: ......getting: List classes = vm.classesByName(className);
--> debugger: ......getting: redefClass = (ReferenceType) classes.get(0);
--> debugger: ......getting: Method method = (Method) 
redefClass.methodsByName(methodName).get(0);
--> debugger: ......getting: boolean isObs = method.isObsolete();
--> debugger:      : method.isObsolete() == false
--> debugger: ......vm.redefineClasses(mapClassToBytes());
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

--> debugger: ......getting: String[] args = argsHandler.getArguments();
--> debugger: ......File fileToBeRedefined = new File(fileToBeRedefinedName);
--> debugger:        fileToBeRedefined.exists(); length == 776
                                                 ^^^^^^^^^^^^^

--> debugger: ......File fileToRedefine = new File(fileToRedefineName);
--> debugger:        fileToRedefine.exists();    length == 1026
                                                 ^^^^^^^^^^^^^^

--> debugger: ......getting: isObs = method.isObsolete();
# ERROR: ##> debugger: ERROR: method.isObsolete() == false
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

debugee.stderr> **> debuggee: method m1: before   m2()
debugee.stderr> **> debuggee: redefining method: b1 true
                              ^^^^^^^^^^^^^^^^^^^^^^^^^^
                              message printed by new m2() method

debugee.stderr> **> debuggee: method m1: after    m2()


--> debugger: breakpointForCommunication

==> nsk/jdi/Method/isObsolete/isobsolete002     TESTING ENDS

----------------------------------------------------------------------

======================================================================




Ivan Popov <  xxxxx@xxxxx  >

This bug affects also the following JDWP test from testbase_nsk:

  nsk/jdwp/Method/IsObsolete/isobsolete002

======================================================================
Work Around
N/A
Evaluation
Need to look at for Hopper

  xxxxx@xxxxx   2002-01-30

It is correct for isObsolete() to return false in this use case.


In the javadoc for VirtualMachine.redefineClasses() we have the
following:
    All classes given are redefined according to the definitions
    supplied. If any redefined methods have active stack frames,
    those active frames continue to run the bytecodes of the
    previous method. The redefined methods will be used on new
    invokes.


The key phrase is:
    "If any redefined methods have active stack frames,
    those active frames continue to run the bytecodes of the
    previous method."

Only in the case of those active stack frames will a call
to thread.frame(0).location().method().isObsolete()
return true.  Thus you must be holding such a StackFrame
before or during the VirtualMachine.redefineClasses() call.
Any StackFrame or any Method lookup obtained after the
redefineClasses() will discover the redefined information,
and hence isObsolete() must correctly return false.

I conclude that this is a test bug and not a product bug.
See suggested fix.





Dostar Kasymov,   xxxxx@xxxxx  

I believe that the test case does not contradict to current specification
of isObsolete() method, which reads:

    public boolean isObsolete()
     Determine if this method is obsolete. 
     Returns:
         true if this method has been replaced by 
         a non-equivalent method using
         VirtualMachine.redefineClasses(java.util.Map).

This spec does say that true must be returned only in case when redefined 
method has active stack frame.

One can understand (as well as the developer of this test case) the statement
"true if this method has been replaced by a non-equivalent method using ..."
as "true if redefinition with non-equivalent method occurred in the past
before isObsolete() invocation".

I filed rfe against JDI spec:
 4633227 JDI spec: usage of methods implementing HotSwap feature needs clarification

Fix for the 4514956 is pending until decision on 4633227.



======================================================================




Fixed in testbase_nsk.v14r12, testbase_nsk.v131r12

The test was fixed in a following way. 
Additional breakpoint is created for a location inside checked
method in order to suspend main debuggee's thread at the moment 
of method execution. After breakpoint hit, redefineClasses 
is invoked. New mirror of checked method is obtained via 
mainThread.frame(0).location().method(). And then result of
isObsolete() is checked.

The test does not fail after this fix. Another test was also
fixed in the same way:
 nsk/jdi/Method/isObsolete/isobsolete001


======================================================================




Ivan Popov <  xxxxx@xxxxx  >

One more JDWP test is fixed due to this bug:

    nsk/jdwp/Method/IsObsolete/isobsolete002

After fixing the test successfully passes against Merlin-b92.

======================================================================
Comments
  
  Include a link with my name & email   


PLEASE NOTE: JDK6 is formerly known as Project Mustang