summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2009-11-24 07:51:02 -0500
committerRich Hickey <richhickey@gmail.com>2009-11-24 07:51:02 -0500
commit4d08439a9cf79f34a730714f12edd5959aae126e (patch)
treec4bf543bd53832cf17a35c786705c14147c3b41a
parent98366f353463afdc195b9b8fdf9d220bca7d0d6a (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.clj26
-rw-r--r--src/clj/clojure/test.clj3
-rw-r--r--src/jvm/clojure/lang/Compiler.java119
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
{