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

Improved method forwarding (requires change to JVM)

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P4 P4
    • None
    • 1.2.0, 5.0
    • specification
    • vm
    • generic, x86
    • generic, windows_xp

      A DESCRIPTION OF THE REQUEST :
      The short summary: When the JVM throws a NoSuchMethodError, include in the error information about the method and arguments that failed (sufficient to permit the error to be caught, and an "invoke" message sent.)

      15.12.4.3 Check Accessibility of Type and Method

      An implementation of the Java programming language must insure, as part of linkage, that the method m still exists in the type T. If this is not true, then a NoSuchMethodError (which is a subclass of IncompatibleClassChangeError) occurs.

      The problem: NoSuchMethodError does not provide any information about what method, or what the arguments were; it is impossible for an exception handler to catch this, and decide at the Java code level how to redirect this message.

      Background/reasoning:


      JUSTIFICATION :
      I'd like to be able to create a Handle class.

      A Handle class would work like traditional handles -- indirect pointers. If I had a handle to MyClass, then I'd have an object of class Handle, with an instance variable with a value of an instance of class MyClass, and any (*1) message sent to this handle would be forwarded to the MyClass variable.

      A benefit of this is that it allows an object to transparently change class at run time, safely. If I have a group of objects that are able to "translate" themselves into strings, and then initialize themselves from a string, I might have the ability to change an object from a square to a circle, or something similar, at runtime. (This is potentially useful for an object-based drawing, or CAD program).

      Or, I might have a "DatabaseObject" class, where an instance of the class represents a row from a database. Because of large databases, circular references, etc, I only want to instantiate those obejcts that are actually used. If a database object has a reference to another database object (a foreign key), then I'd like to have a handle to a DatabaseObject instance. These instances would know how to identify their real class (and would respond to queries about their class appropriately), and if anyone asked for information about their contents, they would read in the appropriate row from the database, change the target ivar in the Handle object, and then forward the information to the new target.

      Similarly, I might want to implement a "Dual classed" object, such as something which is both a warrior and a diplomat. Anytime a message was sent, the "dual classed" object (a handle with two targets, a first and a second) would first try to have the first target handle it, and if it could not, it would give the message to the second.

      The "Dual classed" object could be used to implement multiple inheritence -- a MI object would appear as two seperate objects, with dual instantiations of the shared base classes. And, since either of the two handles could point to another dual class object, there is no limit to the number of "hidden children" that can be contained, making this fully general, other than the question of "Which root (Object) methods are handled specially by this master class and subclasses?". Different implementations of "Dual Classed" objects may vary only in the answer to that question.

      Now, this may seem silly, and you might think of the existing RMI and proxy system. That has limits.

      First, each proxy class has to hard code the specific methods that it handles. The current proxy class does this by using specified interfaces, and constructing a new class that supports only the specified interface methods. This has limits -- update a new version of a class, with more methods, and the interface declaration is the same, so the proxy class cannot "grow" as the underlying class grows.

      Second, this system requires that every proxy class have a seperate implementation class.

      Third, different proxy classes might differ in how some of the meta (Object) level methods are handled -- this means that the proxy classes need to be created with some extra knowledge

      In comparison, this sort of system already exists, in Objective C. In Objective C, class Object has one instance variable -- "isa", which is a pointer to the class table for the object's class. This not only allows the class to be identified, it allows the class to be changed. It means that any "object" is actually a pointer to a pointer to a class table, or, every object is actually a handle (a single pointer reference to the instance variables, and two pointer references to the class data). Now, Objective C -- being a C language derivitive -- is not safe, so this exact construct cannot be used. But a simple Handle class is safe, and a class that is only a handle to data (which can be changed to a new block of data with a single pointer swap) can currently be implemented. This would allow implementing code along with that block of data.

      Objective C does, in fact, have that "Database Object" scheme described above. Apple's EOF system implements exactly the scheme described above, where a placeholder class for a database row knows how to catch arbitrary unknown messages, read in the appropriate database row, change the class on the fly, and call the desired target class. The Dual Class scheme described above is one that I have considered implementing for multiple inheritance, and the only thing that stopped me from doing so was the difficulty of trying to find a "one size fits all" set of meta messages to override (I since determined that it has to be, at least to some extent, application specific).

      Objective C is able to implement these because the "Object X does not recognize message M" error includes all the invocation information. Java's does not.

      What could prevent this from being implemented?

      First, it's a change to the JVM. That's not a light change, no matter how tiny/trivial the change is. So, it needs to carry a LOT of value.

      Debuggers can use this extra information to report on bad message sends.
      Timing/tracing profilers can use these hooks to help developers optimize calls.

      THAT should be considered a lot of value.

      Second, security. The "handle" class isn't a security issue. It can be implemented today. What can not be implemented is the forwarding of failed messages. In some sense, you can catch the existing failed messages by creating dummy classes that use class definitions rather than interface definitions to create the intermediary forwarding class. So in a real sense, there is no security issue in having a small, compact forwarding class versus many large, specific forwarding classes.

      So, the benefits of this:
      1. Better debuggers and profilers
      2. Better ability to say "These groups of handles differ in how these Object methods are implemented.
      3. Easier ability to work with large numbers of these handle clases.
      4. Ability to switch to an object of a new type, not known before hand, that is able to save to/initialize from a string or byte array according to a convention, without having to create a brand new class each time
      5. The ability to work with classes even as they grow over time.


      (*1): Meta calls would NOT be forwarded. If, for example, I was trying to serialize the information (for storing onto a byte stream), I would serialize the handle information and then the object information). Other calls would similarly be handled first by the handle class, and then by the target class, or just by the handle class.
      ###@###.### 2004-11-11 00:17:07 GMT

            abuckley Alex Buckley
            rmandalasunw Ranjith Mandala (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: