
I have from time to time been working on a automatic CPU feature tuning code for Shark to make the LLVM JIT generate better code for Cortex-A8 class ARM CPUs. Using it i was able to gain some substantial speed-improvements, all in all it made Shark generate 30% faster code on ARM and the Shark JIT are now able to beat the 2000 point CaffeineMark 3.0 score! I could not resist using CaffeineMark 3.0 for some benchmarking again
.
While this looks all great with rainbows and unicorns the patch are sadly in limbo. I have had some trouble merging the code into LLVM 2.7 trunk before the next LLVM release since I got hit by LLVM problem report 6544 that will force me to redesign the implementation on top of LLVM before it can be commited.
And a similar optimisation like what i did for ARM Linux can easily be done for Shark on PPC Linux as well by adopting the ARM CPU features detection code from ARM to PPC!
For those who are interested the optimising code are submitted and can be fetched from LLVM PR5389.
Cheers and have a great day!
Xerxes
int main(void)
{
void testMe(void)
{
fprintf(stderr, "b0rk3d!\n");
}
testMe();
return (EXIT_SUCCESS);
}
without optimisations, gcc creates a regular function call, with optimisation I guess it depends on how often you use it, but this simple test gets (unsurprisingly, I guess) inlined.
Very cool :)Now we come to the first peak in The Beatles’ career: their 3rd album A Hard Day’s Night. Somewhere I’ve read that this album sounds like somebody opened a bottle of champaign, and this hits the nail on its head. Where the last album With The Beatles was slightly dark, this here is all bright, hyperactive and full of adrenaline. It starts with the weird opening chord (which puzzled even scientists because nobody was able to find out exactly what chord it was until 2008) of the title song, and runs through a set of 13 Beatles originals (yeah right, no cover versions this time). It shows all the good qualities of the early Beatles, their incredible vocal harmonies, their simple-yet-intriguing melodies and rhythms. And it shows the incredible fun and energy that the guys had.
I remember a fun little story. When I was young (much younger than now at least), I saved myself a lot of money (around 30 DM, approx. 15€ nowadays) to buy this album on CD. That must have been in 1992 or so, I was about 14. I didn’t even have a CD player! So I went to the closest supermarket, gave away my hard-earned money to get this CD. And when I was home and saw ‘Mono’ on the package, I was so disappointed, because I believed that this was a fake thing. In my childish view I assumed that the real thing must be stereo because stereo is obviously better, no? In the end, I went back to the supermarket and returned the CD (that was quite a funny and geeky argument with the salesguy, not wanting the CD because it’s mono). But not without first going to a friend and making a copy of it to cassette tape. Yay
Only much later I realized that the mono version was indeed the official version and bought the CD again. Now I have both, and comparing the versions I must say that the mono version is indeed better, again there are a bunch of glitches on stereo (the start of ‘Should Have Known Better’ for example) that have been corrected in mono. It needs to be said that at this time mono was by far the dominant format and the Beatles themselves never really cared for the stereo mixes, leaving them to others, while attending the mono mixes themselves. However, compared to the first two albums, which have this funny extreme left-right panning, the stereo mixes are a bit more sane, which owes to the fact that they used 4 track recording for the first time.
That was a bit technical this time, I usually try to avoid that because we want to listen to music, not technology, right? I enjoyed listening to this album today anyway. Quite alot even. Next time I will have a look (listen) at the Beatles for Sale.
rkennkeWe are pleased to announce the release of IcedTea6 1.7.1!
The IcedTea project provides a harness to build the source code from
OpenJDK6 using Free Software build tools. It also includes the only
Free Java plugin and Web Start implementation, and support for
additional architectures over and above x86, x86_64 and SPARC via the
Zero assembler port.
The tarball can be downloaded from:
The following people helped with the 1.7 release series:
Lillian Angel, Gary Benson, Deepak Bhole, Andrew Haley, Andrew John Hughes, Nobuhiro Iwamatsu, Matthias Klose, Martin Matejovic, Edward Nevill, Xerxes Rånby, Robert Schuster,Jon VanAlten, Mark Wielaard and Man Lung Wong.
We would also like to thank the bug reporters and testers!
To get started:
$ tar xzf icedtea6-1.7.1.tar.gz $ cd icedtea6-1.7.1
Full build requirements and instructions are in INSTALL:
$ ./configure [--enable-visualvm --with-openjdk --enable-pulse-java --enable-systemtap ...] $ make
Moving on from identity and equality of objects, different notions of equality are also surprisingly subtle in some numerical realms.
As comes up from time to time and is often surprising, the "==" operator defined by IEEE 754 and used by Java for comparing floating-point values
(JLSv3 §15.21.1)
is not an equivalence relation. Equivalence relations satisfy three properties, reflexivity (something is equivalent to itself), symmetry (if a is equivalent to b, b is equivalent to a), and transitivity (if a is equivalent to b and b is equivalent to c, then a is equivalent to c).
The IEEE 754 standard defines four possible mutually exclusive ordering relations between floating-point values:
equal
greater than
less than
unordered
A NaN (Not a Number) is unordered with respective to every floating-point value,
including itself. This was done so that NaNs would not quietly slip by without due notice. Since (NaN == NaN) is false, the IEEE 754 "==" relation is not an equivalence relation since it is not reflexive.
An equivalence relation partitions a set into equivalence classes; each member of an equivalence classes is "the same" as the other members of the classes for the purposes of that equivalence relation. In terms of numerics, one would expect equivalent values to result in equivalent numerical results in all cases. Therefore, the size of the equivalence classes over floating-point values would be expected to be one; a number would only be equivalent to itself. However, in IEEE 754 there are two zeros, -0.0 and +0.0, and they compare as equal under ==. For IEEE 754 addition and subtraction, the sign of a zero argument can at most affect the sign of a zero result. That is, if the sum or difference is not zero, a zero of either sign doesn't change the result. If the sum or differnece is zero and one of the arguments is zero, the other argument must be zero too:
-0.0 + -0.0 ⇒ -0.0
-0.0 + +0.0 ⇒ +0.0
+0.0 + -0.0 ⇒ +0.0
+0.0 + +0.0 ⇒ +0.0
Therefore, under addition and subtraction, both signed zeros are equivalent. However, they are not equivalent under division since 1.0/-0.0 ⇒ -∞ but 1.0/+0.0 ⇒ +∞ and -∞ and +∞ are not equivalent.1
Despite the rationales for the IEEE 754 specification to not define == as an equivalence relation, there are legitimate cases where one needs a true equivalence relation over floating-point values, such as when writing test programs, and cases where one needs a total ordering, such as when sorting. In my numerical tests I use a method
that returns true for two floating-point values x and y if:
((x == y) &&
(if x and y are both zero they have the same sign)) ||
(x and y are both NaN)
Conveniently, this is just computed by using (Double.compare(x, y) == 0). For sorting or a total order, the semantics of Double.compare are fine; NaN is treated as being the largest floating-point values, greater than positive infinity, and -0.0 +0.0. That ordering is the total order used by by java.util.Arrays.sort(double[]). In terms of semantics, it doesn't really matter where the NaNs are ordered with respect to ther values to as long as they are consistently ordered that way.2
These subtleties of floating-point comparison were also germane on the Project Coin mailing list last year; the definition of floating-point equality was discussed in relation to adding support for relational operations based on a type implementing the Comparable interface. That thread also broached the complexities involved in comparing BigDecimal
The BigDecimal class has a natural ordering that is inconsistent with equals; that is for at least some inputs bd1 and bd2,
c.compare(bd1, bd2)==0
has a different boolean value than
bd1.equals(bd2).3
In BigDecimal, the same numerical value can have multiple representations, such as (100 × 100) versus (10 × 101) versus (1 × 102). These are all "the same" numerically (compareTo == 0) but are not equals with each other. Such values are not equivalent under the operations supported by BigDecimal; for example (100 × 100) has a scale of 0 while (1 × 102) has a scale of -2.4
While subtle, the different notions of numerical equality each serve a useful purpose and knowing which notion is appropriate for a given task is an important factor in writing correct programs.
1 There are two zeros in IEEE 754 because there are two infinities. Another way to extend the real numbers to include infinity is to have a single (unsigned) projective infinity. In such a system, there is only one conceptual zero. Early x87 chips before IEEE 754 was standardized had support for both signed (affine) and projective infinities. Each style of infinity is more convenient for some kinds of computations.
2 Besides the equivalence relation offered by
Double.compare(x, y), another equivalence relation can be induced by either of the bitwise conversion routines, Double.doubleToLongBits or Double.doubleToRawLongBits. The former collapses all bit patterns that encode a NaN value into a single canonical NaN bit pattern, while the latter can let through a platform-specific NaN value. Implementation freedoms allowed by the original IEEE 754 standard have allowed different processor families to define different conventions for NaN bit patterns.3 I've at times considered whether it would be worthwhile to include an "
@NaturalOrderingInconsistentWithEquals" annotation in the platform to flag the classes that have this quirk. Such an annotation could be used by various checkers to find potentially problematic uses of such classes in sets and maps.4 Building on wording developed for the
BigDecimalspecification under JSR 13, when I was editor of the IEEE 754 revision, I introduced several pieces of decimal-related terminology into the draft. Those terms include preferred exponent, analogous to the preferred scale fromBigDecimal, and cohort, "The set of all floating-point representations that represent a given floating-point number in a given floating-point format." Put in terms ofBigDecimal, the members of a cohort would be all theBigDecimalnumbers with the same numerical value, but distinct pairs of scale (negation of the exponent) and unscaled value.
During the past months i have seen some really cool stuff done using small powerefficient ARM computers and OpenJDK.

Simple Simon PT connected to a hospital laboratory system by using a powerefficient plugcomputer and displaylink usb screen. All powered by OpenJDK
Simple Simon PT connects:
This project hooks up a battery powered laboratory coagulation device, a Simple Simon PT reader to standard hospital laboratory system using a ASTM-1394-1397 / LIS2-A2 connectivity over ethernet. A small ARM based plugcomputer does all data message processing and communication. User interraction are performed by using the Simon reader and a usb-barcode reader to enter laboratory identification. Optionally can a usb-touch-screen be connected for improved user feedback, by displaying charts using JFreeChart, to show and give a better understanding of the coagulation process.
Powerconsumption tops at 15W with the USB screen attached and 6W without. All running silent without any moving parts!
Shark linked against dynamic LLVM .so library
Earlier today I got Shark linked against a shared libLLVM-2.7svn.so generated by using LLVM 2.7svn trunk. It work by simply building LLVM using configure –enable-shared –enable-optimized –disable-assertions and then tweak the Icedtea6 main Makefiles to use the shared library during liking:
Replace the line
LLVM_LIBS = -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMMCParser -lLLVMX86AsmPrinter -lLLVMX86CodeGen -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMX86Info -lLLVMJIT -lLLVMExecutionEngine -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMTarget -lLLVMMC -lLLVMCore -lLLVMSupport -lLLVMSystem
with
LLVM_LIBS = -lLLVM-2.7svn
in the main icedtea6/Makefile and then build Icedtea6 normally, Shark currently builds and works right out of the box when using a LLVM release build!
A cool thing by building shark against the shared library are that you can switch the LLVM JIT that Shark uses from running with or without assertions, debug code, and various extra optimizations by simply replacing the /usr/local/lib/libLLVM-2.7svn.so file with what you want. Linking time during shark builds and shark footprint are impressively smaller as well. Im really happy to see this functionallity in LLVM 2.7!
The LLVM 2.7 code freeze before the 2.7 release happens in about 1.5 weeks from now and i will stay busy for some days to observe and polish the current LLVM svn trunk to be usable with openjdk-6-shark.
Edward Nevill created a ARM Jazelle RTC Thumb2 JIT reference implementation
Meanwhile I have been busy taming Sharks a new kind of Thumb2 JIT have emerged built by Edward Nevill of Cambridge Software Labs! The new Tumb2JIT have been committed into the Icedtea6 trunk and it are a working implementation of Jazelle RTC to be used by ARM Cortex-A8+ class CPUs. It wonderfull that this have been released as free software, Wow!,
Suddenly we got three different JITs to use on ARM with OpenJDK: Cacao, Shark and T2. An opurtunity has emerged to tier them and so I did. Here comes the raw “truth” produced by Caffeine Mark 3! This will probably be the last time i will show off any Caffeine Mark 3 benchmark since it really dont give justice on real world client applications where responsiveness are more crucial than top runtime speed, nevertheless benchmarking using CM30 have always felt fun so here we go: All benchmarks running using a Sharp PC-Z1 Cortex-A8 Mobile internet tool.

Tier between Edwards Thumb 2 JIT , Shark LLVM JIT and Cacao JIT: All running on a ARM Sharp PC-Z1 Mobile internet tool smartbook using OpenJDK 6 compiled with Icedtea6.
This new T2 JIT’s main strenght are reduced jitting time, it basically cuts all jtting time to almost zero and client applications on ARM finnaly runs from tick one. This thumb2 jit makes a really nice java applet browser experience with about 15 seconds first applet startuptime on a ARM smartbook and and all usable instantly after being loaded.
A small 1min 12seconds .3gp movie displaying some java applets running on the Sharp PC-Z1 featuring the new thumb2jit from Icedtea6
Cheers and have a great day!
Xerxes
Today I successfully executed an invokedynamic call on SPARC for the first time. Excellent!
$ bin/jruby.gamma -J-XX:+UseSerialGC -J-Djruby.compile.invokedynamic=true -J-Xint -J-XX:+UnlockExperimentalVMOptions -J-XX:+EnableMethodHandles -J-XX:+EnableInvokeDynamic bench/bench_fib_recursive.rb OpenJDK Server VM (17.0-b08-internal-jvmg) for solaris-sparc JRE (1.7.0), built on Feb 25 2010 04:35:47 by "ct232829" with Workshop 5.9 VM option '+UseSerialGC' VM option '+UnlockExperimentalVMOptions' VM option '+EnableMethodHandles' VM option '+EnableInvokeDynamic' 52.813000 0.000000 52.813000 ( 52.296000) 52.824000 0.000000 52.824000 ( 52.823000) 51.808000 0.000000 51.808000 ( 51.808000) 49.740000 0.000000 49.740000 ( 49.740000) 49.450000 0.000000 49.450000 ( 49.450000)
MethodHandle calls already work since a couple of days and I can run the JDK MethodHandlesTest without any errors:
$ gamma -Xinternalversion OpenJDK Server VM (17.0-b08-internal-jvmg) for solaris-sparc JRE (1.7.0), built on Feb 25 2010 04:35:47 by "ct232829" with Workshop 5.9 $ gamma -Xint -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -classpath /java/devtools/share/junit/latest/junit.jar:. org.junit.runner.JUnitCore MethodHandlesTestVM option '+UnlockExperimentalVMOptions' VM option '+EnableMethodHandles' JUnit version 4.4 OpenJDK Server VM warning: JSR 292 invokedynamic is disabled in this JVM. Use -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic to enable. .IIIIII.findStatic :::::::::::.findVirtual :::::::::::::::.findSpecial ::.bind ::::::::::::::::::::::.unreflect ::::::::::::::::::::::::I.unreflectGetter .unreflectSetter .arrayElementGetter .arrayElementSetter .convertArguments ::::::.permuteArguments .spreadArguments .collectArguments .insertArguments .filterArguments .foldArguments .dropArguments .exactInvoker, genericInvoker, varargsInvoker, dynamicInvoker .guardWithTest .catchException .throwException .testCastFailure Time: 7.984 OK (23 tests)
JSR 292 SPARC support is on its way...
Let’s continue the Beatles reviews that I started with Please Please Me with their next album: With The Beatles.
I remember quite well when I first listened this album for the first time. It is one of those albums that immediately bring up the mood, smell and details of that particular situation and time in my life. I was about 11 years old (I guess) and visiting my father. He had a czech print of this album, and I listened it over his great headphone. Of course I copied it to cassette (at this point cassette and reel tape was the only source of music for me, no thinking of CDs yet). I listened it over and over again in my walkman and couldn’t get enough of it. The weird hard-panned stereo mix allowed for fun experiments: if you only listen to one channel, you get voices and drums (for example) and on the other channel guitars and base, etc. Quite fun. I was a bit disappointed when I bought the CD later that it was only available in mono – now I understand that the mono version is infact much better overall. Like with the first album (and the next albums as well), the stereo mixes have some glitches that were corrected in mono (listen the start of ‘Roll Over Beethoven’ as an example). The album blasts off with ‘It Won’t Be Long’ (doing the Yeah shouting that they became famous for with their single She Loves You – which did not end up on the album) and keeps the energy until the last note of ‘Money’. Compared to their first album it is slightly more complex, they added a piano (and a rumbling piano that is) and refined their sound. Where the first album was sort of a generic beat music thing, this album is definitely Beatles (in full swing of Beatlemania). They also deliver the same basic ingredients that were also present on the first album: love songs, rockers, exotic stuff, cover versions, some George and some Ringo. My favorite is probably the last song ‘Money (that’s what I want)’ (money seems to be a recurring theme in their career, as if they had too little: ‘Can’t Buy Me Love’, ‘Taxman’, ‘Baby You’re a Rich Man’ and finally ‘You Never Give Me Your Money’ and probably some others that I forgot). The cover of the album is also notable: instead of the happy-go-lucky photographs that was to be expected, it shows an arty black and white photo with the four in black polo neck pullovers. To me this is one of my favorite album covers of the Beatles. I really enjoyed listening this album today, it’s a good album for foggy days, but apparently it also works for sunny spring days like today
Please let me know how do you like the album in the comments below, and stay tuned for the next album A Hard Day’s Night.
rkennke
When designing types to be reused by others, there are reasons to favor interfaces over abstract classes.
One complication of using an interface-based approach stems from defining reasonable behavior for the equals and hashCode methods, especially if different implementations are intended to play well together when used in data structures like collections, in particular if an interface type is meant to serve as the key of a map or as the element type of a set.
Some interfaces, like CharSequence, are designed to not be a usable type for a map key or an element type of a set:
[The
CharSequence] interface does not refine the general contracts of theequalsandhashCodemethods. The result of comparing two objects that implementCharSequenceis therefore, in general, undefined. Each object may be implemented by a different class, and there is no guarantee that each class will be capable of testing its instances for equality with those of the other. It is therefore inappropriate to use arbitraryCharSequenceinstances as elements in a set or as keys in a map.
Amongst other problems, CharSequences are not required to be immutable so in general there are always hazards from time of check to time of use conditions.
Even if a type is not suitable as a map key, it can be fine as the type of the value to which a key gets mapped. Likewise, even if type cannot serve as the element type of a set, it can often still be perfectly fine as the element type of a list.
Expanding on a slide from my JavaOne talk
Tips and Tricks for Using Language Features in API Design and Implementation, for interface types intended to be used as map keys or set elements, equality can be defined in several ways.
First, equality can be defined solely in terms of information retrievable from methods of the interface. Alternatively, equality can be defined in terms of information retrievable via the interface methods as well as additional information. Finally, object identity (the == relation) is always a valid definition for equals and often a good implementation choice.
An example of the first kind of equality definition is specified for annotation types:
java.lang.annotation.Annotation.equals(Object):
Returns true if the specified object represents an annotation that is logically equivalent to this one. In other words, returns true if the specified object is an instance of the same annotation type as this instance, all of whose members are equal to the corresponding member of this annotation, as defined below: ...
java.lang.annotation.Annotation.hashCode():
Returns the hash code of this annotation, as defined below:
The hash code of an annotation is the sum of the hash codes of its members (including those with default values), as defined below:...
A consequence of defining equality in this manner is that the hashCode algorithm must also be specified. If it were not specified, the equals/hashCode contract would be violated since equal objects must have equal hashCodes. Therefore, different implementations of this style of interface must have enough information to implement the equals method and have a precise algorithm for hashCode.
An annotation type is a kind of interface. At runtime, dynamic proxies are used to create the core reflection objects implementing annotation types, such as the objects returned by the
getAnnotation method. After a quick identity check, the equals algorithm used in the proxy sees if the annotation type of the two annotation objects is the same and then compares the results of the annotation type's methods. This indirection allows the annotation objects from core reflection to interact properly with other implementations of annotation objects. The annotation objects generated for annotation processing in apt and javac both use the same underlying implementation as core reflection. However, completely independent annotation implementations are fine too. For example, the code below
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
/**
* Demonstrate equality of different annotation implementations.
*/
@SupportedSourceVersion(SourceVersion.RELEASE_6)
public class AnnotationEqualityDemonstration {
static class MySupportedSourceVersion implements SupportedSourceVersion {
private final SourceVersion sourceVersion;
private MySupportedSourceVersion(SourceVersion sourceVersion) {
this.sourceVersion = sourceVersion;
}
public Class annotationType() {
return SupportedSourceVersion.class;
}
public SourceVersion value() {
return sourceVersion;
}
public boolean equals(Object o) {
if (o instanceof SupportedSourceVersion) {
SupportedSourceVersion ssv = (SupportedSourceVersion) o;
return ssv.value() == sourceVersion;
}
return false;
}
public int hashCode() {
return (127 * "value".hashCode()) ^ sourceVersion.hashCode();
}
}
public static void main(String... args) {
SupportedSourceVersion reflectSSV =
AnnotationEqualityDemonstration.class.getAnnotation(SupportedSourceVersion.class);
SupportedSourceVersion localSSV =
new MySupportedSourceVersion(reflectSSV.value());
System.out.println("reflectSSV == localSSV is " +
(reflectSSV == localSSV));
System.out.println("reflectSSV.equals(localSSV) is " +
reflectSSV.equals(localSSV));
System.out.println("localSSV.equals(reflectSSV) is " +
localSSV.equals(reflectSSV));
System.out.println("reflectSSV.getClass()equals(localSSV.getClass()) is " +
reflectSSV.getClass().equals(localSSV.getClass()));
System.out.println("\nreflectSSV.hashCode() is " +
reflectSSV.hashCode());
System.out.println("localSSV.hashCode() is " +
localSSV.hashCode());
}
}
when run outputs:
reflectSSV == localSSV is false reflectSSV.equals(localSSV) is true localSSV.equals(reflectSSV) is true reflectSSV.getClass()equals(localSSV.getClass()) is false reflectSSV.hashCode() is 1867635603 localSSV.hashCode() is 1867635603
The second kind of equality definition is specified for the language modeling interfaces in the javax.lang.model.element package:
javax.lang.model.element.Element.equals(Object):
Note that the identity of an element involves implicit state not directly accessible from the element's methods, including state about the presence of unrelated types. Element objects created by different implementations of these interfaces should not be expected to be equal even if "the same" element is being modeled; this is analogous to the inequality ofClassobjects for the same class file loaded through different class loaders.
Inside javac, instance control is used for the implementation classes for javax.lang.model.element.Element subtypes. This allows the default pointer equality to be used and allows the hashing algorithm to not be specified. Just as you can't step in the same river twice, the identity of an Element object is tied to the context in which it is created. Operationally, one consequence of this context sensitivity is that Element objects modeling "the same" type produced during different rounds of annotation processing will not be equal even if there are equivalent methods, fields, constructors, etc. in both types in both rounds.
When independent implementations of an interface and not required to be equal to one another, the hashCode algorithm does not need to be specified, providing the implementer more flexibility. This second style of specification allows disjoint islands of implementations to be defined.
Which style of specification is more appropriate depends on how the interface type is intended to be used. Defining interoperable implementation is more difficult and limits the ability of the interface to be retrofitted onto existing types. For example, while the Element interface and other interfaces from JSR 269 were successfully implemented by classes in both javac and Eclipse, it would be impractical to expect Element objects from those disparate implementations to compare as equal.
Mixin interfaces, like CharSequence and Closeable, should be cautious in defining equals behavior if the interface is intended to be widely implemented. In some cases, a mixin interface can finesse this issue by being limited to an existing type hierarchy with already defined equals and hashCode polices. For example, the Parameterizable and QualifiedNameable interfaces added to the javax.lang.model.element package in JDK 7
(6460529)
are extensions to javax.lang.model.Element and therefore get to reuse the existing policies quoted above.
At the end of last year, EMI/Apple re-released the whole Beatles catalogue as a series (or box sets) of remastered CDs. The Beatles were more or less my first encounter with pop music when I was 8 or so, my first self-bought CD at the age of 12 was a Beatles CD and of course, I had to go out and buy these excellent remasters, I got both the mono and stereo editions. I had many weeks now listening these CDs and re-discovering some of the stuff was quite fun, and I want to share my impressions in a short series of short reviews intermingled with some personal anecdotes. Let’s do it in order of the release of the original LPs and start with ‘Please Please Me‘.
I think this is quite a good career starter. Innocent, powerful, inspired, raw, rocking. It has most of the ingredients of their later Beatlemania success albums, i.e. love songs (P.S. I love you and most others), rockers (I Saw Her Standing There,…), some cover versions , a slightly more exotic song (A Taste of Honey), some Ringo (Boys), some George (Do You Want To Know a Secret), a weird sense of humor (the Beatles covering a girl group talking about ‘Boys’). I really always enjoy this album. It was recorded in one day, and with John having a sore throat, and it shows – positively. From the first through the last song you can literally feel the energy of those 4 relatively unknown guys, and sense that the Beatlemania is already about to start. It is what the Beatles were at this point: a hard working live band. Interesting the last song: a kamikaze version of Twist and Shout, with John shredding his vocal chords. Hilarious. It could have been a total fail (with no second chance to record it), but instead it became music history. The stereo version is mostly relevant for historical reasons, the sound beeing a bit thin and the mixes having several glitches which were corrected in the mono mixes. These mono mixes on the other hand are just great and solid rocking. All in all the album always makes for a happy-go-lucky listen on sunny afternoons, even if it is not one of the totally essential ones. Also interesting to note is also the album cover: it shows the four guys on the stairs in the EMI building. Several years later they did the exact same scene again, now with long hair, for the planned last album (Get Back, which should become Let it Be). Both pictures would later be used for the red and blue best of double albums.
Next one up will be With The Beatles. Stay tuned. Please tell me what you think about the album in the comments.
rkennkeCatching up on writing about more numerical work from years past, the second article in a two-part series finished last year discusses some low-level floating-point manipulations methods I added to the platform over the course of JDKs 5 and 6. Previously, I published a blog entry reacting to the first part of the series.
JDK 6 enjoyed several numerics-related library changes. Constants for MIN_NORMAL, MIN_EXPONENT, and MAX_EXPONENT were added to the Float and Double classes. I also added to the Math and StrictMath classes the following methods for low-level manipulation of floating-point values:
public static double copySign(double magnitude, double sign)
public static int getExponent(double d)
public static double nextAfter(double start, double direction)
public static double nextUp(double d)
public static double scalb(double d, int scaleFactor)
There are also overloaded methods for float arguments.
In terms of the IEEE 754 standard from 1985, the methods above provide the core functionality of the recommended functions. In terms of the 2008 revision to IEEE 754, analogous functions are integrated throughout different sections of the document.
While a student at Berkeley, I wrote a tech report on algorithms I developed for an earlier implementation of these methods, an implementation written many years ago when I was a summer intern at Sun. The implementation of the recommended functions in the JDK is a refinement of the earlier work, a refinement that simplified code, added extensive and effective unit tests, and sported better performance in some cases. In part the simplifications came from not attempting to accommodate IEEE 754 features not natively supported in the Java platform, in particular rounding modes and sticky flags.
The primary purpose of these methods is to assist in in the development of math libraries in Java, such as the recent
pure Java implementation of floor and ceil
(6908131).
This expected use-case drove certain API differences with the functions sketched by IEEE 754. For example, the getExponent method simply returns the unbiased value stored in the exponent field of a floating-point value rather than doing additional processing, such as computing the exponent needed to normalized a subnormal number, additional processing called for in some flavors of the 754 logb operation. Such additional functionality can actually slow down math libraries since libraries may not benefit from the additional filtering and may actually have to undo it.
The Math and StrictMath specifications of copySign have a small difference: the
StrictMath version always treats NaNs as having a positive sign (a sign bit of zero) while the
Math version does not impose this requirement.
The IEEE standard does not ascribe a meaning to the sign bit of a NaN and difference processors have different conventions NaN representations and how they propagate. However, if the source argument is not a NaN, the two copySign methods will produce equivalent results.
Therefore, even if being used in a library where the results need to be completely predictable, the faster Math version of copySign can be used as long as the source argument is known to be numerical.
The recommended functions can also be used to solve a little floating-point puzzle: generating the interesting limit values of a floating-point format just starting with constants for 0.0 and 1.0 in that format:
NaN is 0.0/0.0.
POSITIVE_INFINITY is 1.0/0.0.
MAX_VALUE is nextAfter(POSITIVE_INFINITY, 0.0).
MIN_VALUE is nextUp(0.0).
MIN_NORMAL is MIN_VALUE/(nextUp(1.0)-1.0).
I fixed a major bug in the automagic .NET serialization support.
Changes:
Binaries available here: ikvmbin-0.42.0.5.zip
Sources: ikvm-0.42.0.5.zip, openjdk6-b16-stripped.zip
Joe Darcy released OpenJDK6 b18 yesterday evening and this is now integrated with the latest IcedTea6 from Mercurial.
To build:
$ hg clone http://icedtea.classpath.org/hg/icedtea6 $ mkdir icedtea6-build $ cd icedtea6-build $ ../icedtea6/configure $ make
Then grab a beverage of your choice and wait a while… I recommend adding --with-parallel-jobs to the configure invocation if you have a multi-core machine.
Once built, you will have a build of OpenJDK6 which can use the Nimbus Look and Feel as explained in my previous blog
Running with the usual jtreg flags, -a -ignore:quiet in all repositories and adding -s for langtools, the basic regression test results on Linux for OpenJDK 6 build 18 are:
HotSpot, 24 tests passed.
Langtools, 1,355 tests passed.
JDK, 3,148 tests pass, 19 fail, and 2 have errors.
All the HotSpot tests continue to pass:
0: b17-hotspot/summary.txt pass: 24 1: b18-hotspot/summary.txt pass: 24 No differences
In langtools all the tests continue to pass and one test was added:
0: b17-langtools/summary.txt pass: 1,354 1: b18-langtools/summary.txt pass: 1,355 0 1 Test --- pass tools/javac/T6855236.java 1 differences
And in jdk, a few dozen new tests were added in b18 and the existing tests have generally consistent results, with a number of long-standing test failures corrected by Pavel Tisnovsky. The test run below was executed outside of Sun's and Oracle's wide-area network using the following contents for the testing network configuration file:
host=icedtea.classpath.org refusing_host=ns1.gnu.org far_host=developer.classpath.org
The file location to use for the networking configuration can be set by passing a -e JTREG_TESTENV=Path to file option to jtreg.
0: b17-jdk/summary.txt pass: 3,118; fail: 26 1: b18-jdk/summary.txt pass: 3,148; fail: 19; error: 2 0 1 Test --- pass com/sun/java/swing/plaf/nimbus/Test6741426.java --- pass com/sun/java/swing/plaf/nimbus/Test6849805.java --- pass com/sun/jdi/BreakpointWithFullGC.sh --- pass com/sun/jdi/ResumeOneThreadTest.java --- pass com/sun/jdi/SimulResumerTest.java --- pass demo/jvmti/compiledMethodLoad/CompiledMethodLoadTest.java fail pass java/awt/Frame/DynamicLayout/DynamicLayout.java fail pass java/awt/Frame/MaximizedToIconified/MaximizedToIconified.java fail pass java/awt/Frame/ShownOffScreenOnWin98/ShownOffScreenOnWin98Test.java fail pass java/awt/Frame/UnfocusableMaximizedFrameResizablity/UnfocusableMaximizedFrameResizablity.java --- pass java/awt/GraphicsDevice/CloneConfigsTest.java fail pass java/awt/GridLayout/LayoutExtraGaps/LayoutExtraGaps.java fail pass java/awt/Insets/CombinedTestApp1.java fail pass java/awt/KeyboardFocusmanager/TypeAhead/ButtonActionKeyTest/ButtonActionKeyTest.html fail pass java/awt/KeyboardFocusmanager/TypeAhead/MenuItemActivatedTest/MenuItemActivatedTest.html fail pass java/awt/KeyboardFocusmanager/TypeAhead/SubMenuShowTest/SubMenuShowTest.html fail pass java/awt/KeyboardFocusmanager/TypeAhead/TestDialogTypeAhead.html pass fail java/awt/Multiscreen/LocationRelativeToTest/LocationRelativeToTest.java fail pass java/awt/TextArea/UsingWithMouse/SelectionAutoscrollTest.html fail pass java/awt/Toolkit/ScreenInsetsTest/ScreenInsetsTest.java pass --- java/awt/Window/AlwaysOnTop/AlwaysOnTopEvenOfWindow.java pass fail java/awt/Window/GrabSequence/GrabSequence.java fail pass java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java pass fail java/awt/print/PrinterJob/ExceptionTest.java --- pass java/lang/ClassLoader/UninitializedParent.java pass fail java/net/ipv6tests/TcpTest.java pass fail java/nio/channels/SocketChannel/AdaptSocket.java pass fail java/nio/channels/SocketChannel/LocalAddress.java pass fail java/nio/channels/SocketChannel/Shutdown.java pass fail java/rmi/transport/pinLastArguments/PinLastArguments.java --- pass java/util/TimeZone/OldIDMappingTest.sh --- pass java/util/TimeZone/TimeZoneDatePermissionCheck.sh --- pass javax/swing/JButton/6604281/bug6604281.java fail pass javax/swing/JTextArea/Test6593649.java --- pass javax/swing/Security/6657138/ComponentTest.java --- pass javax/swing/Security/6657138/bug6657138.java --- pass javax/swing/ToolTipManager/Test6657026.java --- pass javax/swing/UIManager/Test6657026.java --- pass javax/swing/plaf/basic/BasicSplitPaneUI/Test6657026.java --- pass javax/swing/plaf/metal/MetalBorders/Test6657026.java --- pass javax/swing/plaf/metal/MetalBumps/Test6657026.java --- pass javax/swing/plaf/metal/MetalInternalFrameUI/Test6657026.java --- pass javax/swing/plaf/metal/MetalSliderUI/Test6657026.java pass error sun/java2d/OpenGL/GradientPaints.java pass fail sun/rmi/transport/proxy/EagerHttpFallback.java --- pass sun/security/provider/certpath/DisabledAlgorithms/CPBuilder.java --- pass sun/security/provider/certpath/DisabledAlgorithms/CPValidatorEndEntity.java --- pass sun/security/provider/certpath/DisabledAlgorithms/CPValidatorIntermediate.java --- pass sun/security/provider/certpath/DisabledAlgorithms/CPValidatorTrustAnchor.java pass error sun/security/ssl/javax/net/ssl/NewAPIs/SessionTimeOutTests.java --- pass sun/security/tools/jarsigner/emptymanifest.sh --- pass sun/security/util/DerValue/BadValue.java fail pass sun/tools/jhat/HatHeapDump1Test.java fail pass sun/tools/native2ascii/NativeErrors.java 54 differences
On February 16, 2010 the source bundle for OpenJDK 6 b18 was published.
Major changes in this build include the latest round of security fixes and, courtesy of Andrew John Hughes, a backport of the Nimbus look and feel from JDK 7. In addition, a
new delivery model is being used for the jaxp and jax-ws components.
A detailed list of all the changes is also available.
There‘s a lot of hype around this title. I gave a look at the trailers and I had the feeling that the game play was so similar to very old games (1983!) such as Dragon‘s Lair or Space Quest.
Today, I finally played the demo and I still have constrasting feelings… Is it cool? Yeah… I think it is, really: it‘s like playing a film, full of dark mood, beautiful scenes and colours, and a really intriguing story.
The demo shows some funny behaviour, for example, when not triggering a cut scene (that is, 90% of the time you are in a cut scene), the non playing characters (NPEs) look a bit dumb. In fact, you have the feeling that everything is a bit fake, because the interaction takes place only when is supposed to, and you find yourself wandering around the area without knowing what to do when you have no more options left, with the NPCs staring a wall with idiotic espression :)
There is a nice system that tries to address this issue and adds even more of a nice movie mood to the game: you can listen to your character‘s thoughts, and they act like an offscreen narrator, very cool I have to say.
The game play is almost non existent, though, you press one button or two when some HUDs pops up and inevitably mess with the Sixaxis controller… On the other hand, is really beautiful to watch. I suggest to wait a full review on Gamespot, but the game is cool so far.
I confirm that is the same kind of game as Dragon‘s Lair and Space Ace, be warned if you don‘t like this kind of stuff.
A master programmer passed a novice programmer one day. The master noted the novice's preoccupation with a hand-held computer game. "Excuse me", he said, "may I examine it?" The novice bolted to attention and handed the device to the master. "I see that the device claims to have three levels of play: Easy, Medium, and Hard", said the master. "Yet every such device has another level of play, where the device seeks not to conquer the human, nor to be conquered by the human." "Pray, great master," implored the novice, "how does one find this mysterious setting?" The master dropped the device to the ground and crushed it under foot. And suddenly the novice was enlightened. -- Geoffrey James, "The Tao of Programming"
Writing up a piece of old work for some more
Friday fun, an example of
testing where the failures are likely to be led to my independent discovery of a bug in the FDLIBM pow function, one of only two bugs fixed in
FDLIBM 5.3.
Even back when this bug was fixed for Java some time ago
(5033578),
the FDLIBM library was well-established, widely used in the Java platform and elsewhere, and already thoroughly tested so I was quite proud my tests found a new problem. The next most recent change to the pow implementation was eleven years prior to the fix in 5.3.
The specification for Math.pow is involved, with over two dozen special cases listed. When setting out to write tests for this method, I re-expressed the specification in a tabular form to understand what was going on. After a few iterations reminiscent of tweaking a Karnaugh map, the table below was the result.
| xy | y | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| x | –∞ | –∞ < y < 1 | –1 | –1 < y < 0 | –0.0 | +0.0 | 0 < y < 1 | 1 | 1 < y < +∞ | +∞ | NaN |
| –∞ | +0.0 | f2(y) | 1.0 | f1(y) | +∞ | NaN | |||||
| –∞ < y < –1 | +0.0 | f3(x, y) | f3(x, y) | +∞ | |||||||
| –1 | NaN† | NaN† | |||||||||
| –1 < y < 0 | +∞ | +0.0 | |||||||||
| –0.0 | +∞ | f1(y) | f2(y) | +0.0 | |||||||
| +0.0 | +∞ | +0.0 | |||||||||
| 0 < y < 1 | +∞ | x | +0.0 | ||||||||
| 1 | NaN† | 1.0 | NaN† | ||||||||
| 1 < y < +∞ | +0.0 | x | +∞ | ||||||||
| +∞ | +0.0 | +∞ | |||||||||
| NaN | NaN | NaN | |||||||||
f1(y) = isOddInt(y) ? –∞ : +∞;
f2(y) = isOddInt(y) ? –0.0 : +0.0;
f3(x, y) = isEvenInt(y) ? |x|y : (isOddInt(y) ? –|x|y : NaN);
† Defined to be +1.0 in C99, see §F.9.4.4 of the C99 specification. Large magnitude finite floating-point numbers are all even integers (since the precision of a typical floating-point format is much less than its exponent range, a large number will be an integer times the base raised to a power). Therefore, by the reasoning of the C99 committee,pow(-1.0, ∞)was likepow(-1.0, Unknown large even integer)so the result was defined to be1.0instead ofNaN.
The range of arguments in each row and column are partitioned into eleven categories, ten categories of finite values together with NaN (Not a Number). Some combination of x and y arguments are covered by multiple clauses of the specification.
A few helper functions are defined to simplify the presentation. As noted in the table, a cross-platform wrinkle is that the C99 specification, which came out after Java was first released, defined certain special cases differently than in FDLIBM and Java's Math.pow.
A regression test based on this tabular representation of pow special cases is
jdk/test/java/lang/Math/PowTests.java. The test makes sure each interesting combination in the table is probed at least once. Some combinations receive multiple probes.
When an entry represents a range, the exact endpoints of the range are tested; in addition, other interesting interior points are tested too. For example, for the range 1 < x< +∞ the individual points tested are:
+1.0000000000000002, // nextAfter(+1.0, +oo) +1.0000000000000004, +2.0, +Math.E, +3.0, +Math.PI, -(double)Integer.MIN_VALUE - 1.0, -(double)Integer.MIN_VALUE, -(double)Integer.MIN_VALUE + 1.0, double)Integer.MAX_VALUE + 4.0, (double) ((1L<<53)-1L), (double) ((1L<<53)), (double) ((1L<<53)+2L), -(double)Long.MIN_VALUE, Double.MAX_VALUE,
Besides the endpoints, the interesting interior points include points worth checking because of transitions either in the IEEE 754 double format or a 2's complement integer format.
Inputs that used to fail under this testing include a range of severities, from the almost always numerical benign error of returning a wrongly signed zero, to returning a zero when the result should be finite nonzero result, to returning infinity for a finite result, to even returning a wrongly singed infinity!
Selected Failing Inputs
Failure for StrictMath.pow(double, double): For inputs -0.5 (-0x1.0p-1) and 9.007199254740991E15 (0x1.fffffffffffffp52) expected -0.0 (-0x0.0p0) got 0.0 (0x0.0p0). Failure for StrictMath.pow(double, double): For inputs -0.9999999999999999 (-0x1.fffffffffffffp-1) and 9.007199254740991E15 (0x1.fffffffffffffp52) expected -0.36787944117144233 (-0x1.78b56362cef38p-2) got -0.0 (-0x0.0p0). Failure for StrictMath.pow(double, double): For inputs -1.0000000000000004 (-0x1.0000000000002p0) and 9.007199254740994E15 (0x1.0000000000001p53) expected 54.598150033144236 (0x1.b4c902e273a58p5) got 0.0 (0x0.0p0). Failure for StrictMath.pow(double, double): For inputs -0.9999999999999998 (-0x1.ffffffffffffep-1) and 9.007199254740992E15 (0x1.0p53) expected 0.13533528323661267 (0x1.152aaa3bf81cbp-3) got 0.0 (0x0.0p0). Failure for StrictMath.pow(double, double): For inputs -0.9999999999999998 (-0x1.ffffffffffffep-1) and -9.007199254740991E15 (-0x1.fffffffffffffp52) expected -7.38905609893065 (-0x1.d8e64b8d4ddaep2) got -Infinity (-Infinity). Failure for StrictMath.pow(double, double): For inputs -3.0 (-0x1.8p1) and 9.007199254740991E15 (0x1.fffffffffffffp52) expected -Infinity (-Infinity) got Infinity (Infinity).
The code changes to address the bug were fairly simple; corrections were made to extracting components of the floating-point inputs and sign information was propagated properly.
Even expertly written software can have errors and even long-used software can have unexpected problems. Estimating how often this bug in FDLIBM caused an issue is difficult, while the errors could be egregious, the needed inputs to elicit the problem were arguably unusual (even though perfectly valid mathematically). Thorough testing is key aspect of assuring the quality of numerical software, it is also helpful for end-users to be able to examine the output of their programs to help notice problems.
Doug pointed out yesterday how Eclipse startup performance isn’t great. I asked on his blog entry, wouldn’t it be great if we had something like bootchart — or Michael Meeks‘ work (FOSDEM presentation) — for Eclipse?
Would this be a good Eclipse Summer of Code project?
The
initial way a string switch statement was implemented in JDK 7 was to desugar a string switch into a series of two switch statements, the first switch mapping from the argument string's hash code to the ordinal position of a matching string label followed by a second switch mapping from the computed ordinal position to the code to be executed.
Before this approach was settled on, Jon, Maurizio, and I had extensive discussions about alternative implementation techniques. One approach from Maurizio we seriously considered using employed labeled break statements (in lieu of unavailable goto statements) to allow a string switch to be desugared into a single integer switch statement. In this approach as well, the basis for the integer switch built around the strings' hash codes.
One kind of complication in desugaring string switch statements stems from irregular control flow, such as when control transfers to one label, code is executed, and then control falls through to the code under the next label rather than exiting the switch statement after the initial code execution. When using hash codes to identify the string being switched on, another class of complications stem from dealing with the possibility of hash collisions, the situation where two distinct strings have the same hash code. A string can be constructed to have any integer hash code so collisions are always a possibility. Since many strings have the same hash code, it is not sufficient to verify the string being switched on just has the same hash value as a string case label; the string being switched on must be checked for equality with the case label string. Furthermore, when two string case labels have the same hash value, a string being switched on with a matching hash code must be checked for equality potentially against both case labels.
While relying on hash codes to implement string switch is contentious with some, the hashing algorithm of java.lang.String is an extremely stable part of the platform and there would be too much behavioral compatibility risk in changing it. Therefore, the stability of the algorithm can be relied on as a resource in possible string switch implementations.
Switching on the hash code in the desugaring confers a number of benefits. First, most immediately the hash code maps the string to an integer value, matching the type required for the existing switch statement.
Second, switching on the hash code of a string bounds the worst case behavior. The simplest way to see if a chosen string is in a set of other strings, such as the set of string case labels, would be to compare the chosen string to each of the strings in the set. This could be expensive since the chosen string would need to be traversed many times, potentially once for each case label. The hash code of a string is typically cached after it is first computed. Therefore, when switching on the hash code, the chosen string is not expected to be traversed more than twice (once to compute the hash code if not cached, again to compare against strings from the set of strings with the same hash value — a set usually with only one element).
If instead of a series of two desugared switch statements, only a single switch statement were desired in the desugaring, extra synthetic state variables could be used to contend with hash collisions, fall-through control flows, and default cases,
as described in the Project Coin strings in switch proposal. A goto construct could be used to eliminate state variables, but goto is neither available in the source language nor in javac's intermediate representation. However, by a novel use of nested labeled breaks, a single switch statement can be used in the desugaring without introducing additional synthetic control variables.
Consider the strings switch statement in the method f below
static void f(String s) { // Original sugared code
switch (s) {
case "azvl":
System.out.println("azvl: "+s); // fallthrough
case "quux":
System.out.println("Quux: "+s); // fallthrough
case "foo":
int i = 5; //fallthrough
case "bar":
System.out.println("FooOrBar " + (i = 6) + ": "+s);
break;
case "bmjrabc": // same hash as "azvl"
System.out.println("bmjrabc: "+s);
break;
case "baz":
System.out.println("Baz " + (i = 7) + ": "+s); // fallthrough
default:
System.out.println("default: "+s);
}
}
and the following desugaring procedure.
Create a labeled block to enclose the entire switch statement. Within that enclosing block, create a series of nested blocks, one for each case label, including a default option, if any. In the innermost block, have a switch statement based on the hash code of the strings in the original case labels. For each hash value present in the set of case labels, have an if-then-else chain comparing the string being switched on to the cases having that hash value, breaking to the corresponding label if there is a match. If a match does not occur, if the original switch has a default option, a break should transfer control to the label for the default case; if the original case does not have a default option, a break should occur to the switch exit label.
If a hash value only corresponds to a single case label, the sense of the equality/inequality comparison in the desugared code can be tuned for branch prediction purposes. After the block for a case label is closed, the code for that alternative appears. In the original switch code, there are two normal completion paths of interest: the code for an alternative is run and execution falls through to the next alternative or there is an unlabeled break to exit the switch. In the desugaring, these paths are represented by execution falling through to code for the next alternative and by a labeled break to the label synthesized for the switch statement exit. The preservation of fall through semantics is possible because the code interspersed in the nested labeled statements appears in the same textual order as in the original "sugared" string switch. Local variables can be declared in the middle of a switch block. In desugared code, such variable declarations are hoisted out to reside in the block for the entire switch statement; the declaration of the variable and its uses are then renamed to a synthetic value to avoid changing the meaning of names in other scopes. Sample results of this procedure are shown below.
static void f(String s) { // Desugared code
$exit: {
int i$foo = 0;
$default_label: {
$baz: {
$bmjrabc: {
$bar: {
$foo: {
$quux: {
$azvl: {
switch(s.hashCode()) { // cause NPE if s is null
case 3010735: // "azvl" and "bmjrabc".hashCode()
if (s.equals("azvl"))
break $azvl;
else if (s.equals("bmjrabc"))
break $bmjrabc;
else
break $default_label;
case 3482567: // "quux".hashCode()
if (!s.equals("quux")) // inequality compare
break $default_label;
break $quux;
case 101574: // "foo".hashCode()
if (s.equals("foo")) // equality compare
break $foo;
break $default_label;
case 97299: // "bar".hashCode()
if (!s.equals("bar"))
break $default_label;
break $bar;
case 97307: // "baz".hashCode()
if (!s.equals("baz"))
break $default_label;
break $baz;
default:
break $default_label;
}//switch
}//azvl
System.out.println("azvl: "+s); // fallthrough
} //quux
System.out.println("Quux: "+s); // fallthrough
} //foo
i$foo = 5;
}//bar
System.out.println("FooOrBar " + (i$foo = 6) + ": "+s);
break $exit;
}//bmjrabc
System.out.println("bmjrabc: " + s);
break $exit;
} //baz
System.out.println("Baz " + (i$foo = 7) + ": "+s); // fallthrough
}//default_label
System.out.println("default: "+s);
}//exit
}
While the series of two switches and the labeled break-based desugaring were both viable alternatives, we choose the series of two switches since the transformation seemed more localized and straightforward. The two-switch solution also has simpler interactions with debuggers. If string switches become widely used, profiling information can be used to guide future engineering efforts to optimize their performance.
A friend gave me a CD from Paul Kalkbrenner, and surprisingly, I really quite like it. Check it out:
Speaking of Berlin calling, if all goes well, we’ll be moving to Berlin (area) later this year. Berlin is indeed calling (me)
.
rkennkeMy friend Adam pointed me to Anatoly Zenkov’s generated graph of his mouse pointer movements during 3 hours using Eclipse:
http://www.flickr.com/photos/anatoliy_zenkov/4160723711
The previous photo in his stream has a screenshot of his desktop in the background so you can see what lines up where. It’s more fun to guess, though
For a fun Friday hack, this blog entry describes a program to generate a regular expression to recognize all the valid strings of integers in a given base, that is, a regular expression (regex) which accepts all in-range strings but rejects strings that would cause an overflow if converted.
This sort of regular expression could be used to verify a string won't cause a NumberFormatException when processed by one of the many text → number methods in the Java platform, such as Integer.parseInt(String s, int base). However, using a regular expression may be more expensive than attempting the conversion and catching the exception on invalid input; the regular expression discussed is possibly of more academic interest than practical significance!
An analogous regular expression for floating-point strings has been published in the javadoc for several releases.
First, is the set of strings in a given base that will convert to a 32-bit or 64-bit integer a regular language, a language that can be recognized by a regular expression? Yes, because ignoring sequences of leading zeros for a moment, there are only a finite number of strings that can be converted to integer values, one string for each of the 232 or 264 values in the int or long types, respectively. All finite languages are regular, strings of zero of more leading zeros are regular, and concatenations of regular languages are regular. Putting those facts together, the entire set of convertible strings forms a regular language. This reasoning is not dependent on the base so it holds for all integer bases, including bases 2
through
36
supported by Java's libraries.
A core regular expression of billions of strings offered as alternatives ("1|2|3|...|2147483647") while fine from a mathematical perspective, would be too slow and awkward to use. Fortunately, the pattern of valid strings has sufficient structure to yield reasonably short and manageable regular expressions.
To start we will only consider decimal strings; additionally, we will assume only ASCII digits need to be recognized. Integer values range from
-2147483648
to
2147483647
These strings both have 10 digits. Putting aside leading zeros for the moment, all strings of 9 or fewer digits are valid, with or without a leading minus sign. A regex to recognize strings with 9 or fewer digits is trivial; less obvious is how to specify the "ragged" 10-digit nonzero strings which are in range.
The core regular expression covering non-ragged inputs is
"(-)?"+ // optional leading minus sign
"0*"+ // leading zeros
"(\p{Digit}{1,9})" // numbers with 1 to 9 digits
For the 10-digit strings, if the leading digit is less than the maximum digit, all other digits can have any value:
1(\p{Digit}{9})
If the first digit is at it's maximum, then if the second digit is less than its maximum, the third and subsequent digits can have any value:
20\p{Digit}{8}
Likewise, if the first and second digits are at their maximum, then if the third digit is less than its maximum, the fourth and subsequent digits can have any value. Continuing this pattern for all the digit positions:
1(\p{Digit}{9})|
20(\p{Digit}{8})|
21[0-3](\p{Digit}{7})|
214[0-6](\p{Digit}{6})|
2147[0-3](\p{Digit}{5})|
21474[0-7](\p{Digit}{4})|
214748[0-2](\p{Digit}{3})|
2147483[0-5](\p{Digit}{2})|
21474836[0-3](\p{Digit}{1})|
214748364[0-7]
This regular expression can be ORed with the regex for strings of 1 to 9 digits listed above. Finally, a separate case for the most negative value must be added:
-0*2147483648
All together, with some newlines for readability this yields:
((-)?0*((\p{Digit}){1,9})
|([0-1]\p{Digit}{9})
|(20\p{Digit}{8})
|(21[0-3]\p{Digit}{7})
|(214[0-6]\p{Digit}{6})
|(2147[0-3]\p{Digit}{5})
|(21474[0-7]\p{Digit}{4})
|(214748[0-2]\p{Digit}{3})
|(2147483[0-5]\p{Digit}{2})
|(21474836[0-3]\p{Digit}{1})
|(214748364[0-7])
)|
(-0*2147483648)
The ragged pattern for nonzero strings with maximum possible length will exist for bases that aren't powers of 2, for the Java libraries that includes all conversion radixes other than 2, 4, 8, 16, and 32. For powers of two, the pattern is more regular. For example, in base 16 the values range from
-80000000
to
7fffffff
so for base 16 the regular expression can simply be
((-)?0*(\p{XDigit}{1,7}|
[0-7](\p{XDigit}{7}))|
(-0*80000000)
Generalizing the regular expression generation algorithm to any given base:
Create a regex for an optional leading minus sign ("-") and zero or more leading zeros, "0*."
For the base in question, generate the strings for MIN_VALUE and
MAX_VALUE.
Find n, the length of the MAX_VALUE string. Signed strings of that base with (n-1) or fewer characters are all valid inputs; create a regex recognizing (n-1) or fewer digits.
Create a regex to recognize valid strings of length n.
Combine the above regular expressions.
To the above, concatenate a separate regex for the most negative value,
-(0*)MIN_VALUE_STRING
Taken together, this regex will recognize exactly those strings convertible to the base in question.
Untested code implementing this algorithm is available for your viewing pleasure. Any further debugging, tuning, and enhancements are left as "an exercise for the reader," happy hacking!
Last week Apple released their latest product destined to change the world (the iPad). At least that's what they want us to believe. Perhaps the biggest controversy over the thing is the lack of Flash capability. However this being java.net I have to wonder out loud, where is Java capability, and more importantly why isn't as much controversy being raised over Java being missing? But I think we all can enumerate some reasons for both being missing. And it's worth it for the Java community to ponder this issue.
A couple weeks ago I attended a meeting of the Silicon Valley Web JUG (yes: Java User Group). (The Future of the Web According to Dion Almaer and Ben Galbraith) A very interesting meeting with a great overview of advances in HTML5 with an eye on the great possibilities it holds.
The interesting thing is they began the evening with a question: How many of you are interested in JavaFX? A meeting of 100+ geeks in Silicon Valley who are associated with a Java User Group, you'd think a few of them would be interested in JavaFX. One person raised their hand. I think that says a LOT.
Their presentation said a LOT about why Java and Flash both are missing from the iPad and iPod, and why we shouldn't care about that functionality gap, and indeed should feel liberated at their absence.
The key is web components built using standardized web technologies (a.k.a. The Open Web). That's HTML, XML, HTTP, JavaScript and that ilk. Flash, not being standardized by anybody, is not part of the Open Web. Despite Java having a standards body behind it and being treated/delivered by Sun as an Open Standard, it was never accepted by the tech/web community as part of the Open Web. And.. uh.. JavaFX.. sheesh, that's nowhere near being treated/delivered by Sun as any kind of Open Standard, instead it's being treated as a proprietary product where Sun is the big gorilla. Oh, wait, that's Oracle now. Sigh. In any case the Open Web should most certainly ignore JavaFX just like it calls for Flash to be eschewed.
By being based on Open Standards the Open Web has tooling available from many organizations and a rich ecosystem of experience and adoption.
An issue traditionally with HTML+JavaScript was speed. Javascript has historically been an interpreted only language and anybody who tried Java 1.0 knows how glacial that can be. Lately some Javascript implementations have been developing JIT and bytecode interpretation capabilities that eerily echo the development of Java virtual machines. According to Ben Galbraith some of those teams are staffed with former Java VM developers. In any case it means faster HTML+JavaScript execution with more capability to provide a rich GUI experience using just HTML+JavaScript. (FWIW I'm typing this in Google's Chrome browser)
This ain't the HTML+JavaScript of yesteryear. This is a brave new world. It seems in retrospect the promise of Flash and Java was speedier UI experience than the HTML+JavaScript of yesteryear, and that if the HTML+JavaScript of the future is good enough, then both Flash and Java will be rendered irrelevant. Yes, sure, of course both Adobe and Sun have over a decade of virtual machine implementation experience. But neither can achieve the tight browser integration that JavaScript can.
HTML vs. Flash: Can a turf war be avoided? That's an interesting article covering the current stance where Adobe is saying "HEY WAIT A MINNIT" about the lack of Flash in the iPad. e.g. "We are now on the verge of delivering Flash Player 10.1 for smartphones with all but one of the top manufacturers," Lynch said, specifically mentioning the Nexus One as one such device and adding that the software also works on tablets, Netbooks, and Net-enabled TVs. "Flash in the browser provides a competitive advantage to these devices because it will enable their customers to browse the whole Web...We are ready to enable Flash in the browser on these devices if and when Apple chooses to allow that for its users, but to date we have not had the required cooperation from Apple to make this happen." I happen to know for certain that Sun could say the very same thing about Java on iPhone/iPod/iPad.
Where is the truth between these possible states:-
??
(tangential digression)
Open Source != Open Standard. For a long time the hue and cry was for Sun to Open Source Java, and that would ensue a brave new era of wonderful harmony across the planet or some such. In practice Sun didn't quite open source Java, instead it created an Open Source project on a specific implementation of Java (OpenJDK) but "Java" (in my mind) was explicitly not open sourced. As a result while the resulting situation was much better than before the wonderful era of harmony did not ensue.
In any case an Open Standard can be delivered by closed source software so long as it obeys the standard. An Open Standard still allows wide use of the software and a huge amount of freedom in lots of practical forms of freedom. But Open Standards don't allow things like forking that Open Source explicitly allows.
A small project I worked on during JDK 7 milestones 05 and 06 was the introduction of a java.util.Objects class to serve as a home for static utility methods operating on general objects
(6797535,
6889858,
6891113).
Those utilities include null-safe or null-tolerant methods for
comparing two objects,
computing the hash code of an object,
and returning a string for an object, operations generally relating to the methods defined on java.lang.Object.
The code to implement each of these methods is very short, so short it is tempting to not write tests when adding such methods to a code base. But the methods they aren't so simple that mistakes cannot be made; replacing such helper methods with a common, tested version from the JDK would be a fine refactoring.
The current set of public methods in java.util.Objects is:
static boolean equals(Object a, Object b)
static boolean deepEquals(Object a, Object b)
static <T> int compare(T a, T b, Comparator<? super T> c)
static int hashCode(Object o)
static int hash(Object... values)
static String toString(Object o)
static String toString(Object o, String nullDefault)
static <T> T nonNull(T obj)
static <T> T nonNull(T obj, String message)
The first two methods define two equivalence relations over object references. Unlike the equals methods on Object, the equals(Object a, Object b) method handles null values. That is, true is returned if both arguments are null or if the first argument is non-null and a.equals(b) returns true. A method with this functionality is an especially common utility method to write, there are several versions of it in the JDK, so I expect the two-argument equals will be one of the most heavily used methods in the Objects class.
The second equivalence relation is defined by the deepEquals method. The equals and deepEquals relations can differ for object arrays; see for the javadoc for details. Equality implies deep equality, but the converse is not true. For example, in the program below arrays c and d are deep-equals but not equals.
public class Test {
public static void main(String... args) {
Object common = "A string in common.";
Object[] a = {common};
Object[] b = {common};
Object[] c = {a};
Object[] d = {b};
// c and d are deepEquals, but not equals
}
}
A third equivalence relation is the object identity relation defined by the == operator on references, but since that is already built into the language, no library support is needed. Identity equality implies equals equality and deepEquals equality.
Next, Objects includes a null-tolerant Comparator-style method which first compares for object identity using == before calling the provided Comparator. While Comparable classes aren't as widely available as the methods inherited from java.lang.Object, Comparable is a very useful and frequently implemented interface.
Objects has two hash-related methods. The first is a null-handling hash method which assigns null a zero hash code and the second is a utility method for implementing a reasonable hash function for a class just by passing in the right list of values.
The toString methods provide null handling support, in case of a null argument either returning "null" or the provided default string.
Finally, there are two methods to more conveniently handle null checks, intended to be useful when validating method and constructor parameters.
Taken together, the methods in Objects should lessen the pain and tedium of null handling until
more systematic approaches are used.
The Objects API was shaped by discussion in
various
threads on
core-libs-dev in September and October 2009.
Several other bugs were also fixed as a result of those discussions, one adding a set of compare methods for primitive types
(6582946)
and another to consistently define the hash codes of the wrapper classes
(4245470).
Thanks to Kelly,
the new component delivery model
for jaxp and jax-ws is now available in both JDK 7, as of build 72 of milestone 5, and OpenJDK 6, coming in build 18
(6856630).
As described previously, the JDK build no longer tracks a copy of the jaxp and jax-ws sources under version control. Instead source bundles from the upstream teams are used. The jaxp.properties file in the jaxp repository contains the default URL from which the source bundle is downloaded as well as the expected checksum for that file. The analogous setup is used for jax-ws in its repository.
To avoid downloading another copy of a bundle or to try out an alternate bundle, several variables can be set in the ant build of one of the repositories. For jaxp,
jaxp-repo-directory$ ant -f build.xml \
-Ddrops.master.copy.base=path-to-drop-directory \
-Djaxp_src.bundle.name=name-of-source-zip-bundle-in-drop-directory \
-Djaxp_src.bundle.md5.checksum=md5-of-source-zip-bundle
If changes local to the JDK are needed, patches can be applied from the new patches directory in the two repositories. For example, patches are a mechanism that could be used to deploy security fixes until a new source bundle with those fixes was externally available.
With this new delivery model, I look forward to low-overhead and coordinated updates to jaxp and jax-ws in OpenJDK 6 and JDK 7.
A possible future consolidation would fold the build logic in the now vestigial jaxp and jax-ws repositories into the main jdk repository.
Java developers are familiar with dynamic linking. Class files are a kind of intermediate format with symbolic references. At runtime, a class loader will
load, link, and initialize new types as needed.
Typically the full classpath a class loader uses for searching will have several logically distinct sub components, including the boot classpath, endorsed standards, extension directories, and the user-specified classpath.
The manifest of a jar file can also contain Class-Path entries.
Together, these paths delineate the boundaries of "jar hell."
For many years, modern Unix systems have also supported dynamic linking for C programs. Instead of a classpath, there is a runpath of locations to look to for resolving symbolic references. Like the classpath, the full runpath has multiple components, including a default component for system facilities (analogous to boot classpath), a component stored in a shared object (analogous to jar file Class-Path entries), as well as an end-user specified component (analogous to the -classpath command line option or CLASSPATH environment variable).
The details of linking on Solaris are well explained in Sun's
Linker and Libraries Guide.
Other contemporary Unix platforms like Linux and MacOS have similar facilities, although the details of the various commands differ.
One of the tasks the JDK's
launcher has handled is setting a suitable runpath for the JVM and platform libraries. Historically a runpath was needed to link in the desired JVM, such as client or server, and other system libraries. The client JVM and the server JVM are separate shared objects which support the same set of interfaces; by interpreting the command line flags the launcher selects which JVM to link in. Operationally, the linking is initiated by the Unix dlopen library call.
So that the caller of the java command did not need to set LD_LIBRARY_PATH, after selecting the JVM to run the launcher would modify the LD_LIBRARY_PATH environment variable by prepending the path to the JVM shared object (and paths to other directories with JDK native system libraries). However, the runtime linker only reads the value of LD_LIBRARY_PATH when a process starts. Therefore, to have the new value take effect, the launcher would call an
exec-family system call to start the process anew.
Such re-execing to set LD_LIBRARY_PATH is not recommended practice on Unix systems.
The re-execing to set LD_LIBRARY_PATH had a number of unpleasant consequences in the launcher code. There is only a narrow path to pass information between the exec parent and the exec child, such as by modifying environment variables, which is generally discouraged. To decide whether or not an exec was needed, the launcher checked whether the prefix of LD_LIBRARY_PATH had the expected value; if it did, no exec was done for that purpose and infinite exec loops were avoided. Presetting LD_LIBRARY_PATH to the right value before calling java could thus be used to suppress the exec. There were also complications with correctly supporting multiple LD_LIBRARY_PATH variables on Solaris1 and handling suid java executions on Linux.2
The proper way to accommodate such dependencies is not to set LD_LIBRARY_PATH but rather to use the runtime linker facilities analogous to jar file Class-Path entries; the facility is the $ORIGIN dynamic string token for the runtime linker. As the name implies, $ORIGIN is expanded to the path directory of the object file in question; thus relative paths to other directories can be specified. Therefore, as long as the directory structure of the JDK and JRE are known, $ORIGIN can be used to record any necessary dependencies.
For some time, the JDK build has actually used $ORIGIN in creating its native libraries. Therefore, it may have been the case that LD_LIBRARY_PATH was not actually needed. However, verifying that LD_LIBRARY_PATH was not actually needed would require building an exec-free JDK on all supported Unix platforms and running tests that exercise the all libraries in the directories no longer added to LD_LIBRARY_PATH. The engineering for
Kumar's purge of execing for LD_LIBRARY_PATH was generally straightforward: deleting the the LD_LIBRARY_PATH-related code in the Unix java_md.c file and doing builds on all platforms. Most of the effort of getting this fix back involved running tests to verify everything still worked. The testing revealed an
unneeded, troublesome symlink that was removed at the same time LD_LIBRARY_PATH usage was purged.
While the launcher no longer execs to set the LD_LIBRARY_PATH, there are still cases where an exec will occur for other reasons. If the java command is requested to change data models using the -d32 or -d64 flag, that is, a 32-bit java command is asked to run a 64-bit JVM or vice versa, an exec is needed to effect the change. Also, multiple JRE support, where a different version is requested via the -version:foo flag, will also cause an exec if a different Java version needs to be run.
However, before Kumar's fix the common case was that the launcher would exec once; now the common case is that the launcher will exec zero times.3
I'm very happy this messy use of LD_LIBRARY_PATH has finally been removed in JDK 7. The removal makes the launcher code both simpler and more maintainable. Unless your use of java relies on the number of execs that occur, the change should be largely transparent, other than startup being marginally faster.
One situation to be aware of is launching a LD_LIBRARY_PATH-free JDK 7 java command from a JDK 6 or earlier java process. If the LD_LIBRARY_PATH variable of the older JDK is not cleared, it can affect the liking of the JDK 7 process.
1 Since Solaris 7, that OS line has supported three
LD_LIBRARY_PATHvariables:
LD_LIBRARY_PATH_32: if set, overridesLD_LIBRARY_PATHfor 32-bit processes.
LD_LIBRARY_PATH_64: if set, overridesLD_LIBRARY_PATHfor 64-bit processes.
LD_LIBRARY_PATH: used by both 32-bit and 64-bit processes is not overridden by a data model specific variable.On Solaris, back in JDK 1.4.2 I fixed the launcher to properly take into account all three variables (4731671); on re-
execthe data model specific environment variable is unset andLD_LIBRARY_PATHcontains the old data model specific value prepended with the JDK system paths. Tests to verify all this used to live in and aroundtest/tools/launcher/SolarisDataModel.sh, but they have thankfully been deleted as they are no longer relevant.2 For suid or sgid binaries,
LD_LIBRARY_PATHis handled differently to avoid security problems. While the Solaris runtime linker applies more scrutiny toLD_LIBRARY_PATHin this case, on LinuxglibcsetsLD_LIBRARY_PATHto the empty string. Since the empty string will not contain the expected JDK system directories, the prefix-checking logic detected this case to avoid an infiniteexecloop (4745674). Runningjavasuid or sgid isn't necessarily recommended, but it is possible. To actually resolve linking dependencies for such binaries, OS-specific configuration may be needed to add JDK directories to the set of trusted paths.3 Before my batch of launcher fixes in JDK 1.4.2, the number of
execs was even more varied. Specifying a different data model wouldexectwice, once to change the data model and again to set theLD_LIBRARY_PATHfor that data model. From JDK 1.4.2 until the purge ofLD_LIBRARY_PATH, the launcher used a singleexecto set theLD_LIBRARY_PATHto the target data model (4492822).
![]()