diff options
author | Rich Hickey <richhickey@gmail.com> | 2007-08-18 20:09:06 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2007-08-18 20:09:06 +0000 |
commit | 35e67dc6215ab3be205b1b95d7ffe7a235cedd8f (patch) | |
tree | 423275a92e53eb1601ac3a29bb6f9e08d713e02e /src | |
parent | 8b21472e502732159b4d2e3fa20b25089cfd9c79 (diff) |
revising DynamicVar, now push and pop sets of bindings, single ThreadLocal
Diffstat (limited to 'src')
-rw-r--r-- | src/jvm/clojure/lang/Binding.java | 8 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 55 | ||||
-rw-r--r-- | src/jvm/clojure/lang/DynamicVar.java | 93 |
3 files changed, 91 insertions, 65 deletions
diff --git a/src/jvm/clojure/lang/Binding.java b/src/jvm/clojure/lang/Binding.java index f36c78d3..8cdb1891 100644 --- a/src/jvm/clojure/lang/Binding.java +++ b/src/jvm/clojure/lang/Binding.java @@ -10,16 +10,16 @@ package clojure.lang;
-public class Binding{
-public Object val;
+public class Binding<T>{
+public T val;
public final Binding rest;
-public Binding(Object val){
+public Binding(T val){
this.val = val;
this.rest = null;
}
-public Binding(Object val, Binding rest){
+public Binding(T val, Binding rest){
this.val = val;
this.rest = rest;
}
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 56c5579d..e9c4fe87 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -99,12 +99,14 @@ static String compile(String ns, String className, LineNumberingPushbackReader.. StringWriter w = new StringWriter(); try { - _CRT_OUT.pushThreadBinding(w); - KEYWORDS.pushThreadBinding(null); - VARS.pushThreadBinding(null); - METHOD.pushThreadBinding(null); - LOCAL_ENV.pushThreadBinding(null); - FNS.pushThreadBinding(PersistentVector.EMPTY); + DynamicVar.pushThreadBindings( + RT.map( + _CRT_OUT, w, + KEYWORDS, null, + VARS, null, + METHOD, null, + LOCAL_ENV, null, + FNS, PersistentVector.EMPTY)); format("/* Generated by Clojure */~%~%"); format("package ~A;~%", ns); @@ -116,8 +118,10 @@ static String compile(String ns, String className, LineNumberingPushbackReader.. { try { - IMPORTS.pushThreadBinding(null); - USES.pushThreadBinding(null); + DynamicVar.pushThreadBindings( + RT.map( + IMPORTS, null, + USES, null)); Object eof = new Object(); Object form = null; @@ -155,8 +159,7 @@ static String compile(String ns, String className, LineNumberingPushbackReader.. } finally { - IMPORTS.popThreadBinding(); - USES.popThreadBinding(); + DynamicVar.popThreadBindings(); } } //declare static members for keywords, vars @@ -213,12 +216,7 @@ static String compile(String ns, String className, LineNumberingPushbackReader.. } finally { - _CRT_OUT.popThreadBinding(); - KEYWORDS.popThreadBinding(); - VARS.popThreadBinding(); - METHOD.popThreadBinding(); - LOCAL_ENV.popThreadBinding(); - FNS.popThreadBinding(); + DynamicVar.popThreadBindings(); } return w.toString(); } @@ -285,13 +283,13 @@ static class AnExpr implements Expr{ StringWriter w = new StringWriter(); try { - _CRT_OUT.pushThreadBinding(w); + DynamicVar.pushThreadBindings(RT.map(_CRT_OUT, w)); emitExpression(); return w.toString(); } finally { - _CRT_OUT.popThreadBinding(); + DynamicVar.popThreadBindings(); } } @@ -793,7 +791,7 @@ private static Expr analyzeLet(C context, ISeq form) throws Exception{ } try { - LOCAL_ENV.pushThreadBinding(LOCAL_ENV.get()); + DynamicVar.pushThreadBindings(RT.map(LOCAL_ENV, LOCAL_ENV.get())); for(int i = 0; i < bindingInits.count(); i++) { BindingInit bi = (BindingInit) bindingInits.nth(i); @@ -808,7 +806,7 @@ private static Expr analyzeLet(C context, ISeq form) throws Exception{ } finally { - LOCAL_ENV.popThreadBinding(); + DynamicVar.popThreadBindings(); } } @@ -819,7 +817,7 @@ private static Expr analyzeLetFn(C context, ISeq form) throws Exception{ return analyze(context, RT.list(RT.list(FN, null, form))); try { - LOCAL_ENV.pushThreadBinding(LOCAL_ENV.get()); + DynamicVar.pushThreadBindings(RT.map(LOCAL_ENV, LOCAL_ENV.get())); ISeq bindings = (ISeq) RT.second(form); ISeq body = RT.rest(RT.rest(form)); PersistentVector bindingPairs = PersistentVector.EMPTY; @@ -848,7 +846,7 @@ private static Expr analyzeLetFn(C context, ISeq form) throws Exception{ } finally { - LOCAL_ENV.popThreadBinding(); + DynamicVar.popThreadBindings(); } } @@ -866,7 +864,7 @@ private static Expr analyzeLetStar(C context, ISeq form) throws Exception{ try { - LOCAL_ENV.pushThreadBinding(LOCAL_ENV.get()); + DynamicVar.pushThreadBindings(RT.map(LOCAL_ENV, LOCAL_ENV.get())); PersistentVector bindingInits = PersistentVector.EMPTY; for(ISeq bs = bindings; bs != null; bs = RT.rest(RT.rest(bs))) { @@ -887,7 +885,7 @@ private static Expr analyzeLetStar(C context, ISeq form) throws Exception{ } finally { - LOCAL_ENV.popThreadBinding(); + DynamicVar.popThreadBindings(); } } @@ -1411,8 +1409,10 @@ private static FnMethod analyzeMethod(FnExpr fn, ISeq form) throws Exception{ try { FnMethod method = new FnMethod(fn, (FnMethod) METHOD.get()); - METHOD.pushThreadBinding(method); - LOCAL_ENV.pushThreadBinding(LOCAL_ENV.get()); + DynamicVar.pushThreadBindings( + RT.map( + METHOD, method, + LOCAL_ENV, LOCAL_ENV.get())); PSTATE state = PSTATE.REQ; for(ISeq ps = parms; ps != null; ps = ps.rest()) { @@ -1467,8 +1467,7 @@ private static FnMethod analyzeMethod(FnExpr fn, ISeq form) throws Exception{ } finally { - METHOD.popThreadBinding(); - LOCAL_ENV.popThreadBinding(); + DynamicVar.popThreadBindings(); } } diff --git a/src/jvm/clojure/lang/DynamicVar.java b/src/jvm/clojure/lang/DynamicVar.java index 29be9b81..8e04f589 100644 --- a/src/jvm/clojure/lang/DynamicVar.java +++ b/src/jvm/clojure/lang/DynamicVar.java @@ -15,8 +15,33 @@ package clojure.lang; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; + public class DynamicVar implements IFn{ -volatile InheritableThreadLocal<Binding> dvals; + +static class Frame{ + Associative bmap; + Associative bindings; + Frame prev; + + + public Frame(){ + this(PersistentHashMap.EMPTY, PersistentHashMap.EMPTY, null); + } + + public Frame(Associative bindings, Associative bmap, Frame prev){ + this.bindings = bindings; + this.bmap = bmap; + this.prev = prev; + } +} + +static InheritableThreadLocal<Frame> dvals = new InheritableThreadLocal<Frame>(){ + + protected Frame initialValue(){ + return new Frame(); + } +}; + Object root; final AtomicInteger count; final Symbol sym; @@ -37,14 +62,8 @@ public static DynamicVar intern(Symbol sym, Object root, boolean replaceRoot){ dvout = table.putIfAbsent(sym, dvin); present = dvout != dvin; //might have snuck in } - if(present) - { - synchronized(dvout) - { - if(dvout.root == dvout.dvals || replaceRoot) - dvout.setRoot(root); - } - } + if(present && (dvout.root == dvout.count || replaceRoot)) + dvout.bindRoot(root); return dvout; } @@ -73,7 +92,6 @@ public static DynamicVar create(Object root){ } private DynamicVar(Symbol sym){ - this.dvals = null; this.sym = sym; this.count = new AtomicInteger(); this.root = count; //use count as magic not-bound value @@ -85,11 +103,11 @@ private DynamicVar(Symbol sym, Object root){ } public boolean isBound(){ - return root != count || dvals.get() != null; + return root != count || dvals.get().bmap.contains(this); } final public Object get(){ - Binding b = getThreadBinding(); + Box b = getThreadBinding(); if(b != null) return b.val; if(root != count) @@ -98,48 +116,57 @@ final public Object get(){ } public Object set(Object val){ - Binding b = getThreadBinding(); + Box b = getThreadBinding(); if(b != null) return (b.val = val); //can't establish root binding with set, but can change it if(root != count) return root = val; - throw new IllegalStateException(String.format("Var %s has no binding in this thread.", sym)); + throw new IllegalStateException(String.format("Var %s is unbound.", sym)); } public Object getRoot(){ return root; } -public DynamicVar setRoot(Object root){ +public DynamicVar bindRoot(Object root){ this.root = root; return this; } -public void pushThreadBinding(Object val){ - if(dvals == null) +public static void pushThreadBindings(Associative bindings){ + Frame f = dvals.get(); + Associative bmap = f.bmap; + for(ISeq bs = bindings.seq(); bs != null; bs = bs.rest()) { - synchronized(this) - { - if(dvals == null) - dvals = new InheritableThreadLocal<Binding>(); - } + IMapEntry e = (IMapEntry) bs.first(); + DynamicVar v = (DynamicVar) e.key(); + v.count.incrementAndGet(); + bmap = bmap.assoc(v, new Box(e.val())); } - dvals.set(new Binding(val, dvals.get())); - count.incrementAndGet(); + dvals.set(new Frame(bindings, bmap, f)); } -public void popThreadBinding(){ - Binding b; - if(dvals == null || (b = dvals.get()) == null) - throw new IllegalStateException(String.format("Var %s has no binding in this thread.", sym)); - dvals.set(b.rest); - count.decrementAndGet(); +public static void popThreadBindings(){ + Frame f = dvals.get(); + if(f.prev == null) + throw new IllegalStateException("Pop without matching push"); + for(ISeq bs = f.bindings.seq(); bs != null; bs = bs.rest()) + { + IMapEntry e = (IMapEntry) bs.first(); + DynamicVar v = (DynamicVar) e.key(); + v.count.decrementAndGet(); + } + dvals.set(f.prev); } -final Binding getThreadBinding(){ - if(dvals != null && count.get() > 0) - return dvals.get(); +final Box getThreadBinding(){ + if(count.get() > 0) + { + IMapEntry e = dvals.get().bmap.entryAt(this); + if(e != null) + return (Box) e.val(); + } return null; } |