This is the mail archive of the
kawa@sourceware.org
mailing list for the Kawa project.
Code generation problem?
- From: "Dominique Boucher" <dominique dot boucher at nuecho dot com>
- To: "Kawa List" <kawa at sources dot redhat dot com>
- Date: Fri, 7 Dec 2007 15:09:26 -0500
- Subject: Code generation problem?
Hi,
[this is a rather long and technical post]
While trying to remove some memory leaks in my code occurring on WebSphere
5.1 using IBM?s JVM, I observed something strange. Some closed procedures
are stored in static fields of some Kawa generated classes each time an
activation frame is created.
Consider the following code:
(module-name <test>)
(module-static 'init-run)
(require 'srfi-1)
(define (foo lst x)
(apply (lambda (a b) (+ a b))
(filter (cut eq? <> x) lst)))
The first argument to 'apply' in function 'foo' is a closed procedure. It
does not depend on the lexical environment, only on the global environment.
However, the first argument to 'filter' is a procedure that requires a full
closure (it references the 'x' variable).
For this code, Kawa creates a class 'test$frame' that represents the lexical
environment shared by both procedures. Everything is fine so far. When this
frame is instantiated, two instances of ModuleMethod are created, one for
each of the two procedures. Again, no problem here.
Now look at the generated code:
public class test$frame extends gnu.expr.ModuleBody{
java.lang.Object x;
static gnu.expr.ModuleMethod lambda$Fn1;
final gnu.expr.ModuleMethod lambda$Fn2;
static java.lang.Object lambda1(java.lang.Object,java.lang.Object);
Code:
0: getstatic #6; //Field
gnu/kawa/functions/AddOp.$Pl:Lgnu/kawa/functions/AddOp;
3: aload_0
4: aload_1
5: invokevirtual #12; //Method
gnu/mapping/Procedure.apply2:(Ljava/lang/Object;Ljava/lang/Object;)Ljav
a/lang/Object;
8: areturn
boolean lambda2(java.lang.Object);
Code:
0: aload_1
1: aload_0
2: getfield #18; //Field x:Ljava/lang/Object;
5: if_acmpne 12
8: iconst_1
9: goto 13
12: iconst_0
13: ireturn
The field 'lambda$Fn1' is static! And since it holds a ModuleMethod, which
keeps a reference to the frame itself, non-static objects like 'x' will be
reachable from a static field. If 'x' is a rather large object, it will
never be reclaimed by the GC (unless I set! it to #!null explicitely in my
purely functional code...) I think this is a problem. Moreover, the
initialization of the field is done each time a frame is created. If the
goal was to optimize something, it would have made more sense, IMO, to
initialize it only once.
This clearly breaks the rule of least surprise, IMO, as it has some
unexpected side-effects. I prefer to program in a purely functional style
wherever possible and I am careful about the global environment. But this
compilation strategy may force me to adopt a very different (read: ugly ;-)
coding style...
What do you think? What is the rationale about that optimization?
[I?m using an old version of Kawa (pre 1.8), so this problem may have been
fixed by now. I just wanted to know your opinion on all this.]
Thanks,
Dominique Boucher
Lead Software Developer
Nü Echo Inc.
http://www.nuecho.com