summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2007-08-18 20:09:06 +0000
committerRich Hickey <richhickey@gmail.com>2007-08-18 20:09:06 +0000
commit35e67dc6215ab3be205b1b95d7ffe7a235cedd8f (patch)
tree423275a92e53eb1601ac3a29bb6f9e08d713e02e /src
parent8b21472e502732159b4d2e3fa20b25089cfd9c79 (diff)
revising DynamicVar, now push and pop sets of bindings, single ThreadLocal
Diffstat (limited to 'src')
-rw-r--r--src/jvm/clojure/lang/Binding.java8
-rw-r--r--src/jvm/clojure/lang/Compiler.java55
-rw-r--r--src/jvm/clojure/lang/DynamicVar.java93
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;
}