Sunday, September 09, 2012

Moving jSuneido to Java 7

I'm finally getting around to using Java 7 features in jSuneido. I've been hearing about this stuff for so long, but it hasn't seemed practical to use it till lately. At first, Java 7 wasn't available. Then it was available, but there were some issues. Then Eclipse didn't support it. Now that these issues are resolved, and end-of-life for Java 6 has been announced, it seems like I can finally go ahead.

The main thing I've been waiting for is JSR 292 - Supporting Dynamically Typed Languages on the Java Platform.

For some reason I have a hard time wrapping my head around invoke dynamic + bootstrap + method handles. The ideas seem simple enough, but actually figuring out how to use them properly is tough. Part of the problem is that there's not much documentation available. That's not surprising, considering that the audience is primarily language developers and therefore small. There's the JSR292 Cookbook, which helps, but it's just code, with no explanation. There is a corresponding slide deck from last year's JVM Summit which is still mostly code, but at least highlights the critical pieces.

I decided to take the smallest first step I could - just use java.lang.invoke.MethodHandle to avoid making a class for each built-in method. Even that gave me a few problems because I wasn't sure how much of my infrastructure for default and named arguments I could/should replace.  (I ended up keeping most of it for now.)

I got that working, but then I could no longer get ProGuard to run. (Note: I use it to produce a final jar with only what I need, I don't obfuscate.) It failed with:

Warning: suneido.language.Builtin$Method: can't find referenced method 'java.lang.Object invoke(java.lang.Object,java.lang.Object[])' in class java.lang.invoke.MethodHandle

I searched on the web, but couldn't find anything helpful.

I tried every combination of ProGuard options without any luck.

I eventually looked at the source for MethodHandle (which I somehow had available in Eclipse). The invoke method is native, so I tried the various options which ProGuard recommends for keeping native methods, again with no success.

I think the problem is that MethodHandle.invoke is "signature polymorphic", meaning it doesn't have a fixed signature. I'm guessing that is confusing ProGuard. (Although the signature is (Object... args) so it should accept anything anyway.) Hopefully they'll fix it at some point when more people try to use it.

In the meantime, I more or less gave up and just added:

-dontwarn java.lang.invoke.MethodHandle

to my ProGuard configuration. That "fixes" the warnings and the resulting jar appears to work fine.

Just using MethodHandle for built-in methods doesn't really accomplish much, but it's a start. The real benefit will come from using invokedynamic, but that has a lot more moving parts to figure out.

No comments: