diff options
author | Rich Hickey <richhickey@gmail.com> | 2010-02-16 11:23:42 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2010-02-16 11:23:42 -0500 |
commit | 23f612edadfd629315c68d8962eaf86ee177d687 (patch) | |
tree | b12d53b83cb32c0a00920206359c3d2c6166916c | |
parent | 61202d2ff6925002400a9843e8fbd080f3bef3a5 (diff) |
added :volatile-mutable and :unsynchronized-mutable options to deftype fields
-rw-r--r-- | src/clj/clojure/core_deftype.clj | 20 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 25 |
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(), |