summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2010-02-16 11:23:42 -0500
committerRich Hickey <richhickey@gmail.com>2010-02-16 11:23:42 -0500
commit23f612edadfd629315c68d8962eaf86ee177d687 (patch)
treeb12d53b83cb32c0a00920206359c3d2c6166916c
parent61202d2ff6925002400a9843e8fbd080f3bef3a5 (diff)
added :volatile-mutable and :unsynchronized-mutable options to deftype fields
-rw-r--r--src/clj/clojure/core_deftype.clj20
-rw-r--r--src/jvm/clojure/lang/Compiler.java25
2 files changed, 32 insertions, 13 deletions
diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index b3b7eef6..0e721361 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -231,12 +231,20 @@
by a metadata map (nil for none) and an extension field map (nil for
none).
- The class will have the (immutable) fields named by fields, which
- can have type hints. Protocols/interfaces and methods are
- optional. The only methods that can be supplied are those declared
- in the protocols/interfaces. Note that method bodies are not
- closures, the local environment includes only the named fields, and
- those fields can be accessed directy.
+ The class will have the (by default, immutable) fields named by
+ fields, which can have type hints. Protocols/interfaces and methods
+ are optional. The only methods that can be supplied are those
+ declared in the protocols/interfaces. Note that method bodies are
+ not closures, the local environment includes only the named fields,
+ and those fields can be accessed directy. Fields can be qualified
+ with the metadata :volatile-mutable true or :unsynchronized-mutable
+ true, at which point (set! afield aval) will be supported in method
+ bodies. Note well that mutable fields are extremely difficult to use
+ correctly, and are present only to facilitate the building of higher
+ level constructs, such as Clojure's reference types, in Clojure
+ itself. They are for experts only - if the semantics and
+ implications of :volatile-mutable or :unsynchronized-mutable are not
+ immediately apparent to you, you should not be using them.
Method definitions take the form:
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index 158f1748..881379c4 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -3476,7 +3476,9 @@ static public class ObjExpr implements Expr{
LocalBinding lb = (LocalBinding) s.first();
if(isDeftype())
{
- int access = isVolatile(lb) ? ACC_VOLATILE : (ACC_PUBLIC + ACC_FINAL);
+ int access = isVolatile(lb) ? ACC_VOLATILE :
+ isMutable(lb) ? 0 :
+ (ACC_PUBLIC + ACC_FINAL);
if(lb.getPrimitiveType() != null)
cv.visitField(access
, lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),
@@ -3897,8 +3899,15 @@ static public class ObjExpr implements Expr{
}
}
+ boolean isMutable(LocalBinding lb){
+ return isVolatile(lb) ||
+ RT.booleanCast(RT.contains(fields, lb.sym)) &&
+ RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("unsynchronized-mutable")));
+ }
+
boolean isVolatile(LocalBinding lb){
- return closes.containsKey(lb) && volatiles.contains(lb.sym);
+ return RT.booleanCast(RT.contains(fields, lb.sym)) &&
+ RT.booleanCast(RT.get(lb.sym.meta(), Keyword.intern("volatile-mutable")));
}
boolean isDeftype(){
@@ -4009,15 +4018,15 @@ static public class ObjExpr implements Expr{
}
public void emitAssignLocal(GeneratorAdapter gen, LocalBinding lb,Expr val){
- if(!isVolatile(lb))
- throw new IllegalArgumentException("Cannot assign to non-volatile: " + lb.name);
+ if(!isMutable(lb))
+ throw new IllegalArgumentException("Cannot assign to non-mutable: " + lb.name);
Class primc = lb.getPrimitiveType();
gen.loadThis();
if(primc != null)
{
+ if(!(val instanceof MaybePrimitiveExpr && ((MaybePrimitiveExpr) val).canEmitPrimitive()))
+ throw new IllegalArgumentException("Must assign primitive to primitive mutable: " + lb.name);
MaybePrimitiveExpr me = (MaybePrimitiveExpr) val;
- if(!me.canEmitPrimitive())
- throw new IllegalArgumentException("Must assign primitive to primitive volatile: " + lb.name);
me.emitUnboxed(C.EXPRESSION, this, gen);
gen.putField(objtype, lb.name, Type.getType(primc));
}
@@ -6136,7 +6145,9 @@ static public class NewInstanceExpr extends ObjExpr{
for(ISeq s = RT.keys(ret.closes); s != null; s = s.next())
{
LocalBinding lb = (LocalBinding) s.first();
- int access = ACC_PUBLIC + (ret.isVolatile(lb) ? ACC_VOLATILE : ACC_FINAL);
+ int access = ACC_PUBLIC + (ret.isVolatile(lb) ? ACC_VOLATILE :
+ ret.isMutable(lb) ? 0 :
+ ACC_FINAL);
if(lb.getPrimitiveType() != null)
cv.visitField(access
, lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),