I stated that Clojure's maximum arity is 20. That's not exactly true: for arity's beyond 20, IFn has a special invocation that accepts the arguments as an array. But this means that the compiler has to account for this, and arrange the arguments as a single array argument instead of multiple arguments. So, it just means that for arity's beyond 20, Clojure switches to a slightly less efficient invocation.
(Also, sorry for my weird grammar on that last post. Sometimes when I type, words that are in my head do not end up in the final message. :/ Fill in the gaps!)
I am staring right now at my JVM 7 build of Clojure that uses invokedynamic for Vars that contain functions. It essentially works, well enough for experimentation. A few of my simple apps seem to work fine with it.
There are still a lot of problems: the Clojure test suite fails, and my re-linking fallback mechanism (based on SwitchPoint) does not differentiate between root bindings of Var and their "box" thread-binding, so in theory any rebinding will cause all linkages on that Var to reset. Not very optimal.
I've really done very little optimizing at all at this point: invokedynamic is just replacing the usual invokeinterface. So, I was surprised that when fooling around with some benchmarks, one of them showed about 30% performance improvement on one of my Clojure-built web servers. Tantalizing! But, until the test suite succeeds, I can't be sure that this isn't a side effect of something not so great that's going on.
I'm hoping to have something the rest of you can play with soon, but thought you would want to hear a progress report. What would be the most convenient way to share this? A dump to github of the whole tree? A patch?
I've used the Clojure 1.2.1 codebase, because I didn't want to work on a moving target, and also think it might be easier for the community to help test this with existing applications. (As I said earlier, I also have a few ideas on how to make sure we can have this mechanism gracefully downgrade to JVM <7.)
Many thanks to Paul Stadig and Charlie Nutter for prodding me to realize that the one point where invokedynamic can help is to bridge the gap between dereferencing the Var and then calling invokeinterface on it. My mistake when looking at this the first time around was assuming that the dereferencing and subsequent invokeinterface were fast operations, and that it would make little difference to replace them with invokedynamic. But, speed is not the issue here: it's that this gap represents a black hole for HotSpot, around which it can't optimize well. Because this mechanism represents the primary junction for all of Clojure, optimization here could enable some nifty optimization across the board. I think it's a good way to imagine invokedynamic's benefits: it's a bridge over troubled water for HotSpot.
Paul also points out areas where MethodHandles can replace the rather sticky reflection work that Clojure does now to massage calls to non-Clojure libraries. That's not entirely related to the invokedynamic stuff I'm working on, so I think I'll leave it to somebody else to take a stab at that...
On Sat, Aug 27, 2011 at 8:31 PM, Tal Liron <tal.li...@gmail.com> wrote: > I can think of a few ways in which it would be possible to distribute a > clojure.jar that supports JVM 7 features while still falling back to JVM 5 > compatibility. So, I don't think this was ever a barrier. But you obviously > unconvinced by my report! Thank you for challenging me on this, As I said, > I'm by no means 100% sure I exhausted the issue. I would encourage you to > try out your ideas.
I agree. I wasn't saying that it was impossible to target both Java 5 and take advantage of Java 7 features. I had mentioned that targeting Java 7 could be specified as an option when AOT compiling, or it could automatically be detected when compiling at runtime. However, I think that people (perhaps rightly so) make the argument that the amount of effort weighed against compatibility concerns and resource allocation and the percentage of Clojure code that would benefit, doesn't make it worth doing. That's different than saying that there would be no benefit to Clojure.
*-- If you don't provide any type hints, then the constructor for
> InstanceMethodExpr sets method = null and warns you that you're doing > reflection...[snip] > * > You are right! This is perhaps the only place where invokedynamic can be > useful for Clojure. *However*, to me this is not a big deal, because the > workaround of allowing for type hinting solves the problem just as well, and > perhaps even more efficiently from the compiler's point of view. All it does > is require some extra annotations by the programmer. The fact that Clojure > emits a warning seems good enough for me, personally.
This seems to be a standard response from people, and I don't really understand it. You are comparing apples to oranges. Don't get me wrong. Type hints are a critical tool for improving the performance of critical sections, and would probably be necessary even if Clojure's dynamic dispatch was faster than it is, but it seems like a win to just automatically make dispatch faster without type hints, and I guess it boils down to mostly non-technical factors (see above). Plus the biggest boost would be to code that interoperates with Java, which is arguably rarer than pure Clojure code (though I think that invokedynamic could even speed up Var dispatch, protocol dispatch, and multimethod dispatch (see below)).
*-- I may be missing something, but I don't see how JRuby needs different
> But there is in fact another serious limitation of the JVM that comes into > play here, which might seem very obvious to [Charles Nutter] but not so much > to Clojure folk: the smallest container unit of code for the JVM is a class. > There is no such thing as a free-floating procedure that you can just invoke > whenever. ...
> ...This is a problem not only for JRuby, but also for implementing > delegates in the Java, a long-request feature. Java thus needs to do > ridiculous things like this, which in C# (for example) would be done so much > more elegantly:
> new Thread(new Runnable() { public void run() { ThisIsMyFakeDelegate(); > }).start();
> What we did above was create a new (anonymous) class as well as an > instance! Clojure does essentially the same thing per fn, extending AFn > instead of implementing Runnable.
> * Correction: In my original report, I said that Clojure creates only > instances of AFn, not classes. I was misstating the situation: it's exactly > one class and one instance per fn. Clojure extends AFn and simply overrides > the correct method according to arity. ...
I'm still not seeing an problems that are different than Clojure. JRuby must create a class for every method of every class in order to make the methods hot-swappable at runtime. Clojure does the same thing for its IFns and for the same reason. Both JRuby and Clojure would have to do this even if invokedynamic didn't exist, because it is a problem more with classes and class loading, than with invocation. I don't necessarily want to get distracted by this...
*-- Clojure has similar needs. For instance, Clojure has protocol dispatch
> and multimethod dispatch as well as Var based dispatch. The multimethod > dispatch does a look up in the derivation hierarchy. All of this stuff can > change at runtime, just like in Ruby you can add methods to a class, change > methods on a class, etc. I don't see how Clojure's dispatch needs are much > different than what other dynamic languages are doing. > * > So, perhaps I'm not understanding how you are using the term "change at > runtime" to describe both JRuby regular dispatch and Clojure's multimethod. > ...
Correct me if I'm wrong, but multimethod dispatch calls a dispatch function that returns a value. This value can then be used to inspect the global derivation hierarchy. Then the result is used to find the right defmethod to call, by basically looking up in a dictionary of methods. The global derivation hierarchy can be changed at runtime which can cause different dispatch values to be returned for the same arguments at different times. Also, new defmethods can be added at runtime, which can change the dictionary of methods. Protocol dispatch is similar, but doesn't go through the global derivation hierarchy.
I believe there's already some form of caching implemented for multimethods and protocols. That caching code could be replaced by bootstrap methods and CallSites, which isn't really that exciting. However, I do believe that the JVM can better optimize a MethodHandle in a CallSite than it can an IFn that is fetched from a method dictionary at runtime. Perhaps that's just speculation on my part. However, I've been hearing good things about invokedynamic.
Plus, I believe with a CallSite the cache is more immediate than with a dictionary lookup. With a dictionary lookup, you do the lookup every time through the code path, but, as Charlie mentioned in another post, with a MethodHandle you go straight from a reference to the implementation code without having to do the lookup and without going through an interface. This seems to be not only a performance boost, but provides more specific information to the JVM, which would seem to improve optimizations.
Anyway, the biggest boost would seem to be calling Java methods from Clojure without type hints.
Clojure's multimethod is "dynamic" in an entirely different way: the correct
> function is selected at runtime *according to the arguments* of the > function. JVM-level linkage to the selected method would make no sense, > because you'd be calling your bootstrapping method every single call!
Yeah, I've thought about that. That may be true. However, Clojure does use caching for multimethod and protocol dispatch, and to whatever extent that caching is successful it can be pushed down into the JVM. And again, to me the advantage would be that the JVM has a MethodHandle directly to a method, which would improve optimization potential, and also once they are bootstrapped MethodHandles don't have check and recheck access levels and types of arguments. MethodHandles are designed to remove the extra layers of things you normally have to deal with when implementing dynamic languages on the JVM.
You can argue that Clojure multimethods are inherently inefficient, and
> One solution I could see is we allow to expand Clojure's deftypes into > something more like classes/modules in other languages, in that deftypes > could encapsulate functions as well as fields. But, this would turn Clojure > into essentially object-oriented language, and I sincerely doubt Rich would > allow for that to happen. :)
> Hope this helps clarify things! I don't think I've answered every single > one of your points, but this discussion is already probably too long for > more readers. Again, I encourage you to try to implement your ideas. The > more eyes are on this problem, the better.
On Sun, Aug 28, 2011 at 10:25 AM, Tal Liron <tal.li...@gmail.com> wrote: > Progress!
> I am staring right now at my JVM 7 build of Clojure that uses invokedynamic > for Vars that contain functions. It essentially works, well enough for > experimentation. A few of my simple apps seem to work fine with it.
> There are still a lot of problems: the Clojure test suite fails, and my > re-linking fallback mechanism (based on SwitchPoint) does not differentiate > between root bindings of Var and their "box" thread-binding, so in theory > any rebinding will cause all linkages on that Var to reset. Not very > optimal.
> I've really done very little optimizing at all at this point: invokedynamic > is just replacing the usual invokeinterface. So, I was surprised that when > fooling around with some benchmarks, one of them showed about 30% > performance improvement on one of my Clojure-built web servers. Tantalizing! > But, until the test suite succeeds, I can't be sure that this isn't a side > effect of something not so great that's going on.
> I'm hoping to have something the rest of you can play with soon, but > thought you would want to hear a progress report. What would be the most > convenient way to share this? A dump to github of the whole tree? A patch?
Hey that's good news! It would be simple enough for you to push a branch to your own fork of Clojure on github.
> I've used the Clojure 1.2.1 codebase, because I didn't want to work on a > moving target, and also think it might be easier for the community to help > test this with existing applications. (As I said earlier, I also have a few > ideas on how to make sure we can have this mechanism gracefully downgrade to > JVM <7.)
> Many thanks to Paul Stadig and Charlie Nutter for prodding me to realize > that the one point where invokedynamic can help is to bridge the gap between > dereferencing the Var and then calling invokeinterface on it. My mistake > when looking at this the first time around was assuming that the > dereferencing and subsequent invokeinterface were fast operations, and that > it would make little difference to replace them with invokedynamic. But, > speed is not the issue here: it's that this gap represents a black hole for > HotSpot, around which it can't optimize well. Because this mechanism > represents the primary junction for all of Clojure, optimization here could > enable some nifty optimization across the board. I think it's a good way to > imagine invokedynamic's benefits: it's a bridge over troubled water for > HotSpot.
> Paul also points out areas where MethodHandles can replace the rather > sticky reflection work that Clojure does now to massage calls to non-Clojure > libraries. That's not entirely related to the invokedynamic stuff I'm > working on, so I think I'll leave it to somebody else to take a stab at > that...
I wonder if it would be that difficult to replace the reflector code with an invokedynamic. There is a way to get from a java.lang.reflect.Method to a java.lang.invoke.MethodHandle (see java.lang.invoke.MethodHandles.Lookup.unreflect). You could probably just replace the code that emits a direct call to clojure.lang.Reflector to emit an invokedynamic instruction that calls a bootstrap method that wraps the Reflector code and just converts the Method into a MethodHandle for bootstrapping.
But things always seem easier until you actually get into them. :)
> Paul also points out areas where MethodHandles can replace the rather >> sticky reflection work that Clojure does now to massage calls to non-Clojure >> libraries. That's not entirely related to the invokedynamic stuff I'm >> working on, so I think I'll leave it to somebody else to take a stab at >> that...
> I wonder if it would be that difficult to replace the reflector code with > an invokedynamic. There is a way to get from a java.lang.reflect.Method to a > java.lang.invoke.MethodHandle (see > java.lang.invoke.MethodHandles.Lookup.unreflect). You could probably just > replace the code that emits a direct call to clojure.lang.Reflector to emit > an invokedynamic instruction that calls a bootstrap method that wraps the > Reflector code and just converts the Method into a MethodHandle for > bootstrapping.
I think you're overstating the problem: reflection is ugly, but it only happens here during compilation. From then on, the compiled code does what it needs to do with the types. At least, that's my reading of it: you told me before that I was dead wrong here, and maybe I am! If I'm right, then I don't see a "gap" here that invokedynamic can help bridge.
> But things always seem easier until you actually get into them. :)
Tell me about it! Getting invokedynamic to work was much harder than I thought. It doesn't help that the Clojure codebase is a) very non-canonical Java, and b) utterly undocumented. Also, there's very little documentation about these new JVM features. They involve various tricks having to do with frame stack accounting and signatures, and when you don't get it right, you get terrible exceptions from ASM or the JVM. In both cases, all they can tell you is that "you're doing it wrong." Not for the faint of heart, nor for people who hate assembly...
On Sun, Aug 28, 2011 at 10:58 AM, Tal Liron <tal.li...@gmail.com> wrote: > I wonder if it would be that difficult to replace the reflector code with >> an invokedynamic. There is a way to get from a java.lang.reflect.Method to a >> java.lang.invoke.MethodHandle (see >> java.lang.invoke.MethodHandles.Lookup.unreflect). You could probably just >> replace the code that emits a direct call to clojure.lang.Reflector to emit >> an invokedynamic instruction that calls a bootstrap method that wraps the >> Reflector code and just converts the Method into a MethodHandle for >> bootstrapping.
> I think you're overstating the problem: reflection is ugly, but it only > happens here during compilation. From then on, the compiled code does what > it needs to do with the types. At least, that's my reading of it: you told > me before that I was dead wrong here, and maybe I am! If I'm right, then I > don't see a "gap" here that invokedynamic can help bridge.
If you look at the links in my previous e-mail (specifically this one https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/C...). The reflection is done in the compiler only when there is a tag (i.e. a type hint). Otherwise the compiler just emits an invoke instruction to call the Reflector at runtime. That invoke could be replaced with an invokedynamic instruction.
If you are able to push a branch I may be able to find some time to hack on it.
Thanks for sticking with this though. The more I understand about invokedynamic the more interesting it becomes.
> If you look at the links in my previous e-mail (specifically this one > https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/C...). > The reflection is done in the compiler only when there is a tag (i.e. a type > hint). Otherwise the compiler just emits an invoke instruction to call the > Reflector at runtime. That invoke could be replaced with an invokedynamic > instruction.
Yes, that's exactly where one of us is mistaken. :) My understanding is that this constructor is only called once during the analysis mode. Then, one of the emit() methods is called, and from then on we are only executing the compiled code.
On Aug 28, 12:41 pm, Tal Liron <tal.li...@gmail.com> wrote:
> > If you look at the links in my previous e-mail (specifically this one
> >https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/C...).
> > The reflection is done in the compiler only when there is a tag (i.e. a type
> > hint). Otherwise the compiler just emits an invoke instruction to call the
> > Reflector at runtime. That invoke could be replaced with an invokedynamic
> > instruction.
> Yes, that's exactly where one of us is mistaken. :) My understanding is that
> this constructor is only called once during the analysis mode. Then, one of
> the emit() methods is called, and from then on we are only executing the
> compiled code.
Well, the statement you just made is true, but nonetheless you are the
one who is mistaken. The emit() method is called, but if not enough
information was present at compile time to resolve to a real method
call (that is, if `method = null` was executed), then the emit() code
emits a call to clojure.lang.Reflector/invokeMatchingMethod, which
does runtime reflection. See
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/C... where the "fast path" code is only emitted if `method != null`, and
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/C... where the slow code is emitted instead.
Most of what I know about invokedynamic is from watching this thread,
but here seems to definitely be an area where you could avoid some
runtime reflection, which is quite slow.
You have to be careful, though, because the Method resolved the first
time may not be right the second time. Consider (. some-obj (size)).
If it is called on a j.u.Collection, we can do the reflection and
create a MethodHandle for faster dispatch later. but if someone later
passes in a j.u.Map (which is not a Collection), you have to reflect
again and come up with another MethodHandle. I assume there's some way
to do this, but it's harder than just shoving all runtime reflection
into MethodHandles.
> Well, the statement you just made is true, but nonetheless you are the > one who is mistaken. The emit() method is called, but if not enough > information was present at compile time to resolve to a real method > call (that is, if `method = null` was executed), then the emit() code > emits a call to clojure.lang.Reflector/invokeMatchingMethod, which > does runtime reflection. See
You will get a warning that the slow path will be used, so you will have a chance to add hinting to your code. In my opinion, it's a reasonable workaround.
Still... your comment makes me think that are especially dynamic use cases where you really don't want hinting, but you do want the correct method to be called (which is why this is a warning and not an error, I guess). But... wouldn't solving this in Lisp be easier?
I commented somewhere else that Lisp differs from other languages in that a lot of optimization is often the programmer's job. Memoization, smart recursion techniques, etc., can't be left to the underlying engine. Sometimes this is good! Programmer knows best. :)
I encouraged other people to try, so the least I can do now is to point you at some of the serious challenges.
Right now I have what I think is a nice semi-generic mechanism for invokedynamic. It's called the "Linker": it handles finding the target method handle, bootstrapping, and what I call "restrapping", which is what happens when you guard it with an "ILinkable" (another new interface) and it fallbacks when a SwitchPoint is invalidated. There some various MethodHandle composing to make sure caller and target are both happy. I hope the "Linker" will make is easier to add invokedynamic in Clojure, and possibly in other projects.
My real challenge is not there, however, but with adapting Clojure to JVM 7 more generally. invokedynamic requires V1.7 classes, and for V1.7 the stack frame map that was optional in V1.6 is now a requirement. This is overall a very good idea for moving the JVM forward (these maps are a huge help for HotSpot), but I have no doubt that it will create serious pain for any project that generates JVM bytecode and until JVM 7 now could afford to be sloppier with stack frames. The V1.7 verifier will simply not let you load classes that don't have perfectly aligned maps.
ASM has very nice support for doing the stack frame arithmetic for you, but this is still being worked on in ASM 4 (trunk), and is not working in Clojure. I'm getting VerifyErrors specifically having to do with the mapping of try-catch blocks, and am working on debugging this via close look at CheckClassAdapter dumps. It's about as much fun as filling in tax forms. :/
(I've added support for two new defines, -Dclojure.jvm7=true and -Dclojure.invokedynamic=true, so each can be turned on separately. To be clear, my problems right now are in -Dclojure.jvm7=true and -Dclojure.invokedynamic=false.)
I've already patched one tiny part of ASM commons in order to add support for invokedynamic, and my work on debugging this may result in a more major patch to ASM. Assuming I do manage a fix. :/
So, what can I say? It's the cutting edge, baby. In for a penny, in for a pound.
The version of ASM that is bundled in Clojure is very old. This will likely cause problems. You are correct in looking to ASM 4 since it has started supported the JSR-292 stuff and other Java 7 changes. I am planning on doing an extraction, update, and re-packaging of ASM in Clojure as soon as Programming Clojure hits the printers. This most likely won't get started until October though because of conferences.
> I encouraged other people to try, so the least I can do now is to > point you at some of the serious challenges.
> Right now I have what I think is a nice semi-generic mechanism for > invokedynamic. It's called the "Linker": it handles finding the target > method handle, bootstrapping, and what I call "restrapping", which is > what happens when you guard it with an "ILinkable" (another new > interface) and it fallbacks when a SwitchPoint is invalidated. There > some various MethodHandle composing to make sure caller and target are > both happy. I hope the "Linker" will make is easier to add > invokedynamic in Clojure, and possibly in other projects.
> My real challenge is not there, however, but with adapting Clojure to > JVM 7 more generally. invokedynamic requires V1.7 classes, and for > V1.7 the stack frame map that was optional in V1.6 is now a > requirement. This is overall a very good idea for moving the JVM > forward (these maps are a huge help for HotSpot), but I have no doubt > that it will create serious pain for any project that generates JVM > bytecode and until JVM 7 now could afford to be sloppier with stack > frames. The V1.7 verifier will simply not let you load classes that > don't have perfectly aligned maps.
> ASM has very nice support for doing the stack frame arithmetic for > you, but this is still being worked on in ASM 4 (trunk), and is not > working in Clojure. I'm getting VerifyErrors specifically having to do > with the mapping of try-catch blocks, and am working on debugging this > via close look at CheckClassAdapter dumps. It's about as much fun as > filling in tax forms. :/
> (I've added support for two new defines, -Dclojure.jvm7=true and > -Dclojure.invokedynamic=true, so each can be turned on separately. To > be clear, my problems right now are in -Dclojure.jvm7=true and > -Dclojure.invokedynamic=false.)
> I've already patched one tiny part of ASM commons in order to add > support for invokedynamic, and my work on debugging this may result in > a more major patch to ASM. Assuming I do manage a fix. :/
> So, what can I say? It's the cutting edge, baby. In for a penny, in > for a pound.
> -Tal > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient > with your first post. > To unsubscribe from this group, send email to > clojure+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en
The version of ASM that is bundled in Clojure is very old. This will
likely cause problems. You are correct in looking to ASM 4 since it has
started supported the JSR-292 stuff and other Java 7 changes. I am
planning on doing an extraction, update, and re-packaging of ASM in
Clojure as soon as Programming Clojure hits the printers. This most
likely won't get started until October though because of conferences.
I've already done that for my branch (that was a task in itself!
needed a little monkeypatching to support Clojure's
DynamicClassLoader), so you may want to leave it to me.
My code is in quite a messy state now and I'm embarrassed to make it
public quite yet...
BTW, does somebody have an Eclipse Java code formatter configuration
for Clojure's wacky coding style?
> The version of ASM that is bundled in Clojure is very old. This will > likely cause problems. You are correct in looking to ASM 4 since it has > started supported the JSR-292 stuff and other Java 7 changes. I am > planning on doing an extraction, update, and re-packaging of ASM in > Clojure as soon as Programming Clojure hits the printers. This most > likely won't get started until October though because of conferences.
> I've already done that for my branch (that was a task in itself! needed a > little monkeypatching to support Clojure's DynamicClassLoader), so you may > want to leave it to me.
> My code is in quite a messy state now and I'm embarrassed to make it public > quite yet...
> BTW, does somebody have an Eclipse Java code formatter configuration for > Clojure's wacky coding style?
You mean for the java parts of Clojure in java.lang ? No, sorry, no.
> -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en
I started on some work to use invokedynamic instructions (instead of reflection) for calling Java interop. I based my work on 1.3beta2, and my goal was just to see how much of a performance difference it could make (if any).
So far all I have done is update the bundled ASM and modify Clojure to emit Java7 class files, but I'm getting VerifyErrors (same as Tal). It's possible that this is a bug in the way that ASM automatically calculates stack maps, or perhaps it is the best that ASM can do, in which case the Clojure compiler would have to be modified to do bookkeeping around stack maps.
I even tried moving to ASM trunk to see if it made any difference, but it didn't.
Anyway, I pushed a couple of branches to my fork of Clojure:
On Mon, Aug 29, 2011 at 7:05 PM, Tal Liron <tal.li...@gmail.com> wrote: > On 08/29/2011 06:01 PM, Aaron Bedra wrote:
> The version of ASM that is bundled in Clojure is very old. This will > likely cause problems. You are correct in looking to ASM 4 since it has > started supported the JSR-292 stuff and other Java 7 changes. I am > planning on doing an extraction, update, and re-packaging of ASM in > Clojure as soon as Programming Clojure hits the printers. This most > likely won't get started until October though because of conferences.
> I've already done that for my branch (that was a task in itself! needed a > little monkeypatching to support Clojure's DynamicClassLoader), so you may > want to leave it to me.
> My code is in quite a messy state now and I'm embarrassed to make it public > quite yet...
> BTW, does somebody have an Eclipse Java code formatter configuration for > Clojure's wacky coding style?
> -Tal
> -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscribe@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en
So far all I have done is update the bundled ASM and modify
Clojure to emit Java7 class files, but I'm getting VerifyErrors
(same as Tal). It's possible that this is a bug in the way that
ASM automatically calculates stack maps, or perhaps it is the best
that ASM can do, in which case the Clojure compiler would have to
be modified to do bookkeeping around stack maps.
Cool! I'm making some progress with some folk on the ASM mailing
list. We might crack this yet.