diff options
author | Rich Hickey <richhickey@gmail.com> | 2009-11-24 07:51:02 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2009-11-24 07:51:02 -0500 |
commit | 4d08439a9cf79f34a730714f12edd5959aae126e (patch) | |
tree | c4bf543bd53832cf17a35c786705c14147c3b41a | |
parent | 98366f353463afdc195b9b8fdf9d220bca7d0d6a (diff) |
direct linking of var calls, inlining of self calls
Granularity and control options for these still TBD, right now all of clojure* is direct linked, and contrib.mock known failing
-rw-r--r-- | src/clj/clojure/core.clj | 26 | ||||
-rw-r--r-- | src/clj/clojure/test.clj | 3 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 119 |
3 files changed, 112 insertions, 36 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index 6f96e1e1..1cd7b167 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -227,7 +227,8 @@ fdecl) m (conj {:arglists (list 'quote (sigs fdecl))} m)] (list 'def (with-meta name (conj (if (meta name) (meta name) {}) m)) - (cons `fn fdecl))))) + (cons `fn (cons name fdecl)))))) + ;(cons `fn fdecl))))) (. (var defn) (setMacro)) @@ -427,8 +428,6 @@ [obj f & args] (with-meta obj (apply f (meta obj) args))) - - (defmacro lazy-seq "Takes a body of expressions that returns an ISeq or nil, and yields a Seqable object that will invoke the body only the first time seq @@ -489,8 +488,6 @@ (cat (concat x y) zs)))) ;;;;;;;;;;;;;;;;at this point all the support for syntax-quote exists;;;;;;;;;;;;;;;;;;;;;; - - (defmacro delay "Takes a body of expressions and yields a Delay object that will invoke the body only the first time it is forced (with force), and @@ -1908,6 +1905,10 @@ (next vs)) map))) +(defmacro declare + "defs the supplied var names with no bindings, useful for making forward declarations." + [& names] `(do ~@(map #(list 'def (vary-meta % assoc :declared true)) names))) + (defn line-seq "Returns the lines of text from rdr as a lazy sequence of strings. rdr must implement java.io.BufferedReader." @@ -2289,6 +2290,7 @@ of *out*. Prints the object(s), separated by spaces if there is more than one. By default, pr and prn print in a way that objects can be read by the reader" + {:dynamic true} ([] nil) ([x] (pr-on x *out*)) @@ -2886,7 +2888,7 @@ (let [name (if (symbol? (first sigs)) (first sigs) nil) sigs (if name (next sigs) sigs) sigs (if (vector? (first sigs)) (list sigs) sigs) - psig (fn [sig] + psig (fn* [sig] (let [[params & body] sig conds (when (and (next body) (map? (first body))) (first body)) @@ -2898,11 +2900,11 @@ `((let [~'% ~(if (< 1 (count body)) `(do ~@body) (first body))] - ~@(map (fn [c] `(assert ~c)) post) + ~@(map (fn* [c] `(assert ~c)) post) ~'%)) body) body (if pre - (concat (map (fn [c] `(assert ~c)) pre) + (concat (map (fn* [c] `(assert ~c)) pre) body) body)] (if (every? symbol? params) @@ -3780,7 +3782,7 @@ [fmt & args] (print (apply format fmt args))) -(def gen-class) +(declare gen-class) (defmacro with-loading-context [& body] `((fn loading# [] @@ -3912,7 +3914,7 @@ (let [d (root-resource lib)] (subs d 0 (.lastIndexOf d "/")))) -(def load) +(declare load) (defn- load-one "Loads a lib given its name. If need-ns, ensures that the associated @@ -4187,10 +4189,6 @@ #^{:doc "bound in a repl thread to the most recent exception caught by the repl"} *e) -(defmacro declare - "defs the supplied var names with no bindings, useful for making forward declarations." - [& names] `(do ~@(map #(list 'def %) names))) - (defn trampoline "trampoline can be used to convert algorithms requiring mutual recursion without stack consumption. Calls f with supplied args, if diff --git a/src/clj/clojure/test.clj b/src/clj/clojure/test.clj index 0d7c4600..5e432899 100644 --- a/src/clj/clojure/test.clj +++ b/src/clj/clojure/test.clj @@ -544,7 +544,8 @@ Chas Emerick, Allen Rohner, and Stuart Halloway", 'is' call 'report' to indicate results. The argument given to 'report' will be a map with a :type key. See the documentation at the top of test_is.clj for more information on the types of - arguments for 'report'."} + arguments for 'report'." + :dynamic true} report :type) (defmethod report :default [m] diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index b1096704..060ce4d6 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -187,6 +187,9 @@ static final public Var KEYWORD_CALLSITES = Var.create(); //vector<var> static final public Var PROTOCOL_CALLSITES = Var.create(); +//vector<var> +static final public Var VAR_CALLSITES = Var.create(); + //keyword->constid static final public Var KEYWORDS = Var.create(); @@ -2734,11 +2737,13 @@ static class InvokeExpr implements Expr{ public final int line; public final String source; public boolean isProtocol = false; - public int siteIndex = 0; + public boolean isDirect = false; + public int siteIndex = -1; public Class protocolOn; public java.lang.reflect.Method onMethod; static Keyword onKey = Keyword.intern("on"); static Keyword methodMapKey = Keyword.intern("method-map"); + static Keyword dynamicKey = Keyword.intern("dynamic"); public InvokeExpr(String source, int line, Symbol tag, Expr fexpr, IPersistentVector args) throws Exception{ this.source = source; @@ -2767,6 +2772,17 @@ static class InvokeExpr implements Expr{ this.onMethod = (java.lang.reflect.Method) methods.get(0); } } + else if(pvar == null && VAR_CALLSITES.isBound() + && fvar.ns.name.name.startsWith("clojure") + && !RT.booleanCast(RT.get(RT.meta(fvar),dynamicKey)) +// && !fvar.sym.name.equals("report") +// && fvar.isBound() && fvar.get() instanceof IFn + ) + { + //todo - more specific criteria for binding these + this.isDirect = true; + this.siteIndex = registerVarCallsite(((VarExpr) fexpr).var); + } } this.tag = tag != null ? tag : (fexpr instanceof VarExpr ? ((VarExpr) fexpr).tag : null); } @@ -2795,6 +2811,23 @@ static class InvokeExpr implements Expr{ { emitProto(context,objx,gen); } + else if(isDirect) + { + Label callLabel = gen.newLabel(); + + gen.getStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE); + gen.dup(); + gen.ifNonNull(callLabel); + + gen.pop(); + fexpr.emit(C.EXPRESSION, objx, gen); + gen.checkCast(IFN_TYPE); +// gen.dup(); +// gen.putStatic(objx.objtype, objx.varCallsiteName(siteIndex), IFN_TYPE); + + gen.mark(callLabel); + emitArgsAndCall(0, context,objx,gen); + } else { fexpr.emit(C.EXPRESSION, objx, gen); @@ -3044,7 +3077,9 @@ static public class FnExpr extends ObjExpr{ KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, - PROTOCOL_CALLSITES, PersistentVector.EMPTY)); + PROTOCOL_CALLSITES, PersistentVector.EMPTY, + VAR_CALLSITES, PersistentVector.EMPTY + )); //arglist might be preceded by symbol naming this fn if(RT.second(form) instanceof Symbol) @@ -3097,6 +3132,7 @@ static public class FnExpr extends ObjExpr{ fn.constants = (PersistentVector) CONSTANTS.deref(); fn.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); fn.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); + fn.varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); fn.constantsID = RT.nextID(); // DynamicClassLoader loader = (DynamicClassLoader) LOADER.get(); @@ -3153,6 +3189,7 @@ static public class ObjExpr implements Expr{ IPersistentVector keywordCallsites; IPersistentVector protocolCallsites; + IPersistentVector varCallsites; final static Method voidctor = Method.getMethod("void <init>()"); @@ -3318,6 +3355,12 @@ static public class ObjExpr implements Expr{ null, null); } + for(int i=0;i<varCallsites.count();i++) + { + cv.visitField(ACC_PRIVATE + ACC_STATIC + ACC_FINAL + , varCallsiteName(i), IFN_TYPE.getDescriptor(), null, null); + } + //static init for constants, keywords and vars GeneratorAdapter clinitgen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, Method.getMethod("void <clinit> ()"), @@ -3335,6 +3378,29 @@ static public class ObjExpr implements Expr{ if(keywordCallsites.count() > 0) emitKeywordCallsites(clinitgen); + for(int i=0;i<varCallsites.count();i++) + { + Label skipLabel = clinitgen.newLabel(); + Label endLabel = clinitgen.newLabel(); + Var var = (Var) varCallsites.nth(i); + clinitgen.push(var.ns.name.toString()); + clinitgen.push(var.sym.toString()); + clinitgen.invokeStatic(RT_TYPE, Method.getMethod("clojure.lang.Var var(String,String)")); + clinitgen.dup(); + clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("boolean hasRoot()")); + clinitgen.ifZCmp(GeneratorAdapter.EQ,skipLabel); + + clinitgen.invokeVirtual(VAR_TYPE,Method.getMethod("Object getRoot()")); + clinitgen.checkCast(IFN_TYPE); + clinitgen.putStatic(objtype, varCallsiteName(i), IFN_TYPE); + clinitgen.goTo(endLabel); + + clinitgen.mark(skipLabel); + clinitgen.pop(); + + clinitgen.mark(endLabel); + } + clinitgen.returnValue(); clinitgen.endMethod(); @@ -3374,11 +3440,6 @@ static public class ObjExpr implements Expr{ cv.visitField(ACC_PRIVATE, cachedProtoFnName(i), AFUNCTION_TYPE.getDescriptor(), null, null); cv.visitField(ACC_PRIVATE, cachedProtoImplName(i), IFN_TYPE.getDescriptor(), null, null); } - for(int i=0;i<keywordCallsites.count();i++) - { -// cv.visitField(ACC_FINAL, siteName(i), ILOOKUP_SITE_TYPE.getDescriptor(), null, null); -// cv.visitField(ACC_PUBLIC, thunkName(i), ILOOKUP_THUNK_TYPE.getDescriptor(), null, null); - } //ctor that takes closed-overs and inits base + fields Method m = new Method("<init>", Type.VOID_TYPE, ctorTypes()); @@ -3422,17 +3483,7 @@ static public class ObjExpr implements Expr{ } } - //copy static sites into instance site and thunk - for(int i=0;i<keywordCallsites.count();i++) - { -// ctorgen.loadThis(); -// ctorgen.getStatic(objtype,siteNameStatic(i),KEYWORD_LOOKUPSITE_TYPE); -// ctorgen.putField(objtype, siteName(i),ILOOKUP_SITE_TYPE); -// ctorgen.loadThis(); -// ctorgen.getStatic(objtype,siteNameStatic(i),KEYWORD_LOOKUPSITE_TYPE); -// ctorgen.putField(objtype, thunkName(i),ILOOKUP_THUNK_TYPE); - } - + ctorgen.visitLabel(end); ctorgen.returnValue(); @@ -3924,6 +3975,10 @@ static public class ObjExpr implements Expr{ return "__cached_proto_impl__" + n; } + String varCallsiteName(int n){ + return "__var__callsite__" + n; + } + String thunkNameStatic(int n){ return thunkName(n) + "__"; } @@ -5087,7 +5142,7 @@ private static KeywordExpr registerKeyword(Keyword keyword){ private static int registerKeywordCallsite(Keyword keyword){ if(!KEYWORD_CALLSITES.isBound()) - throw new IllegalAccessError(); + throw new IllegalAccessError("KEYWORD_CALLSITES is not bound"); IPersistentVector keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); @@ -5098,7 +5153,7 @@ private static int registerKeywordCallsite(Keyword keyword){ private static int registerProtocolCallsite(Var v){ if(!PROTOCOL_CALLSITES.isBound()) - throw new IllegalAccessError(); + throw new IllegalAccessError("PROTOCOL_CALLSITES is not bound"); IPersistentVector protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); @@ -5107,6 +5162,18 @@ private static int registerProtocolCallsite(Var v){ return protocolCallsites.count()-1; } +private static int registerVarCallsite(Var v){ + if(!VAR_CALLSITES.isBound()) + throw new IllegalAccessError("VAR_CALLSITES is not bound"); + + IPersistentVector varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); + + varCallsites = varCallsites.cons(v); + VAR_CALLSITES.set(varCallsites); + return varCallsites.count()-1; +} + + private static Expr analyzeSymbol(Symbol sym) throws Exception{ Symbol tag = tagOf(sym); if(sym.ns == null) //ns-qualified syms are always Vars @@ -5390,6 +5457,10 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) thro RT.map(LOADER, RT.makeClassLoader(), SOURCE_PATH, sourcePath, SOURCE, sourceName, + METHOD, null, + LOCAL_ENV, null, + LOOP_LOCALS, null, + NEXT_LOCAL_NUM, 0, RT.CURRENT_NS, RT.CURRENT_NS.deref(), LINE_BEFORE, pushbackReader.getLineNumber(), LINE_AFTER, pushbackReader.getLineNumber() @@ -5496,6 +5567,10 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t Var.pushThreadBindings( RT.map(SOURCE_PATH, sourcePath, SOURCE, sourceName, + METHOD, null, + LOCAL_ENV, null, + LOOP_LOCALS, null, + NEXT_LOCAL_NUM, 0, RT.CURRENT_NS, RT.CURRENT_NS.deref(), LINE_BEFORE, pushbackReader.getLineNumber(), LINE_AFTER, pushbackReader.getLineNumber(), @@ -5724,7 +5799,8 @@ static public class NewInstanceExpr extends ObjExpr{ KEYWORDS, PersistentHashMap.EMPTY, VARS, PersistentHashMap.EMPTY, KEYWORD_CALLSITES, PersistentVector.EMPTY, - PROTOCOL_CALLSITES, PersistentVector.EMPTY + PROTOCOL_CALLSITES, PersistentVector.EMPTY, + VAR_CALLSITES, PersistentVector.EMPTY )); if(ret.isDeftype()) { @@ -5751,6 +5827,7 @@ static public class NewInstanceExpr extends ObjExpr{ ret.constantsID = RT.nextID(); ret.keywordCallsites = (IPersistentVector) KEYWORD_CALLSITES.deref(); ret.protocolCallsites = (IPersistentVector) PROTOCOL_CALLSITES.deref(); + ret.varCallsites = (IPersistentVector) VAR_CALLSITES.deref(); } finally { |