He already mentioned the Dragon Book which is a must.
I also understand that Appel's Modern Compiler Implementation series is popular but I have never read them myself. The C version looked a bit thin compared to the Dragon Book (but some may argue that one has too much detail).
That's about all the books I know on compilers. If you're interested in compilers, I would also recommend that you contact your local university or college. Many univerities work with tech companies to offer some form of training.
A book that is not really about compilers but that I have found really useful is the GOF book on Design Patterns. I cannot live without Visitor(331).
If you are interested in Java™ programming language compilers or the like, the puzzlers book by Joshua Bloch and Neal Gafter has a number of interesting comments for language designers.
I like books on general software engineering best practices and can especially recommend:
Finally, don't forget to read the mirror paper by Gilad Bracha and David Ungar.
The strange thing is that I haven't seen any comments from people that understands closures saying they don't like them. So this makes you think if closures is just a matter of understanding them or not.
This must be what Neal is thinking because he tries to answer the
question: what is the point of closures?
I would also recommend that you play a little with Smalltalk or Ruby.
I'm not allowing comments on this one as you can comment on my previous entry on closures or on Neal's blog.
If there is anything you would like to see in such a guide, please let me know within the next few days.
UPDATE: unfortunately, it only became clear to me very recently that I would have to write the guide and it was almost too late for JDK 6. I have added a minimal version that includes links to the manual pages and all the relevant API (this should make it easier to locate the Tree API docs). We hope to improve the guide in the coming month so it is ready for the first update release to JDK 6. The good news is that that gives us more time to incorporate your ideas and I have opened the comments again.
A closure is an anonymous function (aka lambda expression) in which all free variables can be accessed (even if they are not final). Furthermore, in the tradition of Smalltalk, the closure should be able to return directly from the method enclosing the closure definition (aka non-local return).
In the Java™ programming language, closures can be simulated to some extent with anonymous classes but these cannot access non-final local variables and have no way to exit the method containing the definition besides throwing an exception (which should not be used for control flow).
Closures have been a favorite of most Smalltalk freaks and has gotten renewed interest in languages such as Ruby.
Anonymous classes, although useful, can be a tad verbose and tiresome to type so this proposal must address the proper closure of free variables and non-local return as well as suggest a consice syntax.
The short answer is that HotSpot is not targeted to javac code but some static transformation can adversely affect the performance of your application. I'll give some more details below.
Damon also mentioned that there had been some fuss about a VM crash caused by some code generated by jikes. I know that all the HotSpot engineers treat VM crashes with utmost urgency and I checked with Ken Russell. Ken remembers one particular crash where jikes used the invokeinterface bytecode to call methods declared in java.lang.Object. This crash was treated with high priority and has since been fixed.
HotSpot is just a piece of software and may contain bugs but that does not mean javac is getting a better deal. However, there are certain factors which can play a role in how good a job HotSpot can do on your application.
Some of the industry benchmarks are based on the combination of compiler and JVM so if HotSpot seems biased towards javac, that may be the reason but not intentional.
On the other hand, many static optimizers will automatically inline method calls. The fundamental problem with inlining method calls is that if the inlined method was never called by method into which it was inlined it will just make the resulting method bigger (and perhaps prevent it from being inlined in other methods). So although a static optimizer think it is optimizing it has no data about how the program behaves at runtime and may make mistakes.
This is a fundamental problem that will make your programs run slower on HotSpot. The name HotSpot comes from the VM's ability to recognize hotspots in the program based on statistics collected while the program is running. By using this data, HotSpot can generally make better decisions than a static optimizer.
Besides hurting HotSpots ability to inline based on live data, big
methods resulting from premature inlining can have other negative
effects on performance. HotSpot will compile hot
methods
to native machine code. This code is sensitive to CPU level
optimizations such as code caches and branch prediction. I don't know
if this is a real life problem.
I checked with Ken and Ross Knippel to see if there could be other problems and they mentioned that obfuscators sometimes makes some very radical transformations of the control flow of your application. This can cause problems for HotSpots ability to detect loops and optimize them. A similar problem could occur if the compiler generated code that looked very different from what javac and similar compilers generate. However, in Mustang, HotSpot will apply a technique called loop rotation to properly place a loop exit that is testing an induction variable. Ross provided this example:
int i = 0;
while (true) {
stmt1;
i++;
if (i >= n) break;
stmt2;
}
is transformed into
int i = 0;
stmt1;
i++;
if (i < n) {
do {
stmt2;
stmt1;
i++;
} while (i < n)
}


Joe has posted about JSR 269 events on his blog. I may join him at his booth slot on Tuesday.
Indicates that a method declaration is intended to override a method declaration in a superclass. If a method is annotated with this annotation type but does not override a superclass method, compilers are required to generate an error message.
There are a few subtle points that may escape the casual reader:
There are a few surprising consequences of this:
abstract class C1 {
public abstract void m();
}
class C2 extends C1 {
@Override
public void m() {}
}
Although the method C2.m implements the method C1.m, it also overrides it. So this is OK according to the current specification and javac accepts it. The next example is even more convoluted:
public interface Test {
void m();
}
abstract class A implements Test {
// m() is inherited from Test
}
class B extends A {
@Override
public void m() {}
}
This is also legal since m is a member of the abstract class A, B.m is overriding (and implementing) a method in a superclass. However, javac fails to accept this program.
So thought about it and came up with this specification:
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but does not override a supertype method, compilers are required to generate an error message
However, this doesn't work as you would expect: although override and implements are not mutually exclusive, override is not a "superset" of implements:
interface A {
void m();
}
class B implements A {
public void m() {} // implements but doesn't override
}
Whereas:
interface A {
void m();
}
interface B extends A {
void m(); // overrides but doesn't implement
}
Confused? Then you're getting there ;-)
So we tried this one:
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but does not override or implement a supertype method, compilers are required to generate an error message
However, what about (currently accepted by javac):
interface Foo {
@Override
String toString();
}
So does Foo.toString override or implement a method in a supertype? Not really, the JLS is a bit convoluted here but basically says that although Object is a direct supertype of Foo, Foo does not inherit Object.toString because Foo itself declares a toString method...
Now what? We thought about it and came up with:
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but is not in fact override-equivalent to any method declared in a supertype, compilers are required to generate an error message.
So how is this different? Rather than relying on the definition of override or implements in the JLS we simply say what we intended to say all along: if a similar method exists in a supertype, then you may use @Override.
So then Eugene says: what about visibility. Oh boy:
Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type compilers are required to generate an error message unless either the method is override-equivalent to a [update: public or protected] method in Object, or the method does override or implement a method declared in a supertype.
I hope to have this ready for b86.
This should demonstrate the value of writing tests for even the most trivial of changes. Did somebody recently mention something about testing...? ;-)
Imagine writing s StarOffice macro in Java
6341023: (javac) Tree API: Tree.Kind should have mapping to interface
6341177: (JSR 269) Add IDE toolability API to JSR 269
6402506: (JSR 269) Add ProcessingEnvironment.getSourceVersion
6403466: (javac) javac TaskListener should be informed when annotation processing occurs
6406212: (JSR 269) Syntax of options should be better verified
6406771: (javac) Tree API clients need access to the compiler's line number table
6407257: (javac) javac locks up when encountering cyclic inheritance
Thanks to Joe, Jon, and Wei.
Also, the JDK will be build using -target 5 from now on. Previously, we shipped with -target 6 to allow thorough testing of the new verifier. However, we always planned to ship with -target 5 in Mustang RC. The reason for this is very simple: we want people to upgrade to Mustang as soon as possible. One problem we identified in JDK 5.0 was that customers running any kind of app server will run into a problem if the app server has a built-in compiler that doesn't understand the new class file format. Fortunately, there is a very simple solution to this for Mustang: use the old class file format.
6340951: (javac) Tree API: some literals are identifiers
6365980: (JSR 269) FilerException(null) doesn't throw NPE
6395981: (javac) JSR 199: JavaCompilerTool and Tool must specify version of JLS and JVMS
6395983: (javac) JSR 199: improve documentation of JavaCompilerTool
6396397: (javac) JSR 199: JavaFileManager should extend Flushable
6397044: (javac) JCModifiers.getModifiers() returns incorrect Modifiers set.
6397097: (javac) JSR 199: JavaCompilerTool.CompilationTask is clumsy with respect to "delayed"
6397104: (javac) JSR 199: JavaFileManager.getFileForOutput should have sibling argument
6397286: (javac) TaskListener calls are not protected agains user exceptions
6397348: (javac) JSR 199: supported options
6399894: (javac) JSR 199: WrapperJavaFileObject should extend new class WrapperFileObject
6400204: (javac) JSR 199: StandardJavaFileManager.getJavaObjectsFrom* should throw exception if argument is directory
6400205: (javac) JSR 199: getClassLoader(location) returns null if getLocation(location) returns null
6400207: (javac) JSR 199: JavaFileManager.list and unset location
6400208: (javac) JSR 199: failure mode for inferBinaryName
6400225: (javac) JSR 199: StandardJavaFileManager.getEffectiveLocation
6400267: (javac) JSR 199: specify the exact requirements for relative URIs
6401107: (javac) JSR 199: all methods must return non-null values unless explicitly allowed
6401277: (javac) JSR 199: javax.tools.ToolProvider.getSystemToolClassLoader throws UnsupportedOperationException
6401906: (javac) JSR 199: rename Wrapper* to Forwarding*
6401994: (javac) JSR 199: JavaCompilerTool.CompilationTask.run should not copy Runnable spec
6406164: (JSR 269) ElementKindIterator.hasNext() throws NPE when ElementFilter Iterable methods are used.
6407066: (javac) Paths code should not discard non-existent directories
6410184: (javac) JSR 199: javax.Tools.WrapperJavaFileManager and WrapperJavaFileObject are not reflexive
6410297: (javac) JSR 199: javax.tools.SimpleJavaFileObject.isNameCompatible doesn't work or has wrong spec
6410653: (javac) REGRESSION: javac crashes if -d or -s argument is a file
6411327: (JSR 269) Some typeUtils methods can result in an IllegalArgumentException and this is not documented.
Thanks to Joe, Jon, and Scott.
6345812: (JSR 269) annotation processing breaks with assertion, in Types.isAssignable() method.
6370653: (javac) javac does not use iinc opcode for postfix decrement of local variable
6376083: (JSR 269) should check annotation processor for compatability with specified source version
6376084: (JSR 269) Annotation processor infrastructure should check for unsupported options
6391649: (JSR 269) javax.lang.model.util.Elements.getAllMembers() does not return initializers
6392818: (JSR 269) Add isDeprecated to javax.lang.model.util.Elements
6397298: (JSR 269) RoundEnvironment.getElementsAnnotatedWith(anno) returns null, no empty set
6400986: (JSR 269) RoundEnvironment.getElementsAnnotatedWith() misses some elements
6401264: (JSR 269) Link Character.isIdentifier{Start, Part} to javax.lang.model.SourceVersion.isIdentifier
6407011: (javac) javac crashes in b78 with NPE in DefaultFileManager:293
Thanks to Wei, Scott, Joe, and java.net contributor dmytro_sheyko.
A very special thanks to Tim for doing an extra integration that allowed me to fix 6407011 in less than a week.
Earlier today Xiomara discovered a nasty problem with Windows and mixed case filenames. We had to rewrite the part of javac that handles files because of an upcoming revision to JSR 199. Good news: we caught the problem before the bits were pushed to java.net. Bad news: we didn't catch it soon enough so we had to back it out in the last minute.
If we're lucky, the changes we had planned for b77 will make it to b78.
Regardless, I'll keep posting what we are putting into the various builds as soon as we have completed our part of the release cycle. I think it provides an interesting view into our daily work.
I can't wait for NetBeans 6.0 to go beta...
5024091: (javac) (crash) AssertionError when StringBuilder is used with cldc.jar as bootclasspath
6236704: (javac) bad jar files ignored in extension and endorsed dirs
6295519: (javac) javac throws ZipException when you have invalid files in classpath
6306967: (javac) This code compiles but gives VerifyError when run
6327885: (javac) JSR 199: open issues
6346249: (javac) javac Tree API missing functionality
6346453: (JSR 269) Types.directSupertypes implementation returns an invalid list.
6346506: (JSR 269) Elements.getTypeElement(String s) will throw NPE for a unknown class.
6346973: (JSR 269) directSupertypes(Mirror m) causes java.lang.StackOverflowError
6348193: (javac) AS8.1 UR2 BAT test failure with "javac"
6350057: (JSR 269) visitVariableAsLocalVariable is called on enum's parameter of valueOf(String name)
6358024: (javac) TaskListener should be propagated between processing rounds
6358166: (JSR 269) -verbose reports absurd times when annotation processing involved
6361619: (javac) AssertionError from ClassReader
6366196: (javac) regression in CharacterRangeTable format
6392058: (javac) rename internal class Diagnostic to JCDiagnostic
6392118: (javac) mismatch between JavacTaskImpl.context and JSR 269
6394563: (javac) REGRESSION: javac ignores -nowarn switch in 1.5.0_06 for deprecation warnings
6395269: (javac) Paths should use List<File> or List<URI> instead of List<String> to represent a path
6395974: (javac) files are parsed even after failure to find annotation processor is reported
Thanks to Joe, Jon, Neal, Nishant, Scott, and Wei. Especially a big thank you to Jon for helping me getting JSR 199 ready for b77. We pulled some later hours on that one... Unfortunately, this left the wildcard bug I mentioned two weeks ago unfixed.
For those of you using jcov, send happy thoughts to Wei for fixing the javac regressions that broke jcov.
So while this is good style:
/** * ... * @throws java.lang.RuntimeException if an unrecoverable error * occurred in a user supplied component. The cause will be the * error in user code. */
This is not:
void run() throws RuntimeException;
So how can I reliably find all unchecked exceptions? Very easily if I use an annotation processor. I used this annotation processor:
@SupportedAnnotationTypes("*") @SupportedOptions("summary") public class FindRuntimeException extends AbstractProcessor { // For summary of unchecked exceptions used in throws clauses final Set<TypeMirror> uncheckedExceptions = new LinkedHashSet<TypeMirror>(); public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) { // Get various utility classes final Elements elements = processingEnv.getElementUtils(); final Types types = processingEnv.getTypeUtils(); final Messager log = processingEnv.getMessager(); // Get the types (type mirrors) of RuntimeException and Error final TypeMirror runtimeException = elements.getTypeElement("java.lang.RuntimeException").asType(); final TypeMirror error = elements.getTypeElement("java.lang.Error").asType(); // Scanner for traversing the structure of a class, interface, etc. ElementScanner6<Void,Void> scan = new ElementScanner6<Void,Void>() { @Override public Void visitExecutable(ExecutableElement e, Void p) { // Executable means method or constructor, this method is called for // every method or constructor. So we just have to look at the throws // declaration... for (TypeMirror t :e.getThrownTypes()) // ...and see if any of the thrown types are subtypes of // RuntimeException or Error. if (types.isSubtype(t, runtimeException) || types.isSubtype(t, error)) { uncheckedExceptions.add(t); // print a warning so you can use your favorite editor to jump // to the problematic method log.printMessage(WARNING, "Throwing unchecked exception " + t, e); } return null; } }; // examine all the classes provided on the command line for (TypeElement e : roundEnvironment.getSpecifiedTypeElements()) scan.scan(e); // print a summary of found unchecked exceptions if (roundEnvironment.processingOver() && processingEnv.getOptions().containsKey("summary")) { System.out.println("Summary of unchecked exceptions found in throws clauses:"); for (TypeMirror t : uncheckedExceptions) System.out.println("\t" + t); } return true; } }
UPDATE: I have updated the code with comments and colors (using htmlize.el by Hrvoje Niksic)
Then I compiled the annotation processor:
javac -classpath /usr/java/jdk1.6.0/lib/tools.jar FindRuntimeException.java
You need a fairly recent Mustang snapshot to compile this. Also, from b74 (Thanks Kelly!), you won't have to put tools.jar on the classpath anymore. Then run the annotation processor:
javac -Asummary -proc:only -processor FindRuntimeException src/share/classes/javax/tools/*.java
Enjoy...