diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-11-02 14:06:18 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-11-02 14:06:18 -0500 |
commit | bb51320ebeac95ca137148e16da9b09fc29f2b66 (patch) | |
tree | 153553cd49c51a44de34d0bf3d2dfb7f79544f34 | |
parent | f1133b97df5384f3336ba79fdc6d0acd2f4f3eed (diff) |
keyword invocation specialization
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 145 |
1 files changed, 137 insertions, 8 deletions
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 0b634bb5..d4938ca4 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -2479,6 +2479,120 @@ public static class VectorExpr implements Expr{ } +static class KeywordInvokeExpr implements Expr{ + public final KeywordExpr kw; + public final Object tag; + public final Expr target; + public final int line; + public final String source; + static Type ILOOKUP_TYPE = Type.getType(ILookup.class); + + public KeywordInvokeExpr(String source, int line, Symbol tag, KeywordExpr kw, Expr target){ + this.source = source; + this.kw = kw; + this.target = target; + this.line = line; + this.tag = tag; + } + + public Object eval() throws Exception{ + try + { + return kw.k.invoke(target.eval()); + } + catch(Throwable e) + { + if(!(e instanceof CompilerException)) + throw new CompilerException(source, line, e); + else + throw (CompilerException) e; + } + } + + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ + Label slowLabel = gen.newLabel(); + Label endLabel = gen.newLabel(); + + gen.visitLineNumber(line, gen.mark()); + target.emit(C.EXPRESSION, objx, gen); + gen.dup(); + gen.instanceOf(ILOOKUP_TYPE); + gen.ifZCmp(GeneratorAdapter.EQ, slowLabel); + kw.emit(C.EXPRESSION, objx, gen); + gen.invokeInterface(ILOOKUP_TYPE, new Method("valAt", OBJECT_TYPE, ARG_TYPES[1])); + gen.goTo(endLabel); + + gen.mark(slowLabel); + kw.emit(C.EXPRESSION, objx, gen); + gen.invokeStatic(RT_TYPE, new Method("get", OBJECT_TYPE, ARG_TYPES[2])); + + gen.mark(endLabel); + + if(context == C.STATEMENT) + gen.pop(); + } + + public boolean hasJavaClass() throws Exception{ + return tag != null; + } + + public Class getJavaClass() throws Exception{ + return HostExpr.tagToClass(tag); + } + +} +static class KeywordSiteInvokeExpr implements Expr{ + public final Expr site; + public final Object tag; + public final Expr target; + public final int line; + public final String source; + + public KeywordSiteInvokeExpr(String source, int line, Symbol tag, Expr site, Expr target){ + this.source = source; + this.site = site; + this.target = target; + this.line = line; + this.tag = tag; + } + + public Object eval() throws Exception{ + try + { + KeywordCallSite s = (KeywordCallSite) site.eval(); + return s.thunk.invoke(s,target.eval()); + } + catch(Throwable e) + { + if(!(e instanceof CompilerException)) + throw new CompilerException(source, line, e); + else + throw (CompilerException) e; + } + } + + public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ + gen.visitLineNumber(line, gen.mark()); + site.emit(C.EXPRESSION, objx, gen); + gen.dup(); + gen.getField(Type.getType(KeywordCallSite.class),"thunk",IFN_TYPE); + gen.swap(); + target.emit(C.EXPRESSION, objx, gen); + + gen.invokeInterface(IFN_TYPE, new Method("invoke", OBJECT_TYPE, ARG_TYPES[2])); + if(context == C.STATEMENT) + gen.pop(); + } + + public boolean hasJavaClass() throws Exception{ + return tag != null; + } + + public Class getJavaClass() throws Exception{ + return HostExpr.tagToClass(tag); + } + +} static class InvokeExpr implements Expr{ public final Expr fexpr; public final Object tag; @@ -2555,6 +2669,13 @@ static class InvokeExpr implements Expr{ if(context != C.EVAL) context = C.EXPRESSION; Expr fexpr = analyze(context, form.first()); + if(fexpr instanceof KeywordExpr && RT.count(form) == 2) + { +// fexpr = new ConstantExpr(new KeywordCallSite(((KeywordExpr)fexpr).k)); + Expr target = analyze(context, RT.second(form)); + return new KeywordInvokeExpr((String) SOURCE.deref(), (Integer) LINE.deref(), tagOf(form), + (KeywordExpr) fexpr, target); + } PersistentVector args = PersistentVector.EMPTY; for(ISeq s = RT.seq(form.next()); s != null; s = s.next()) { @@ -2846,7 +2967,7 @@ static public class ObjExpr implements Expr{ ClassVisitor cv = cw; // ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out)); //ClassVisitor cv = new TraceClassVisitor(cw, new PrintWriter(System.out)); - cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, internalName, null,superName,interfaceNames); + cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER + ACC_FINAL, internalName, null,superName,interfaceNames); // superName != null ? superName : // (isVariadic() ? "clojure/lang/RestFn" : "clojure/lang/AFunction"), null); String source = (String) SOURCE.deref(); @@ -3060,6 +3181,12 @@ static public class ObjExpr implements Expr{ gen.invokeStatic(Type.getType(Keyword.class), Method.getMethod("clojure.lang.Keyword intern(clojure.lang.Symbol)")); } + else if(value instanceof KeywordCallSite) + { + emitValue(((KeywordCallSite) value).k.sym, gen); + gen.invokeStatic(Type.getType(KeywordCallSite.class), + Method.getMethod("clojure.lang.KeywordCallSite create(clojure.lang.Symbol)")); + } else if(value instanceof Var) { Var var = (Var) value; @@ -3359,6 +3486,10 @@ static public class ObjExpr implements Expr{ //can't emit derived fn types due to visibility if(LazySeq.class.isAssignableFrom(c)) return Type.getType(ISeq.class); + else if(c == Keyword.class) + return Type.getType(Keyword.class); + else if(c == KeywordCallSite.class) + return Type.getType(KeywordCallSite.class); else if(RestFn.class.isAssignableFrom(c)) return Type.getType(RestFn.class); else if(AFn.class.isAssignableFrom(c)) @@ -3367,6 +3498,7 @@ static public class ObjExpr implements Expr{ return Type.getType(Var.class); else if(c == String.class) return Type.getType(String.class); + // return Type.getType(c); } return OBJECT_TYPE; @@ -5622,7 +5754,7 @@ public static class CaseExpr extends UntypedExpr{ public final Expr defaultExpr; public final HashMap<Integer,Expr> tests; public final HashMap<Integer,Expr> thens; - public final boolean identity; + public final boolean allKeywords; public final int line; @@ -5632,7 +5764,7 @@ public static class CaseExpr extends UntypedExpr{ public CaseExpr(int line, Expr expr, int shift, int mask, int low, int high, Expr defaultExpr, - HashMap<Integer,Expr> tests,HashMap<Integer,Expr> thens, boolean identity){ + HashMap<Integer,Expr> tests,HashMap<Integer,Expr> thens, boolean allKeywords){ this.expr = expr; this.shift = shift; this.mask = mask; @@ -5642,7 +5774,7 @@ public static class CaseExpr extends UntypedExpr{ this.tests = tests; this.thens = thens; this.line = line; - this.identity = identity; + this.allKeywords = allKeywords; } public Object eval() throws Exception{ @@ -5668,9 +5800,6 @@ public static class CaseExpr extends UntypedExpr{ gen.visitLineNumber(line, gen.mark()); expr.emit(C.EXPRESSION, objx, gen); - if(identity) - gen.invokeVirtual(OBJECT_TYPE,hashCodeMethod); - else gen.invokeStatic(UTIL_TYPE,hashMethod); gen.push(shift); gen.visitInsn(ISHR); @@ -5683,7 +5812,7 @@ public static class CaseExpr extends UntypedExpr{ gen.mark(labels.get(i)); expr.emit(C.EXPRESSION, objx, gen); tests.get(i).emit(C.EXPRESSION, objx, gen); - if(identity) + if(allKeywords) { gen.visitJumpInsn(IF_ACMPNE, defaultLabel); } |