Unlike books on the Java API (application programming interface), which are a dime a dozen, books on the JVM are few and far between. This month I review the only three JVM books available at press time:
- The Java Virtual Machine Specification by Tim Lindholm and Frank Yellin (Addison-Wesley)
- Inside the Java Virtual Machine by Bill Venners (McGraw-Hill)
- Java Virtual Machine by Jon Meyer and Troy Downing (O'Reilly)
This table gives you a bird's-eye view of each book's main characteristics.
|The Java Virtual Machine Specification||Inside the Java Virtual Machine||Java Virtual Machine|
|Price (U.S. $)||39.95||39.95||32.95|
|475, 10 (0)||579, 20 (4)||426, 13 (4)|
|Listings Density (lines/page)||Not applicable||52||53|
|Java Native Interface (JNI)||No||Yes||No|
A bit of guidance for the table:
In the absence of tools to calculate the true cost-per-bit equivalent of a book, Listings Density gives you an idea of how dense or "aerated" the source listings are. Low lines/page values usually mean unreadable listings and a high page-fill factor, so the higher this value, the better. Because the Addison-Wesley book contains almost no code examples, this title has no "Listings Density" value.
Java Native Interface (JNI) indicates whether the book contains any discussion of the only important JVM-related change introduced with the 1.1 JDK -- that is, JNI.
The Java Virtual Machine Specification by Tim Lindholm and Frank Yellin
The operative word in this book's title is, without a shadow of a doubt, "Specification." As a specification for all would-be JVM implementors to follow, this book is very formal, frustratingly stingy with concrete implementation tips or pointers, yet precise to the point of reading like legalese.
This is not a book to enjoy in bed, rather, it is "The Law," delineating how any third-party JVM is to behave if it even hopes to acquire the much-coveted "Java compatible" status.
The Java Virtual Machine Specification starts off by reviewing Java language concepts that are relevant to any discussion of the JVM. Then, in Chapter 3, "Structure of the Java Virtual Machine," it offers an accurate, detailed overview of all the components and processes that together make a compatible JVM implementation: These include type support and enforcement, runtime "data areas" (operand stacks, the heap, Java stack, method area, constant pools, native method stacks, and areas), class file format, and last, but not least, the JVM instruction set.
Chapter 4 is called "The Class File Format," and is devoted to Java's nearest equivalent to a conventional "executable" file format. This chapter describes the structure of class files from the macro level (methods, fields, constant pool, and so on) right down to the bit-level encoding of some fields' bitfields. Chapter 5, "Constant Pool Resolution," discusses one of the key architectural features behind Java's powerful late binding (for methods as well as fields).
Chapter 6 enumerates and describes every JVM instruction in (abstract) detail, from aaload (the instruction to load an object reference from an array) to wide (a special instruction modifier to extend the normal local variable indexing range). Each instruction entry starts at the top of a page, so locating a given instruction is a breeze. Every instruction is described in a consistent manner, through the use of a template that should be familiar to any assembler programmer: mnemonic name (for example, nop, jsr, iadd, fmul, and so on), one-line synopsis, instruction format, opcode forms, stack before and afters, long description, and, possibly, notes. Notice that no code examples are given to illustrate possible contexts and/or uses for instructions.
Chapter 7, "Compiling for the Java Virtual Machine," is the first (and only) chapter in which the reader gets to see the JVM instructions "in action," exposed in disassembled snippets of Java code. While this chapter's title suggests it is mainly meant for compiler writers (of any language, not just Java) I suspect that this chapter will be devoured by many a Java programmer, as it contains much information that can be used to optimize Java (language) code.
What I view as the last true chapter of the book, Chapter 8, "Threads and Locks," is a highly technical discussion of how multithreading has to be supported by any JVM. Chapters 9 and 10 should have been designated as appendices, since basically that's what they are: "An Optimization" (discussing the "quick" opcodes in Sun's JVM implementation); and "Opcode Mnemonics by Opcode" (the standard processor user manual appendix table listing mnemonics in opcode-sorted order).
Inside the Java Virtual Machine by Bill Venners
Every regular JavaWorld reader will know Bill Venners (at least virtually, that is) and his in-depth knowledge of the Java virtual machine. With his recently retired Under the Hood column in JavaWorld, Java programmers got a sneak preview of what has now become a first-class Java book published by McGraw-Hill.
Before I delve into the structure and content of this book, I would like to mention the aspect of Venners's book that impressed me most of all: the sheer attention to detail and consistent accuracy of his writing. I've reviewed quite a few Java books in the last 12 months, and found that the majority are written by authors who use established terminology in a highly unprofessional, sloppy way. Bill Venners's book lies at the opposite, positive end of the scale: I could almost feel the concentration that went into the wording of every single phrase. Words with technically precise semantics like "type," "reference," "class," "object," and "interface" are used to express their precise, Java-specific meaning -- never in a technically incorrect sense. Because so many Java books are not written to such standards of technical excellence, I urge current and future Java book authors to read Venners's book (beginning with his "Some Terminology" on page xxxiv).
Venners's book consists of two main parts. The first four chapters lay some motivational foundations for Java's -- and the JVM's -- features ("Introduction to Java's Architecture," "Platform Independence," "Security," "Network Mobility"). Pervading these chapters are numerous deep insights into the history of computing and, of course, Java. These chapters certainly offer lots of added value over the average "let's-rehash-a-JavaSoft-spec" Java books out there.
The second part, and the real meat of the book, delves into the highly technical and multifaceted internals of every JVM. Time limitations prevent me from going into much detail on each of Venners's remaining chapters (Chapters 6 to 20), so I will enumerate the long list by giving their tell-tale titles instead:
Chapter 6 "The Java Class File"
Chapter 7 "The Lifetime of a Class"
Chapter 8 "The Linking Model"
Chapter 9 "Garbage Collection"
Chapter 10 "Stack and Local Variable Operations"
Chapter 11 "Type Conversion"
Chapter 12 "Integer Arithmetic"
Chapter 13 "Logic"
Chapter 14 "Floating-Point Arithmetic"
Chapter 15 "Objects and Arrays"
Chapter 16 "Control Flow"
Chapter 17 "Exceptions"
Chapter 18 "
Chapter 19 "Method Invocation and Return"
Chapter 20 "Thread Synchronization"
The recurring (and expensive-to-produce) features in these chapters are the animated, interactive, and enlightening applets that bring to life those chapters' main topics. The garbage collection chapter, for example, not only contains a good introduction to various modern garbage collection algorithms but also includes a "Heap of Fish" applet to let the reader accumulate a real, hands-on understanding of garbage collection issues and possible solutions. Adding, in my opinion, to his commendable credits as a professional book author (and not a conveyor-belt writer), Venners did not paste a single line of his numerous JVM-enlightening applets into his book. In short, he made no attempt to cheaply inflate the size of the volume. All applet source code (which, in its own right, will be quite valuable to many readers) is located on his book's accompanying CD-ROM instead. In fact, the amount and diversity of material in Chapters 6 to 20, and the depth to which it is explored, is such that inserting the complete code for even a single one of the applets would surely overload many a reader.
Like all the books in this review, Inside the Java Virtual Machine also contains a full instruction set reference (Appendix A). Finally, while Venners's writing is formal throughout the book, he manages to inject quite a bit of humor that thoroughly agreed with me.
Java Virtual Machine by Jon Meyer and Troy Downing
O'Reilly's entry in the JVM books niche is organized into three parts:
Machine Overview -- Chapters 1-6: "Overview," "Quick Tour," "Components of the Machine," "Classes," "Security," and "Implementation Notes"
Instruction Set Guide -- Chapters 7-11: "Data Operations," "Arithmetic," "Flow Control," "Exceptions," and "Threads"
- Reference -- Chapters 12 and 13: "Class File Reference" and "Instruction Reference"
The overview chapter introduces the JVM material by comparing the JVM with a conventional microprocessor (specifically, an Intel 8086). Such a comparison is a necessity, yet the two other books in this review fail to emphasize the fact that a JVM is a (virtual) microprocessor first and foremost, with lots of higher-level generic and Java-specific subsystems layered on top. Microprocessors can be programmed directly, without the aid of a high-level language (HLL), by way of assembly languages, yet the JVM spec does not formally define an assembler notation for its JVM instructions. Meyer and Downing side-step this problem in their book by defining their own notation, designed to resemble the output of
javap (the JDK class file disassembler utility), and implementing a complete, freely available assembler called "Jasmin." (As in Venners's book, here the source code is not listed in the book itself but is located on the accompanying floppy.)
The book's main strength lies in the inclusion of numerous Jasmin/JVM assembler examples. The authors' pedagogically sound reliance on Jasmin doesn't, however, prevent them from making mistakes: Their "Quick Tour" chapter contains increasingly complex Jasmin examples, presented too early -- before the reader has even been introduced to the JVM execution engine architecture (the heart and business-end of every JVM). That the authors leave the real introduction of the execution engine to the next chapter makes things confusing for the reader -- especially because the JVM is a stack-based architecture. (All mainstream processors are register-based, and only a few unconventional and specialized processors, like Inmos's Transputer or the processors behind Hewlett-Packard's RPN calculators, are stack-based in silicon).
"Components of the Machine" (Chapter 3) gives a 20-page overview of the JVM and related topics (Java's compilation model, data types, constant pools, runtime system). The execution engine is discussed only at the very end of this chapter, which I found a bit odd in light of the engine's fundamental role. In a similar vein, the JVM operand stack (the heart of the heart of the JVM, as it were) is the last subtopic to receive the spotlight, after method stack frames and registers. This is also the wrong order in which to cover topics because the JVM's operand stack is the architectural foundation that shaped many other important JVM components. Finally, still in Chapter 3, the sections on "Running Applets" and "Applets vs. Applications" were totally outside the legitimate scope for such a book.
Chapter 4, "Classes," deals too briefly with the JVM's multistage class loading mechanism, and spends most of the chapter explaining the class file format. Here the authors take a real-life class file (the canonical
HelloWorld class), produce a hex dump from it, and proceed to dissect this byte-by-byte. Chapter 5, "Security," focuses on the JVM class file verification stage. This section of the book is the only one that deals with its subject matter in more detail than does Venners's book.
The next chapter, "Implementation Notes," is very poor, content-wise. Its title suggests that the chapter will address would-be JVM implementors, but its content borders on the farcical in places. For example, the authors felt the need to explain the difference between little- and big-endian byte order, and, unbelievably, added, "In case you are unclear, the following simple program will print out the byte ordering used by the computer on which it is compiled and run." I doubt there exists a single systems programmer who would not have preferred some rather more realistic help, for example hints on which data structures to use for key JVM runtime areas, like the JVM's method area. Instead, the book's page real estate is squandered on kindergarten computer science stuff.