Contents | Prev | Next | Index | The JavaTM Virtual Machine Specification |
This appendix discusses the differences between the original version of The JavaTM Virtual Machine Specification and the present revision. Its purpose is twofold: to summarize what changes have been made and to explain why they were made.
Throughout this appendix, we refer to the original version of The JavaTM Virtual Machine Specification (that is, the first published version of this book) as the original specification or the original specification of the Java virtual machine. We refer to the current book as the revised specification. We denote the first edition of The JavaTM Language Specification as simply The JavaTM Language Specification.
The revised specification seeks to clarify points that gave rise to misunderstanding and to correct ambiguities, errors, and omissions in the original specification.
Except for the treatment of floating-point computation, the differences between the revised specification and its predecessor have no effect on valid programs written in the Java programming language. The revisions influence only how the virtual machine handles incorrect programs. In many of these instances, most implementations did not implement the original specification. The revised specification documents the intended behavior.
The most obvious changes are in the specification of floating-point types and operations; class
file verification; initialization, loading, and linking; and the method invocation instructions. In addition, several other important corrections have been made.
The revised specification also fixes errors or clarifies issues that were brought to our attention by readers of the original specification.
While we have made every effort to correct as many problems as possible, we recognize that additional improvements would benefit this specification. In particular, we believe that the description of class
file verification should be further refined, ideally to the point of constituting a formal specification. We anticipate that future revisions will address remaining weaknesses and correct any newly reported bugs, while retaining unchanged the semantics of the Java programming language.
The following sections discuss the changes to the original specification in greater detail and explain why the changes were necessary.
As a result of this change, implementations on processors that more naturally and efficiently support extended precision formats and floating-point operations on extended precision formats can deliver better performance for floating-point calculations. Implementations on processors that naturally and efficiently implement IEEE 754 single- and double-precision operations as mandated by the original specification may continue to do so. The floating-point behavior of any Java virtual machine implementation that conforms to the original specification also conforms to the revised specification.
class
File Verificationclass
file verification is that every
Java virtual machine implementation must in fact perform verification. This is stated
unambiguously in the The JavaTM
Language Specification. The original specification
of the Java virtual machine contained several misleading sentences that led some
readers to conclude that verification was optional.
The discussion of the class
file format in Chapter 4 also corrects a number of small errors in the original specification. The most significant of these corrections are:
<clinit>
methods).
CONSTANT_Fieldref_info
can be an interface type since interfaces can contain static
fields.
native
or abstract
cannot have a Code
attribute.
class
file verification no longer bans attempts
to invoke abstract
methods; see a complete discussion of this issue later in this
appendix.
The evident confusion over the circumstances triggering initialization led us to reword the specification of when initialization occurs (§2.17.4). However, this reworded specification is equivalent to the original.
One of the original requirements was that a class would be initialized the first time one of its constructors is invoked. In the Java programming language, constructor invocation constitutes instance creation. Furthermore, since no instance method can be invoked if no instances exist, it is clear that the requirement that a class be initialized the first time one of its methods is invoked is relevant only for static
methods. By similar reasoning, the requirement that a class be initialized if any of its fields is accessed applies only to static
fields.
The original specification did not accurately describe the circumstances that would trigger initialization at the Java virtual machine level (see discussion later in this appendix). Section 5.5 now gives a simple and precise definition in terms of Java virtual machine instructions.
The key changes include the following:
The description of class loading in the original specification did not state that resolving a class required its superinterfaces to be resolved. This was an error in early Java virtual machine implementations that has been corrected.
The description of CONSTANT_Class_info
resolution in Section 5.1.1 of the
original specification implied that resolution of a reference to a class causes
it to be linked. While this was true of Sun's Java virtual machine implementation,
the description was more restrictive than The JavaTM
Language Specification
, which clearly states that Java virtual machine implementations have
flexibility in the timing of linking activities. The revised specification of the
Java virtual machine agrees with The JavaTM
Language Specification on this
issue.
The description of CONSTANT_Class_info
resolution in Section 5.1.1 of the
original specification implied that resolution of a class causes it to be initialized.
However, the original specification also included the contradictory
statement that initialization should occur only on the first active use of a class.
In a Java virtual machine implementation that performs lazy resolution, the
distinction is subtle. In other implementations the distinction is much clearer.
For example, eager resolution is explicitly allowed by The Java
Language
Specification. If resolution always provoked initialization, such an implementation
would be forced to perform eager initialization, in clear contradiction to
The JavaTM
Language Specification. The contradiction is resolved by decoupling
resolution from initialization.
A closely related problem is the statement in Section 5.1.2 of the original
specification that the loadClass
method of class ClassLoader
can cause
initialization to occur if its second argument is true
. This contradicts The
JavaTM
Language Specification, which states that only loading and linking
occur in this case. Again, the contradiction has been resolved to conform to
The JavaTM
Language Specification, for essentially the same reasons.
ClassLoader.loadClass(String)
.
The original specification stated that when loading a class or interface using a
user-defined class loader the Java virtual machine invokes the two-argument
method ClassLoader.loadClass(String,
boolean)
. The purpose of the
boolean
argument was to indicate whether linking should take place. However,
it was noted on page 144 of the original specification that this interface
was likely to change. It was recognized that placing responsibility for linking
on the class loader was both inappropriate and unreliable.
Beginning with JDK release 1.1, linking is handled directly by the Java
virtual machine. An additional method loadClass(String)
has also been
added to class ClassLoader
. This method may similarly be invoked by the
Java virtual machine. The revised specification defines class loading in terms
of the new method. The two argument version is still retained in the Java 2
platform v1.2 in the interests of compatibility, but plays no role in the revised
specification.
The subtleties of type safe linkage in the presence of multiple, user-defined class loaders were not sufficiently appreciated when the original specification was written. It has subsequently become clear that a detailed description of loading constraints on runtime types is warranted. Of course, the presence of loading constraints is observable only by invalid programs.
These rules follow from The JavaTM Language Specification, but were left implicit in the original specification. The rules correspond to the behavior of existing implementations.
Section 5.1.1 of the original specification states that a NoClassDefFoundError
should be thrown if the representation of a class or interface is invalid.
However, both The JavaTM
Language Specification and Section 2.16.2 of the
original specification state that a ClassFormatError
is thrown in this case.
Clearly, a ClassFormatError
is more appropriate.
The original specification was unclear as to whether, during method or field resolution, the referenced field had to be declared in the exact class referenced or could be inherited. This led to variations among Java virtual machine implementations and inconsistency between The Java Virtual Machine Specification and The JavaTM Language Specification. The revised specification gives a more precise description that agrees with the behavior of most implementations, but not with The JavaTM Language Specification. The JavaTM Language Specification will be corrected in its next edition.
This choice gives programmers the flexibility of moving methods and fields in the class hierarchy while retaining binary compatibility with previous implementations of their programs.
AbstractMethodError
may not be raised during preparation.
The JavaTM
Language Specification requires that adding a method to an interface
be a binary compatible change. However, Sections 5.1.1 and 2.16.3 of
the original specification require that preparation reject a class that has an
abstract
method unless that class is itself abstract
. The latter requirement
contradicts the former.
Consider the case of an interface I implemented by a class C that is not
abstract
. If a new method is added to I, C must implement it. However, if
an old version of C is used together with the new version of I at run time, C
will indeed have an abstract
method. If preparation were to raise an
AbstractMethodError
in this case, adding a method to I would not have
been a binary compatible change, since it would have resulted in a link-time
failure. Consequently, the check at preparation time has been dropped. This
change has implications for method invocation, as discussed below.
The description in Section 5.3 of the original specification omitted the checks required during interface method resolution. These checks (that the referenced interface exists and that the referenced method exists in that interface) are required by The JavaTM Language Specification and are performed by most widely used implementations of the Java virtual machine. The checks are documented in Section 5.4.3.4 of the revised specification.
As a consequence of the decoupling of class and interface initialization from resolution, it became necessary to specify when the Java virtual machine triggers initialization. This specification is given in Section 5.5 of the revised specification. As noted earlier, this description agrees with the specification of the events at the Java programming language level triggering initialization, given in Section 2.17.4 of the revised specification.
The descriptions of the method invocation instructions made use of the well-known concept of a method dispatch table. The method tables were used as expository devices, but unfortunately many readers mistakenly thought that the use of such tables was a requirement of the specification. To clarify this point, a lookup algorithm is given instead.
The original specification sometimes listed exceptions that could be raised by an instruction according to their position in the exception hierarchy, rather than by when they might occur. This usage was inconsistent and sometimes erroneous.
The intent of the categories Linking Exceptions and Runtime Exceptions
at the end of each instruction description is to describe at what phase of execution
an error will be thrown. An important example of this is the treatment
of UnsatisfiedLinkError
. The descriptions of all method invocation
instructions specify that native
methods are bound at run time if they have
not been bound already. If the binding fails, an UnsatisfiedLinkError
is
thrown. However, UnsatisfiedLinkError
is consistently listed in the
instruction descriptions of the original specification as a Linking Exception.
To make it clear that the exception is actually thrown at run time, the revised
specification lists UnsatisfiedLinkError
as a Runtime Exception in the
descriptions of all the method invocation instructions.
Another instance of this problem was in the description of the invokeinterface instruction. Most of the exceptions listed in the original specification of invokeinterface as Linking Exceptions actually occurred at run time. They are listed in the revised specification as Runtime Exceptions.
abstract
methods at run time.
This is a direct result of the elimination of the abstract
method check during
class or interface preparation, as discussed earlier. While in many cases the
use of an abstract
method on a class that is not abstract
will still result in
a link-time error, it is possible to construct cases where the error will not
occur until run time.
Consider an abstract
class A with abstract
method foo
and concrete
subclass B. If B neglects to implement foo
, then a method
void bar(A
a) {a.foo();}
will fail if invoked upon an instance of B. This will not be detected at link
time, but at run time. As a result, invokeinterface and invokevirtual may raise
an AbstractMethodError
at run time.
The description of the invokeinterface instruction now states that the target of the method invocation must support the referenced interface. This is required by The JavaTM Language Specification and has been a property of all major Java virtual machine implementations for some time.
The second bullet on page 261 of the original specification was redundant and has been removed. The other bullets have been reordered, and the fact that ordinarily the resolved method is selected for execution has been asserted explicitly. These changes do not alter the specification in any way, but serve only to make the text more understandable.
Innerclasses
and Synthetic
attributes,
described in the revised specification in Section 4.7.5 and Section 4.7.6, respectively,
were added in JDK release 1.1 in order to support nested classes.
Unfortunately, we have not been able to include a description of nested classes in the Java programming language overview given in Chapter 2. A complete description will be included in the next edition of the The JavaTM
Language Specification. Until then, refer to the documentation on the World Wide Web at http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses
.
The chapter has been removed from the revised specification. The optimization technique it described is now well understood. More important, the technique exactly as described is not used by many of the Java virtual machine implementations, including some of Sun's, developed since the original specification was published. The value of the chapter to tool writers has diminished for the same reason. Thus, the chapter is now best seen as documentation for a specific Java virtual machine implementation, making it inappropriate for the Java virtual machine specification.
class
file format has changed. The major version number is now intended to correspond to new platform major releases (for instance, the Java 2 platform, Standard Edition, v1.2), while the minor version number may be used to represent release levels of platform implementations (for instance, the Java 2 SDK, Standard Edition, v1.2.1). Since the first public release of the Java platform, all class
files have been generated using major version number 45 and minor version number 3. Hence, no existing well-formed class
file is affected by this change in interpretation.
class
files with the historically used version numbers.
final
. This documents the behavior of existing implementations.
IllegalMonitorStateException
. The original specification implicitly allowed for the raising of such an exception as a consequence of Section 8.5:
An unlock operation by thread T on lock L may occur only if the number of preceding unlock operations by T on L is strictly less than the number of preceding lock operations by T on L.
and Section 8.13:
If execution of the method's body is ever completed, either normally or abruptly, an unlock operation is automatically performed on that same lock.
However, this had not been stated clearly and explicitly.
synchronized
statements given in Section 8.13 of the original specification was erroneous. It stated the following:
If execution of the body is ever completed, either normally or abruptly, an unlock operation is automatically performed on that same lock.
This is a property of programs written in the Java programming language,
guaranteed by correct compilers for the Java programming language; it is not
guaranteed by the Java virtual machine. However, programs do indeed make
structured use of locking, and Java virtual machine implementations may rely
on and enforce this property. The appropriate rules are given in the revised
version of Section 8.13. As a consequence of those rules, IllegalMonitorStateException
exceptions may be raised by the return instructions and
athrow, and by the method invocation instructions when invoking native
methods.
Deprecated
attribute, an attribute introduced in JDK release 1.1 to support the @deprecated
tag in documentation comments, has been specified. The presence of a Deprecated
attribute does not alter the semantics of a class or interface.
Contents | Prev | Next | Index
The JavaTM Virtual Machine Specification
Copyright © 1999 Sun Microsystems, Inc.
All rights reserved
Please send any comments or corrections to jvm@java.sun.com