|
JNIPort for Dolphin Smalltalk |
|
Back to Goodies |
Ghost ClassesJNIPort includes the Wrapper Wizard which uses Java's introspective facilities (such as they are) to generate wrapper methods for Java members. The ghost class concept takes this one step further. Ghost classes are (relatively) light-weight classes that are generated on demand, and which are discarded when the Java runtime shuts down. They are populated with ghost methods, which are essentially the same as the wrapper methods that would be generated by the Wrapper Wizard. In case you are interested, I came up with the name “ghost classes” because they are ephemeral and in a sense invisible. The word “ghost” seemed to express something of those ideas, and had not yet been overtaken by the computing community's ravening appetite for jargon.
Ghost classes do not appear in the standard browsers, since they are not fully
linked into the class hierarchy, and they are not installed in the global
The name of a ghost class is the fully qualified name of the corresponding Java class
for the instance side, and the same with '.static' added for the class side. The name is
only used by instances' Pros and ConsThe great advantage of ghost classes is that they are convenient. There is no need to mess about creating wrapper classes by hand (not even with the aid of the Wizard). They also have a performance edge, though the difference may not be significant for many applications.
The biggest disadvantage of ghost classes is that loading any Java class will
(subject to configuration) cause a ghost to be generated for it. But doing that
may well cause other classes to be loaded, and so on. For instance, in the
Swing example, the first mention of
Ghost classes also take up more memory, naturally. The impact is not huge, but it may matter in some cases. For one example, loading the 300 Swing classes causes around 6000 ghost methods to be generated; they take up, between them, around 1MB of memory. It's worth mentioning that the planned improvements to ghost class generation will also reduce the ghost method footprint — most of the Swing classes are never used (by JNIPort), and so would not have ghost methods generated for them. One other aspect of ghost classes might be considered to be a disadvantage. Ghost methods are generated as Smalltalk source (rather than by bytecode magic), so they need the compiler. Dolphin's licence does permit you to distribute the compiler DLL with a deployed application, but it is something of a nuisance, especially as the compiler is not included in “To-Go” applications. Using Ghost ClassesGhost classes are just dynamic special-cases of static wrapper classes, and all the observations about wrapper classes are true of ghost classes. In particular they use the same naming scheme for generated methods. The big difference, of course, is that you don't have to have generated a static wrapper to call a Java object's methods. You can use the ghost methods “raw” or you can set up helper methods. There are at least two ways of doing this in a reasonably well-structured way. You can use custom wrapper classes, or you can write a Facade/Adaptor class.
Using a custom wrapper class is just the same as writing a custom static wrapper class.
You create a subclass of
You can leave it at that; the single method
Alternatively, you can create an Adaptor or Facade. For instance the Smalltalk class
ConfigurationGhost class generation is controlled by the 'ghostClassSettings' sub-setting. Most of the settings determine what members will be exposed by ghost methods, they are the same as the corresponding flags that control the defaults for static wrapper generation. By default JNIPort will only expose “public” members. Custom wrapper classes can override the settings, but nothing in this version of JNIPort uses the feature. The 'retainMethodSource' flag controls whether JNIPort will keep the source to ghost methods. If it does then the source is stored as Strings in the image, not written to the change log. This setting is ignored except in development sessions. The remaining options control what kinds of objects JNIPort will generate ghost classes for:
How they workPlease note: this description has become slightly out of date. It is still accurate, but it should be updated to discuss the new lazy ghosts too
When JNIPort creates a class static for a Java class that it hasn't seen before (see
the class lifecycle), the
If the Java class has a superclass (interfaces do not, and neither does
After creating the appropriate class(es), the ghost maker populates them with ghost methods. It adds the same set of methods as a similarly configured Wrapper Wizard would, but the implementations of those methods is not the same (more on this below).
In normal circumstances the ghost methods expose (a subset of) the members of the Java
class. However there is one situation where ghost methods are generated for inherited
members too. This happens when the ghost maker is subclassing a non-ghost wrapper class.
For instance, after bootstrapping but before any
static wrapper classes have been converted into ghosts, the class registry is (temporarily)
set up so that instances of
There is one other special case, constructors. In Java, constructors are not inherited
(not even in the sense that static methods can be considered to be “inherited”).
For statically-generated wrappers that doesn't matter because attempting to use an
inherited wrapper for a constructor will cause a run-time error when the dynamic lookup
of the “inherited” constructor fails (or at least it should do,
I have noticed that the BEA JRockit runtime gets this wrong). For ghost methods, the
lookup is performed as the ghost method is created and the result is bound into the method.
That means that if the constructor wrapper were inherited, then when it was called from
a subclass, it would be calling the superclass's constructor, rather than creating an
instance of the subclass. The way that the ghost maker avoids this problems is to
ensure that all inherited constructors are overridden to call
Ghost MethodsGhost methods are created by the ghost maker to expose the underlying Java object's (or class's) methods and fields. They are created by compiling generated Smalltalk code. Normally the code is discarded immediately unless the 'retainMethodSource' is set and you are in a development session. The generated code is highly stereotyped, so the corresponding bytecodes tend to repeat often; ghost methods share their bytecode arrays wherever possible (in my current image, there are 14K ghost methods, but they only use 252 distinct bytecode arrays). Because the Smalltalk code is automatically generated, and isn't intended for people to read or modify, the ghost maker can take several performance-enhancing shortcuts. The generated code does not resemble that generated by the Wrapper Wizard. One optimisation is that ghost methods use the lowest levels of JNIPort directly, rather that going through the framework provided by level 2 ('Java Base') of JNIPort.
A second optimisation is that JNIPort can make use of information available when the method
is generated, to write code that otherwise would require a run-time lookup each time the method
was called. One application of this is that the JNI “method ID” can be resolved
at this time and hard-wired in the code (see below). The other is that, in some cases, the
method can be determined to return a Java object of a “final” class, for instance
The third optimisation is that JNIPort can embed references to the significant objects
directly in the method's literal frame. The effect is similar to using Dolphin's
If you have the 'retainMethodSource' option turned on, then you will see the Symbols if you step into a ghost method in the debugger. Please note: you cannot recompile the source of a ghost method and still expect it to work! (Which means that you can't set breakpoints in ghost methods.) The effects of these optimisations are that, compared to statically generated wrapper methods:
(All times measured on a Pentium3 laptop running at 650Mhz, using Sun's J2SDK 1.4.1 and Dolphin 5.0.3) |
Copyright © Chris Uppal, 2003-2005
Java, JNI (probably), JVM (possibly), and God knows what else, are trademarks of Sun Microsystems, Inc.