Skip to content

Commit cce7e34

Browse files
committed
Initial implementation of customizable proxymaker with annotation support and reference implementation in tests.
Remaining: * constructor signatures * more tests
1 parent d4e15b9 commit cce7e34

18 files changed

Lines changed: 1209 additions & 233 deletions

src/org/python/compiler/ClassFile.java

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,18 @@
77
import java.util.ArrayList;
88
import java.util.Collections;
99
import java.util.List;
10+
import java.util.Map;
11+
import java.util.Map.Entry;
1012

1113
import org.objectweb.asm.AnnotationVisitor;
1214
import org.objectweb.asm.ClassWriter;
1315
import org.objectweb.asm.FieldVisitor;
1416
import org.objectweb.asm.MethodVisitor;
1517
import org.objectweb.asm.Opcodes;
18+
import org.objectweb.asm.Type;
1619

1720
import org.python.core.imp;
21+
import org.python.compiler.ProxyCodeHelpers.AnnotationDescr;
1822

1923
public class ClassFile
2024
{
@@ -27,6 +31,7 @@ public class ClassFile
2731
String[] interfaces;
2832
List<MethodVisitor> methodVisitors;
2933
List<FieldVisitor> fieldVisitors;
34+
List<AnnotationVisitor> annotationVisitors;
3035

3136
public static String fixName(String n) {
3237
if (n.indexOf('.') == -1)
@@ -37,6 +42,34 @@ public static String fixName(String n) {
3742
}
3843
return new String(c);
3944
}
45+
46+
47+
public static void visitAnnotations(AnnotationVisitor av, Map<String, Object> fields) {
48+
for (Entry<String, Object>field: fields.entrySet()) {
49+
visitAnnotation(av, field.getKey(), field.getValue());
50+
}
51+
}
52+
53+
// See org.objectweb.asm.AnnotationVisitor for details
54+
// TODO Support annotation annotations and annotation array annotations
55+
public static void visitAnnotation(AnnotationVisitor av, String fieldName, Object fieldValue) {
56+
Class<?> fieldValueClass = fieldValue.getClass();
57+
58+
if (fieldValue instanceof Class) {
59+
av.visit(fieldName, Type.getType((Class<?>)fieldValue));
60+
} else if (fieldValueClass.isEnum()) {
61+
av.visitEnum(fieldName, ProxyCodeHelpers.mapType(fieldValueClass), fieldValue.toString());
62+
} else if (fieldValue instanceof List) {
63+
AnnotationVisitor arrayVisitor = av.visitArray(fieldName);
64+
List<Object> fieldList = (List<Object>)fieldValue;
65+
for (Object arrayField: fieldList) {
66+
visitAnnotation(arrayVisitor, null, arrayField);
67+
}
68+
arrayVisitor.visitEnd();
69+
} else {
70+
av.visit(fieldName, fieldValue);
71+
}
72+
}
4073

4174
public ClassFile(String name) {
4275
this(name, "java/lang/Object", Opcodes.ACC_SYNCHRONIZED | Opcodes.ACC_PUBLIC,
@@ -56,6 +89,7 @@ public ClassFile(String name, String superclass, int access, long mtime) {
5689
cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
5790
methodVisitors = Collections.synchronizedList(new ArrayList<MethodVisitor>());
5891
fieldVisitors = Collections.synchronizedList(new ArrayList<FieldVisitor>());
92+
annotationVisitors = Collections.synchronizedList(new ArrayList<AnnotationVisitor>());
5993
}
6094

6195
public void setSource(String name) {
@@ -77,7 +111,54 @@ public Code addMethod(String name, String type, int access)
77111
methodVisitors.add(pmv);
78112
return pmv;
79113
}
80-
114+
public Code addMethod(String name, String type, int access, String[] exceptions)
115+
throws IOException
116+
{
117+
MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions);
118+
Code pmv = new Code(mv, type, access);
119+
methodVisitors.add(pmv);
120+
return pmv;
121+
}
122+
123+
public Code addMethod(String name, String type, int access, String[] exceptions,
124+
AnnotationDescr[]methodAnnotationDescrs, AnnotationDescr[][] parameterAnnotationDescrs)
125+
throws IOException
126+
{
127+
MethodVisitor mv = cw.visitMethod(access, name, type, null, exceptions);
128+
129+
// method annotations
130+
for (AnnotationDescr ad: methodAnnotationDescrs) {
131+
AnnotationVisitor av = mv.visitAnnotation(ad.getName(), true);
132+
if (ad.hasFields()) {
133+
visitAnnotations(av, ad.getFields());
134+
}
135+
av.visitEnd();
136+
}
137+
138+
// parameter annotations
139+
for (int i = 0; i < parameterAnnotationDescrs.length; i++) {
140+
for (AnnotationDescr ad: parameterAnnotationDescrs[i]) {
141+
AnnotationVisitor av = mv.visitParameterAnnotation(i, ad.getName(), true);
142+
if (ad.hasFields()) {
143+
visitAnnotations(av, ad.getFields());
144+
}
145+
av.visitEnd();
146+
}
147+
}
148+
149+
Code pmv = new Code(mv, type, access);
150+
methodVisitors.add(pmv);
151+
return pmv;
152+
}
153+
154+
public void addClassAnnotation(AnnotationDescr annotationDescr) {
155+
AnnotationVisitor av = cw.visitAnnotation(annotationDescr.getName(), true);
156+
if (annotationDescr.hasFields()) {
157+
visitAnnotations(av, annotationDescr.getFields());
158+
}
159+
annotationVisitors.add(av);
160+
}
161+
81162
public void addField(String name, String type, int access)
82163
throws IOException
83164
{
@@ -103,6 +184,12 @@ public void endMethods()
103184
}
104185
}
105186

187+
public void endClassAnnotations() {
188+
for (AnnotationVisitor av: annotationVisitors) {
189+
av.visitEnd();
190+
}
191+
}
192+
106193
public void write(OutputStream stream) throws IOException {
107194
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, this.name, null, this.superclass, interfaces);
108195
AnnotationVisitor av = cw.visitAnnotation("Lorg/python/compiler/APIVersion;", true);
@@ -118,6 +205,7 @@ public void write(OutputStream stream) throws IOException {
118205
if (sfilename != null) {
119206
cw.visitSource(sfilename, null);
120207
}
208+
endClassAnnotations();
121209
endFields();
122210
endMethods();
123211

@@ -129,4 +217,5 @@ public void write(OutputStream stream) throws IOException {
129217
//debug(baos);
130218
baos.close();
131219
}
220+
132221
}

src/org/python/compiler/Code.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.objectweb.asm.MethodVisitor;
1111
import org.objectweb.asm.Opcodes;
1212

13-
class Code extends MethodVisitor implements Opcodes {
13+
public class Code extends MethodVisitor implements Opcodes {
1414
MethodVisitor mv;
1515
String sig;
1616
String locals[];

src/org/python/compiler/JavaMaker.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,8 @@ public void addConstructor(String name,
3232
int access) throws Exception {
3333
/* Need a fancy constructor for the Java side of things */
3434
Code code = classfile.addMethod("<init>", sig, access);
35-
callSuper(code, "<init>", name, parameters, null, sig);
36-
code.visitVarInsn(ALOAD, 0);
37-
getArgs(code, parameters);
38-
code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr));
39-
code.visitInsn(RETURN);
35+
callSuper(code, "<init>", name, parameters, Void.TYPE, false);
36+
callInitProxy(parameters, code);
4037
}
4138

4239
@Override

0 commit comments

Comments
 (0)