Created
November 22, 2013 16:03
-
-
Save tobias/7602270 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| commit 7d4a8f4724ea8f82709550d8a55798c87bfab802 (HEAD, refs/heads/clj-1299-no-nil) | |
| Author: Toby Crawley <toby@tcrawley.org> | |
| Date: Fri Nov 22 09:49:44 2013 -0500 | |
| Prevent a conveyed binding frame from being removed by a popThreadBindings call [CLJ-1299] | |
| This introduces a TOP frame that is used to mark the top of a | |
| push/pop stack. It also removes unnecessary nil checks around dvals. | |
| Modified src/jvm/clojure/lang/Var.java | |
| diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java | |
| index 7463337..af942f6 100644 | |
| --- a/src/jvm/clojure/lang/Var.java | |
| +++ b/src/jvm/clojure/lang/Var.java | |
| @@ -45,17 +45,13 @@ static public class Unbound extends AFn{ | |
| } | |
| static class Frame{ | |
| + final static Frame TOP = new Frame(PersistentHashMap.EMPTY, null); | |
| //Var->TBox | |
| Associative bindings; | |
| //Var->val | |
| // Associative frameBindings; | |
| Frame prev; | |
| - | |
| - public Frame(){ | |
| - this(PersistentHashMap.EMPTY, null); | |
| - } | |
| - | |
| public Frame(Associative bindings, Frame prev){ | |
| // this.frameBindings = frameBindings; | |
| this.bindings = bindings; | |
| @@ -63,9 +59,7 @@ static class Frame{ | |
| } | |
| protected Object clone() { | |
| - Frame f = new Frame(); | |
| - f.bindings = this.bindings; | |
| - return f; | |
| + return new Frame(this.bindings, null); | |
| } | |
| } | |
| @@ -73,7 +67,7 @@ static class Frame{ | |
| static final ThreadLocal<Frame> dvals = new ThreadLocal<Frame>(){ | |
| protected Frame initialValue(){ | |
| - return new Frame(); | |
| + return Frame.TOP; | |
| } | |
| }; | |
| @@ -96,17 +90,11 @@ public final Namespace ns; | |
| //IPersistentMap _meta; | |
| public static Object getThreadBindingFrame(){ | |
| - Frame f = dvals.get(); | |
| - if(f != null) | |
| - return f; | |
| - return new Frame(); | |
| + return dvals.get(); | |
| } | |
| public static Object cloneThreadBindingFrame(){ | |
| - Frame f = dvals.get(); | |
| - if(f != null) | |
| - return f.clone(); | |
| - return new Frame(); | |
| + return dvals.get().clone(); | |
| } | |
| public static void resetThreadBindingFrame(Object frame){ | |
| @@ -359,11 +347,10 @@ public static void pushThreadBindings(Associative bindings){ | |
| } | |
| public static void popThreadBindings(){ | |
| - Frame f = dvals.get(); | |
| - if(f.prev == null) | |
| + Frame f = dvals.get().prev; | |
| + if (f == null) { | |
| throw new IllegalStateException("Pop without matching push"); | |
| - f = f.prev; | |
| - if (f.prev == null) { | |
| + } else if (f == Frame.TOP) { | |
| dvals.remove(); | |
| } else { | |
| dvals.set(f); | |
| Modified test/clojure/test_clojure/parallel.clj | |
| diff --git a/test/clojure/test_clojure/parallel.clj b/test/clojure/test_clojure/parallel.clj | |
| index fb98d60..357e961 100644 | |
| --- a/test/clojure/test_clojure/parallel.clj | |
| +++ b/test/clojure/test_clojure/parallel.clj | |
| @@ -27,3 +27,14 @@ | |
| ;; regression fixed in r1218; was OutOfMemoryError | |
| (is (= '(1) (pmap inc [0])))) | |
| + | |
| +(def ^:dynamic *test-value* 1) | |
| + | |
| +(deftest future-fn-properly-retains-conveyed-bindings | |
| + (let [a (atom [])] | |
| + (binding [*test-value* 2] | |
| + @(future (dotimes [_ 3] | |
| + ;; we need some binding to trigger binding pop | |
| + (binding [*print-dup* false] | |
| + (swap! a conj *test-value*)))) | |
| + (is (= [2 2 2] @a))))) | |
| [back] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment