From 3155a888b34d83e56ff5f1711c17c48e2e567e8f Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sun, 9 Sep 2012 01:01:38 -0700 Subject: [PATCH] CLJ-1065: Only do duplicate map key checks at compile time if all keys constant Also changes several calls to RT.map to RT.mapUniqueKeys, to save a little bit of unnecessary duplicate key checking there. Many more such calls could be modified, but I only did so for those that had more than a few keys/val pairs. --- src/jvm/clojure/lang/Compiler.java | 76 ++++++++++++++++++++++++++++-------- src/jvm/clojure/lang/RT.java | 12 +++++- 2 files changed, 69 insertions(+), 19 deletions(-) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index e2146a6..2e094a7 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -2788,6 +2788,7 @@ public static class ListExpr implements Expr{ public static class MapExpr implements Expr{ public final IPersistentVector keyvals; final static Method mapMethod = Method.getMethod("clojure.lang.IPersistentMap map(Object[])"); + final static Method mapUniqueKeysMethod = Method.getMethod("clojure.lang.IPersistentMap mapUniqueKeys(Object[])"); public MapExpr(IPersistentVector keyvals){ @@ -2802,8 +2803,28 @@ public static class MapExpr implements Expr{ } public void emit(C context, ObjExpr objx, GeneratorAdapter gen){ + boolean allKeysConstant = true; + boolean allConstantKeysUnique = true; + IPersistentSet constantKeys = PersistentHashSet.EMPTY; + for(int i = 0; i < keyvals.count(); i+=2) + { + Expr k = (Expr) keyvals.nth(i); + if(k instanceof LiteralExpr) + { + Object kval = k.eval(); + if (constantKeys.contains(kval)) + allConstantKeysUnique = false; + else + constantKeys = (IPersistentSet)constantKeys.cons(kval); + } + else + allKeysConstant = false; + } MethodExpr.emitArgsAsArray(keyvals, objx, gen); - gen.invokeStatic(RT_TYPE, mapMethod); + if((allKeysConstant && allConstantKeysUnique) || (keyvals.count() <= 2)) + gen.invokeStatic(RT_TYPE, mapUniqueKeysMethod); + else + gen.invokeStatic(RT_TYPE, mapMethod); if(context == C.STATEMENT) gen.pop(); } @@ -2819,7 +2840,10 @@ public static class MapExpr implements Expr{ static public Expr parse(C context, IPersistentMap form) { IPersistentVector keyvals = PersistentVector.EMPTY; - boolean constant = true; + boolean keysConstant = true; + boolean valsConstant = true; + boolean allConstantKeysUnique = true; + IPersistentSet constantKeys = PersistentHashSet.EMPTY; for(ISeq s = RT.seq(form); s != null; s = s.next()) { IMapEntry e = (IMapEntry) s.first(); @@ -2827,23 +2851,41 @@ public static class MapExpr implements Expr{ Expr v = analyze(context == C.EVAL ? context : C.EXPRESSION, e.val()); keyvals = (IPersistentVector) keyvals.cons(k); keyvals = (IPersistentVector) keyvals.cons(v); - if(!(k instanceof LiteralExpr && v instanceof LiteralExpr)) - constant = false; + if(k instanceof LiteralExpr) + { + Object kval = k.eval(); + if (constantKeys.contains(kval)) + allConstantKeysUnique = false; + else + constantKeys = (IPersistentSet)constantKeys.cons(kval); + } + else + keysConstant = false; + if(!(v instanceof LiteralExpr)) + valsConstant = false; } Expr ret = new MapExpr(keyvals); if(form instanceof IObj && ((IObj) form).meta() != null) return new MetaExpr(ret, MapExpr .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) form).meta())); - else if(constant) + else if(keysConstant) { - IPersistentMap m = PersistentHashMap.EMPTY; - for(int i=0;i