Skip to content

Commit

Permalink
initial annotation support, for definterface/type/record types (put i…
Browse files Browse the repository at this point in the history
…n metadata on type name), deftype/record fields (in metadata on field names), and deftype/record methods (in metadata on method name)
  • Loading branch information
richhickey committed Apr 23, 2010
1 parent 5916e9e commit fa899d2
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 7 deletions.
51 changes: 51 additions & 0 deletions src/clj/clojure/core.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -3803,6 +3803,57 @@
"Returns true if x is an instance of Class" "Returns true if x is an instance of Class"
[x] (instance? Class x)) [x] (instance? Class x))


(defn- is-annotation? [c]
(and (class? c)
(.isAssignableFrom java.lang.annotation.Annotation c)))

(defn- is-runtime-annotation? [#^Class c]
(boolean
(and (is-annotation? c)
(when-let [#^java.lang.annotation.Retention r
(.getAnnotation c java.lang.annotation.Retention)]
(= (.value r) java.lang.annotation.RetentionPolicy/RUNTIME)))))

(defn- descriptor [#^Class c] (clojure.asm.Type/getDescriptor c))

(declare process-annotation)
(defn- add-annotation [#^clojure.asm.AnnotationVisitor av name v]
(cond
(vector? v) (let [avec (.visitArray av name)]
(doseq [vval v]
(add-annotation avec "value" vval))
(.visitEnd avec))
(symbol? v) (let [ev (eval v)]
(cond
(instance? java.lang.Enum ev)
(.visitEnum av name (descriptor (class ev)) (str ev))
(class? ev) (.visit av name (clojure.asm.Type/getType ev))
:else (throw (IllegalArgumentException.
(str "Unsupported annotation value: " v " of class " (class ev))))))
(seq? v) (let [[nested nv] v
c (resolve nested)
nav (.visitAnnotation av name (descriptor c))]
(process-annotation nav nv)
(.visitEnd nav))
:else (.visit av name v)))

(defn- process-annotation [av v]
(if (map? v)
(doseq [[k v] v]
(add-annotation av (name k) v))
(add-annotation av "value" v)))

(defn- add-annotations [visitor m]
(doseq [[k v] m]
(when (symbol? k)
(when-let [c (resolve k)]
(when (is-annotation? c)
;this is known duck/reflective as no common base of ASM Visitors
(let [av (.visitAnnotation visitor (descriptor c)
(is-runtime-annotation? c))]
(process-annotation av v)
(.visitEnd av)))))))

(defn alter-var-root (defn alter-var-root
"Atomically alters the root binding of var v by applying f to its "Atomically alters the root binding of var v by applying f to its
current value plus any args" current value plus any args"
Expand Down
1 change: 1 addition & 0 deletions src/clj/clojure/genclass.clj
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -621,6 +621,7 @@
iname nil "java/lang/Object" iname nil "java/lang/Object"
(when (seq extends) (when (seq extends)
(into-array (map #(.getInternalName (asm-type %)) extends)))) (into-array (map #(.getInternalName (asm-type %)) extends))))
(add-annotations cv (meta name))
(doseq [[mname pclasses rclass] methods] (doseq [[mname pclasses rclass] methods]
(. cv visitMethod (+ Opcodes/ACC_PUBLIC Opcodes/ACC_ABSTRACT) (. cv visitMethod (+ Opcodes/ACC_PUBLIC Opcodes/ACC_ABSTRACT)
(str mname) (str mname)
Expand Down
35 changes: 28 additions & 7 deletions src/jvm/clojure/lang/Compiler.java
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -226,6 +226,9 @@ public class Compiler implements Opcodes{
static final public Var INSTANCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")), static final public Var INSTANCE = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
Symbol.create("instance?")); Symbol.create("instance?"));


static final public Var ADD_ANNOTATIONS = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
Symbol.create("add-annotations"));

//Integer //Integer
static final public Var LINE = Var.create(0); static final public Var LINE = Var.create(0);


Expand Down Expand Up @@ -3208,6 +3211,7 @@ static public class ObjExpr implements Expr{
Object src; Object src;


final static Method voidctor = Method.getMethod("void <init>()"); final static Method voidctor = Method.getMethod("void <init>()");
protected IPersistentMap classMeta;


public final String name(){ public final String name(){
return name; return name;
Expand Down Expand Up @@ -3350,7 +3354,7 @@ void compile(String superName, String[] interfaceNames, boolean oneTimeUse) thro
"*E"; "*E";
cv.visitSource(source, smap); cv.visitSource(source, smap);
} }

addAnnotation(cv, classMeta);
//static fields for constants //static fields for constants
for(int i = 0; i < constants.count(); i++) for(int i = 0; i < constants.count(); i++)
{ {
Expand Down Expand Up @@ -3434,14 +3438,16 @@ void compile(String superName, String[] interfaceNames, boolean oneTimeUse) thro
int access = isVolatile(lb) ? ACC_VOLATILE : int access = isVolatile(lb) ? ACC_VOLATILE :
isMutable(lb) ? 0 : isMutable(lb) ? 0 :
(ACC_PUBLIC + ACC_FINAL); (ACC_PUBLIC + ACC_FINAL);
FieldVisitor fv;
if(lb.getPrimitiveType() != null) if(lb.getPrimitiveType() != null)
cv.visitField(access fv = cv.visitField(access
, lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(), , lb.name, Type.getType(lb.getPrimitiveType()).getDescriptor(),
null, null); null, null);
else else
//todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal? //todo - when closed-overs are fields, use more specific types here and in ctor and emitLocal?
cv.visitField(access fv = cv.visitField(access
, lb.name, OBJECT_TYPE.getDescriptor(), null, null); , lb.name, OBJECT_TYPE.getDescriptor(), null, null);
addAnnotation(fv, RT.meta(lb.sym));
} }
else else
{ {
Expand Down Expand Up @@ -4336,6 +4342,7 @@ abstract public static class ObjMethod{
int maxLocal = 0; int maxLocal = 0;
int line; int line;
PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY; PersistentHashSet localsUsedInCatchFinally = PersistentHashSet.EMPTY;
protected IPersistentMap methodMeta;


public final IPersistentMap locals(){ public final IPersistentMap locals(){
return locals; return locals;
Expand Down Expand Up @@ -5432,6 +5439,17 @@ static PathNode commonPath(PathNode n1, PathNode n2){
return (PathNode) RT.first(xp); return (PathNode) RT.first(xp);
} }


static void addAnnotation(Object visitor, IPersistentMap meta){
try{
if(ADD_ANNOTATIONS.isBound())
ADD_ANNOTATIONS.invoke(visitor, meta);
}
catch (Exception e)
{
throw new RuntimeException(e);
}
}

private static Expr analyzeSymbol(Symbol sym) throws Exception{ private static Expr analyzeSymbol(Symbol sym) throws Exception{
Symbol tag = tagOf(sym); Symbol tag = tagOf(sym);
if(sym.ns == null) //ns-qualified syms are always Vars if(sym.ns == null) //ns-qualified syms are always Vars
Expand Down Expand Up @@ -5949,7 +5967,7 @@ public Expr parse(C context, final Object frm) throws Exception{
rform = RT.next(rform); rform = RT.next(rform);
String tagname = ((Symbol) rform.first()).toString(); String tagname = ((Symbol) rform.first()).toString();
rform = rform.next(); rform = rform.next();
String classname = ((Symbol) rform.first()).toString(); Symbol classname = (Symbol) rform.first();
rform = rform.next(); rform = rform.next();
IPersistentVector fields = (IPersistentVector) rform.first(); IPersistentVector fields = (IPersistentVector) rform.first();
rform = rform.next(); rform = rform.next();
Expand Down Expand Up @@ -5985,7 +6003,7 @@ public Expr parse(C context, Object frm) throws Exception{
rform = RT.next(rform); rform = RT.next(rform);




ObjExpr ret = build(interfaces, null, null, classname, classname, null, rform, frm); ObjExpr ret = build(interfaces, null, null, classname, Symbol.intern(classname), null, rform, frm);
if(frm instanceof IObj && ((IObj) frm).meta() != null) if(frm instanceof IObj && ((IObj) frm).meta() != null)
return new MetaExpr(ret, (MapExpr) MapExpr return new MetaExpr(ret, (MapExpr) MapExpr
.parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) frm).meta())); .parse(context == C.EVAL ? context : C.EXPRESSION, ((IObj) frm).meta()));
Expand All @@ -5995,12 +6013,13 @@ public Expr parse(C context, Object frm) throws Exception{
} }


static ObjExpr build(IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, static ObjExpr build(IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym,
String tagName, String className, String tagName, Symbol className,
Symbol typeTag, ISeq methodForms, Object frm) throws Exception{ Symbol typeTag, ISeq methodForms, Object frm) throws Exception{
NewInstanceExpr ret = new NewInstanceExpr(null); NewInstanceExpr ret = new NewInstanceExpr(null);


ret.src = frm; ret.src = frm;
ret.name = className; ret.name = className.toString();
ret.classMeta = RT.meta(className);
ret.internalName = ret.name.replace('.', '/'); ret.internalName = ret.name.replace('.', '/');
ret.objtype = Type.getObjectType(ret.internalName); ret.objtype = Type.getObjectType(ret.internalName);


Expand Down Expand Up @@ -6451,6 +6470,7 @@ static NewInstanceMethod parse(ObjExpr objx, ISeq form, Symbol thistag,
} }
LOOP_LOCALS.set(argLocals); LOOP_LOCALS.set(argLocals);
method.name = name.name; method.name = name.name;
method.methodMeta = RT.meta(name);
method.argLocals = argLocals; method.argLocals = argLocals;
method.body = (new BodyExpr.Parser()).parse(C.RETURN, body); method.body = (new BodyExpr.Parser()).parse(C.RETURN, body);
return method; return method;
Expand Down Expand Up @@ -6500,6 +6520,7 @@ public void emit(ObjExpr obj, ClassVisitor cv){
null, null,
extypes, extypes,
cv); cv);
addAnnotation(gen,methodMeta);
gen.visitCode(); gen.visitCode();
Label loopLabel = gen.mark(); Label loopLabel = gen.mark();
gen.visitLineNumber(line, loopLabel); gen.visitLineNumber(line, loopLabel);
Expand Down

0 comments on commit fa899d2

Please sign in to comment.