From: <cg...@us...> - 2009-08-30 22:17:33
|
Revision: 6730 http://jython.svn.sourceforge.net/jython/?rev=6730&view=rev Author: cgroves Date: 2009-08-30 22:17:24 +0000 (Sun, 30 Aug 2009) Log Message: ----------- Hide more of ProxyMaker's internals to make it clearer how to subclass it. Modified Paths: -------------- branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java Modified: branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java 2009-08-30 22:15:47 UTC (rev 6729) +++ branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java 2009-08-30 22:17:24 UTC (rev 6730) @@ -5,7 +5,6 @@ import java.util.HashSet; import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; public class AdapterMaker extends ProxyMaker { @@ -17,19 +16,20 @@ protected void build() { classfile.addInterface(mapClass(interfaces[0])); visitMethods(interfaces[0], new HashSet<MethodDescr>()); - visitConstructors(); - for (String name : names) { - classfile.addField(name, $pyObj, Opcodes.ACC_PUBLIC); + try { + addConstructor(Object.class.getConstructor()); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "Object.class doesn't have a no-arg constructor? What the dickens?", e); } } @Override - protected void addMethod(Method method) { + protected void addOverrideMethod(Method method) { Class<?>[] parameters = method.getParameterTypes(); Class<?> ret = method.getReturnType(); String name = method.getName(); - names.add(name); - Code code = classfile.addMethod(name, makeSig(ret, parameters), Opcodes.ACC_PUBLIC); + Code code = classfile.addMethod(name, makeSig(ret, parameters), ACC_PUBLIC); code.aload(0); code.getfield(classfile.name, name, $pyObj); code.dup(); @@ -38,5 +38,6 @@ callMethod(code, name, parameters, ret, method.getExceptionTypes()); code.label(returnNull); doNullReturn(code, ret); + classfile.addField(name, $pyObj, ACC_PUBLIC); } } Modified: branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java 2009-08-30 22:15:47 UTC (rev 6729) +++ branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java 2009-08-30 22:17:24 UTC (rev 6730) @@ -1,6 +1,7 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.compiler; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; @@ -32,12 +33,18 @@ } @Override - public void addConstructor(Class<?>[] parameters, int access) { + protected void build() { + super.build(); + + addInitProxy(); + } + + @Override + public void visitConstructor(Constructor<?> constructor) + { /* Need a fancy constructor for the Java side of things */ - String sig = makeSig(Void.TYPE, parameters); - Code code = classfile.addMethod("<init>", sig, access); - callSuper(code, "<init>", mapClass(superclass), parameters, Void.TYPE, false); - callInitProxy(parameters, code); + Code code = addOpenConstructor(constructor); + callInitProxy(constructor.getParameterTypes(), code); } /** @@ -51,11 +58,7 @@ code.visitInsn(RETURN); } - @Override - public void addProxy() { - super.addProxy(); - - // _initProxy method + protected void addInitProxy() { Code code = classfile.addMethod("__initProxy__", makeSig("V", $objArr), Modifier.PUBLIC); code.visitVarInsn(ALOAD, 0); Modified: branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java 2009-08-30 22:15:47 UTC (rev 6729) +++ branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java 2009-08-30 22:17:24 UTC (rev 6730) @@ -2,36 +2,38 @@ import java.util.Map; +import org.objectweb.asm.Label; +import org.objectweb.asm.Opcodes; import org.python.util.Generic; /** * Various static methods and constants used in generating bytecode for proxy classes. */ -public class ProxyCodeHelpers { +public class ProxyCodeHelpers implements ClassConstants, Opcodes { - public static final int tBoolean = 0; + private static final int tBoolean = 0; - public static final int tByte = 1; + private static final int tByte = 1; - public static final int tShort = 2; + private static final int tShort = 2; - public static final int tInteger = 3; + private static final int tInteger = 3; - public static final int tLong = 4; + private static final int tLong = 4; - public static final int tFloat = 5; + private static final int tFloat = 5; - public static final int tDouble = 6; + private static final int tDouble = 6; - public static final int tCharacter = 7; + private static final int tCharacter = 7; - public static final int tVoid = 8; + private static final int tVoid = 8; - public static final int tOther = 9; + private static final int tOther = 9; - public static final int tNone = 10; + private static final int tNone = 10; - public static Map<Class<?>, Integer> types = Generic.map(); + private static Map<Class<?>, Integer> types = Generic.map(); static { types.put(Boolean.TYPE, tBoolean); types.put(Byte.TYPE, tByte); @@ -44,7 +46,7 @@ types.put(Void.TYPE, tVoid); } - public static int getType(Class<?> c) { + private static int getType(Class<?> c) { if (c == null) { return tNone; } @@ -56,6 +58,62 @@ } } + protected static void getArgs(Code code, Class<?>[] parameters) { + if (parameters.length == 0) { + code.getstatic("org/python/core/Py", "EmptyObjects", $pyObjArr); + } else { + code.iconst(parameters.length); + code.anewarray("java/lang/Object"); + + int array = code.getLocal("[org/python/core/PyObject"); + code.astore(array); + + int local_index; + int i; + for (i=0, local_index=1; i<parameters.length; i++) { + code.aload(array); + code.iconst(i); + + switch (getType(parameters[i])) { + case tBoolean: + case tByte: + case tShort: + case tInteger: + code.iload(local_index); + local_index += 1; + code.invokestatic("org/python/core/Py", "newInteger", "(I)" + $pyInteger); + break; + case tLong: + code.lload(local_index); + local_index += 2; + code.invokestatic("org/python/core/Py", "newInteger", "(J)" + $pyObj); + break; + case tFloat: + code.fload(local_index); + local_index += 1; + code.invokestatic("org/python/core/Py", "newFloat", "(F)" + $pyFloat); + break; + case tDouble: + code.dload(local_index); + local_index += 2; + code.invokestatic("org/python/core/Py", "newFloat", "(D)" + $pyFloat); + break; + case tCharacter: + code.iload(local_index); + local_index += 1; + code.invokestatic("org/python/core/Py", "newString", "(C)" + $pyStr); + break; + default: + code.aload(local_index); + local_index += 1; + break; + } + code.aastore(); + } + code.aload(array); + } + } + public static String[] mapClasses(Class<?>[] classes) { String[] mapped = new String[classes.length]; for (int i = 0; i < mapped.length; i++) { @@ -65,7 +123,10 @@ } public static String mapClass(Class<?> c) { - String name = c.getName(); + return mapClass(c.getName()); + } + + public static String mapClass(String name) { int index = name.indexOf("."); if (index == -1) { return name; @@ -82,7 +143,7 @@ return buf.toString(); } - public static String mapType(Class<?> type) { + private static String mapType(Class<?> type) { if (type.isArray()) return "[" + mapType(type.getComponentType()); switch(getType(type)){ @@ -187,4 +248,155 @@ break; } } + + public static void callSuper(Code code, + String name, + String superclass, + Class<?>[] parameters, + Class<?> ret, + boolean doReturn) { + code.aload(0); + int local_index; + int i; + for (i=0, local_index=1; i<parameters.length; i++) { + switch(getType(parameters[i])) { + case tCharacter: + case tBoolean: + case tByte: + case tShort: + case tInteger: + code.iload(local_index); + local_index += 1; + break; + case tLong: + code.lload(local_index); + local_index += 2; + break; + case tFloat: + code.fload(local_index); + local_index += 1; + break; + case tDouble: + code.dload(local_index); + local_index += 2; + break; + default: + code.aload(local_index); + local_index += 1; + break; + } + } + code.invokespecial(superclass, name, makeSig(ret, parameters)); + + if (doReturn) { + doReturn(code, ret); + } + } + + public static void callMethod(Code code, + String name, + Class<?>[] parameters, + Class<?> ret, + Class<?>[] exceptions) { + Label start = null; + Label end = null; + + String jcallName = "_jcall"; + int instLocal = 0; + + if (exceptions.length > 0) { + start = new Label(); + end = new Label(); + jcallName = "_jcallexc"; + instLocal = code.getLocal("org/python/core/PyObject"); + code.astore(instLocal); + code.label(start); + code.aload(instLocal); + } + + getArgs(code, parameters); + + switch (getType(ret)) { + case tCharacter: + doJavaCall(code, "char", "C", jcallName); + break; + case tBoolean: + doJavaCall(code, "boolean", "Z", jcallName); + break; + case tByte: + case tShort: + case tInteger: + doJavaCall(code, "int", "I", jcallName); + break; + case tLong: + doJavaCall(code, "long", "J", jcallName); + break; + case tFloat: + doJavaCall(code, "float", "F", jcallName); + break; + case tDouble: + doJavaCall(code, "double", "D", jcallName); + break; + case tVoid: + doJavaCall(code, "void", "V", jcallName); + break; + default: + code.invokevirtual("org/python/core/PyObject", jcallName, makeSig($pyObj, $objArr)); + code.ldc(ret.getName()); + code.invokestatic("java/lang/Class","forName", makeSig($clss, $str)); + code.invokestatic("org/python/core/Py", "tojava", makeSig($obj, $pyObj, $clss)); + // I guess I need this checkcast to keep the verifier happy + code.checkcast(mapClass(ret)); + break; + } + if (end != null) { + code.label(end); + } + + doReturn(code, ret); + + if (exceptions.length > 0) { + boolean throwableFound = false; + + Label handlerStart = null; + for (Class<?> exception : exceptions) { + handlerStart = new Label(); + code.label(handlerStart); + int excLocal = code.getLocal("java/lang/Throwable"); + code.astore(excLocal); + + code.aload(excLocal); + code.athrow(); + + code.visitTryCatchBlock(start, end, handlerStart, mapClass(exception)); + doNullReturn(code, ret); + + code.freeLocal(excLocal); + if (exception == Throwable.class) + throwableFound = true; + } + + if (!throwableFound) { + // The final catch (Throwable) + handlerStart = new Label(); + code.label(handlerStart); + int excLocal = code.getLocal("java/lang/Throwable"); + code.astore(excLocal); + code.aload(instLocal); + code.aload(excLocal); + + code.invokevirtual("org/python/core/PyObject", "_jthrow", makeSig("V", $throwable)); + code.visitTryCatchBlock(start, end, handlerStart, "java/lang/Throwable"); + + code.freeLocal(excLocal); + doNullReturn(code, ret); + } + code.freeLocal(instLocal); + } + } + + private static void doJavaCall(Code code, String name, String type, String jcallName) { + code.invokevirtual("org/python/core/PyObject", jcallName, makeSig($pyObj, $objArr)); + code.invokestatic("org/python/core/Py", "py2" + name, makeSig(type, $pyObj)); + } } Modified: branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java 2009-08-30 22:15:47 UTC (rev 6729) +++ branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java 2009-08-30 22:17:24 UTC (rev 6730) @@ -7,7 +7,6 @@ import java.util.Set; import org.objectweb.asm.Label; -import org.objectweb.asm.Opcodes; import org.python.core.Py; import org.python.core.PyMethod; import org.python.core.PyObject; @@ -15,7 +14,7 @@ import org.python.core.PyReflectedFunction; import org.python.util.Generic; -public class ProxyMaker extends ProxyCodeHelpers implements ClassConstants, Opcodes { +public class ProxyMaker extends ProxyCodeHelpers { /** * Retrieves <code>name</code> from the PyObject in <code>proxy</code> if it's defined in * Python. This is a specialized helper function for internal PyProxy use. @@ -45,28 +44,13 @@ protected final Class<?> superclass; protected final Class<?>[] interfaces; - protected final Set<String> names = Generic.set(); - protected final Set<String> supernames = Generic.set(); + private final Set<String> names = Generic.set(); + private final Set<String> supernames = Generic.set(); protected ClassFile classfile; /** The name of the class to build. */ public String proxyClassName; /** - * Creates a proxy class maker that produces classes named - * <code>org.python.proxies.(superclassName)</code> with <code>superclass</code> as an - * implemented interface or extended class, depending on the its type. - * - * @deprecated - Use {@link ProxyMaker#ProxyMaker(String, Class, Class[]) - */ - @Deprecated - public ProxyMaker(String superclassName, Class<?> superclass) { - this("org.python.proxies." + superclassName, - superclass.isInterface() ? Object.class : superclass, - superclass.isInterface() ? new Class<?>[] { superclass} : new Class<?>[0]); - - } - - /** * Creates a proxy class maker that produces classes named <code>proxyClassName</code> that * extends <code>superclass</code> and implements the interfaces in <code>interfaces</code>. */ @@ -99,12 +83,11 @@ * Builds this proxy and returns its bytecode. */ public synchronized byte[] make() { - classfile = new ClassFile(proxyClassName, mapClass(superclass), Modifier.PUBLIC - | Modifier.SYNCHRONIZED); + classfile = new ClassFile(proxyClassName, mapClass(superclass)); build(); - names.clear(); - supernames.clear(); - return classfile.create(); + byte[] result = classfile.create(); + classfile = null; + return result; } /** @@ -120,223 +103,17 @@ visitMethods(); addClassDictInit(); + names.clear(); + supernames.clear(); } - protected void callSuper(Code code, - String name, - String superclass, - Class<?>[] parameters, - Class<?> ret, boolean doReturn) { - - code.aload(0); - int local_index; - int i; - for (i=0, local_index=1; i<parameters.length; i++) { - switch(getType(parameters[i])) { - case tCharacter: - case tBoolean: - case tByte: - case tShort: - case tInteger: - code.iload(local_index); - local_index += 1; - break; - case tLong: - code.lload(local_index); - local_index += 2; - break; - case tFloat: - code.fload(local_index); - local_index += 1; - break; - case tDouble: - code.dload(local_index); - local_index += 2; - break; - default: - code.aload(local_index); - local_index += 1; - break; - } - } - code.invokespecial(superclass, name, makeSig(ret, parameters)); - - if (doReturn) { - doReturn(code, ret); - } - } - - protected void doJavaCall(Code code, String name, String type, String jcallName) { - code.invokevirtual("org/python/core/PyObject", jcallName, makeSig($pyObj, $objArr)); - code.invokestatic("org/python/core/Py", "py2" + name, makeSig(type, $pyObj)); - } - - - protected void getArgs(Code code, Class<?>[] parameters) { - if (parameters.length == 0) { - code.getstatic("org/python/core/Py", "EmptyObjects", $pyObjArr); - } else { - code.iconst(parameters.length); - code.anewarray("java/lang/Object"); - - int array = code.getLocal("[org/python/core/PyObject"); - code.astore(array); - - int local_index; - int i; - for (i=0, local_index=1; i<parameters.length; i++) { - code.aload(array); - code.iconst(i); - - switch (getType(parameters[i])) { - case tBoolean: - case tByte: - case tShort: - case tInteger: - code.iload(local_index); - local_index += 1; - code.invokestatic("org/python/core/Py", "newInteger", "(I)" + $pyInteger); - break; - case tLong: - code.lload(local_index); - local_index += 2; - code.invokestatic("org/python/core/Py", "newInteger", "(J)" + $pyObj); - break; - case tFloat: - code.fload(local_index); - local_index += 1; - code.invokestatic("org/python/core/Py", "newFloat", "(F)" + $pyFloat); - break; - case tDouble: - code.dload(local_index); - local_index += 2; - code.invokestatic("org/python/core/Py", "newFloat", "(D)" + $pyFloat); - break; - case tCharacter: - code.iload(local_index); - local_index += 1; - code.invokestatic("org/python/core/Py", "newString", "(C)" + $pyStr); - break; - default: - code.aload(local_index); - local_index += 1; - break; - } - code.aastore(); - } - code.aload(array); - } - } - - protected void callMethod(Code code, - String name, - Class<?>[] parameters, - Class<?> ret, - Class<?>[] exceptions) { - Label start = null; - Label end = null; - - String jcallName = "_jcall"; - int instLocal = 0; - - if (exceptions.length > 0) { - start = new Label(); - end = new Label(); - jcallName = "_jcallexc"; - instLocal = code.getLocal("org/python/core/PyObject"); - code.astore(instLocal); - code.label(start); - code.aload(instLocal); - } - - getArgs(code, parameters); - - switch (getType(ret)) { - case tCharacter: - doJavaCall(code, "char", "C", jcallName); - break; - case tBoolean: - doJavaCall(code, "boolean", "Z", jcallName); - break; - case tByte: - case tShort: - case tInteger: - doJavaCall(code, "int", "I", jcallName); - break; - case tLong: - doJavaCall(code, "long", "J", jcallName); - break; - case tFloat: - doJavaCall(code, "float", "F", jcallName); - break; - case tDouble: - doJavaCall(code, "double", "D", jcallName); - break; - case tVoid: - doJavaCall(code, "void", "V", jcallName); - break; - default: - code.invokevirtual("org/python/core/PyObject", jcallName, makeSig($pyObj, $objArr)); - code.ldc(ret.getName()); - code.invokestatic("java/lang/Class","forName", makeSig($clss, $str)); - code.invokestatic("org/python/core/Py", "tojava", makeSig($obj, $pyObj, $clss)); - // I guess I need this checkcast to keep the verifier happy - code.checkcast(mapClass(ret)); - break; - } - if (end != null) { - code.label(end); - } - - doReturn(code, ret); - - if (exceptions.length > 0) { - boolean throwableFound = false; - - Label handlerStart = null; - for (Class<?> exception : exceptions) { - handlerStart = new Label(); - code.label(handlerStart); - int excLocal = code.getLocal("java/lang/Throwable"); - code.astore(excLocal); - - code.aload(excLocal); - code.athrow(); - - code.visitTryCatchBlock(start, end, handlerStart, mapClass(exception)); - doNullReturn(code, ret); - - code.freeLocal(excLocal); - if (exception == Throwable.class) - throwableFound = true; - } - - if (!throwableFound) { - // The final catch (Throwable) - handlerStart = new Label(); - code.label(handlerStart); - int excLocal = code.getLocal("java/lang/Throwable"); - code.astore(excLocal); - code.aload(instLocal); - code.aload(excLocal); - - code.invokevirtual("org/python/core/PyObject", "_jthrow", makeSig("V", $throwable)); - code.visitTryCatchBlock(start, end, handlerStart, "java/lang/Throwable"); - - code.freeLocal(excLocal); - doNullReturn(code, ret); - } - code.freeLocal(instLocal); - } - } - /** * Adds an override of <code>method</code> to the class being implemented. If * <code>method</code> is abstract, the generated method will expect to find an object of the * method's name in the Python object and call it. If it isn't abstract, if an object is found * in the Python object, it'll be called. Otherwise the superclass will be called. */ - protected void addMethod(Method method) { + protected void addOverrideMethod(Method method) { boolean isAbstract = Modifier.isAbstract(method.getModifiers()); addMethod(method.getName(), method.getReturnType(), method.getParameterTypes(), @@ -351,11 +128,10 @@ * @param - the modifier to be used on the generated method. */ protected void addMethod(String name, - Class<?> ret, - Class<?>[] parameters, - Class<?>[] exceptions, - int modifier) { - addMethod(name, ret, parameters, exceptions, modifier, null); + Class<?> ret, + Class<?>[] parameters, + Class<?>[] exceptions) { + addMethod(name, ret, parameters, exceptions, Modifier.PUBLIC, null); } /** @@ -365,12 +141,12 @@ * in the Python object, it'll be called. Otherwise the superclass will be called. No checking * is done to guarantee that the superclass has a method with the same signature. */ - protected void addMethod(String name, - Class<?> ret, - Class<?>[] parameters, - Class<?>[] exceptions, - int access, - Class<?> declaringClass) { + private void addMethod(String name, + Class<?> ret, + Class<?>[] parameters, + Class<?>[] exceptions, + int access, + Class<?> declaringClass) { names.add(name); Code code = classfile.addMethod(name, makeSig(ret, parameters), access, mapClasses(exceptions)); @@ -461,85 +237,54 @@ } } + /** Adds a constructor that calls through to superclass and returns immediately. */ + protected void addConstructor(Constructor<?> constructor) { + Code code = addOpenConstructor(constructor); + doReturn(code, superclass); + } + /** - * Visits all methods declared on the given class and classes in its inheritance hierarchy. - * Methods visible to subclasses are added to <code>seen</code>. + * Adds a constructor that calls through to superclass and leaves the returned Code open for + * more operations. The caller of this method must add a return to the returned Code. */ - protected void visitMethods(Class<?> klass, Set<MethodDescr> seen) { - for (Method method : klass.getDeclaredMethods()) { + protected Code addOpenConstructor(Constructor<?> constructor) { + String sig = makeSig(Void.TYPE, constructor.getParameterTypes()); + Code code = classfile.addMethod("<init>", sig, ACC_PUBLIC, + mapClasses(constructor.getExceptionTypes())); + callSuper(code, "<init>", mapClass(superclass), constructor.getParameterTypes(), Void.TYPE, + false); + return code; + } - int access = method.getModifiers(); - if (Modifier.isStatic(access) || Modifier.isPrivate(access) || - PyReflectedFunction.isPackagedProtected(access)) { - // package protected and private aren't visible to our class, so they don't enter - // into the namespace, and likewise for static methods, regardless of their access. - - // TODO - allow overriding of package protected methods if the generated class is in - // the same package, throw an exception otherwise. + /** + * Visits constructors from this proxy's superclass. + */ + private void visitConstructors() { + for (Constructor<?> constructor : superclass.getDeclaredConstructors()) { + if (Modifier.isPrivate(constructor.getModifiers())) { continue; } - - if (!seen.add(new MethodDescr(method))) { - // A method with the same signature has already been added, skip this. - continue; - } - - // TODO - Track accessible final methods in their own Set, protect from overrides - if (Modifier.isFinal(access)) { - if (Modifier.isProtected(access)) { - addSuperMethod(method); - } - continue; - } - visitMethod(method); + visitConstructor(constructor); } - - Class<?> superClass = klass.getSuperclass(); - if (superClass != null) { - visitMethods(superClass, seen); - } - - for (Class<?> iface : klass.getInterfaces()) { - visitMethods(iface, seen); - } } /** - * Called for every method on the proxy's superclass and interfaces that can be overriden by the - * proxy class. If the proxy wants to perform Python lookup and calling for the method, - * {@link #addMethod(Method)} should be called. For abstract methods, addMethod must be called. + * Called for every method on the proxy's superclass and interfaces that can be overridden by + * the proxy class. If the proxy wants to perform Python lookup and calling for the method, + * {@link #addOverrideMethod(Method)} should be called. For abstract methods, addMethod must be + * called. */ protected void visitMethod(Method method) { - addMethod(method); + addOverrideMethod(method); } - /** Adds a constructor that calls through to superclass. */ - protected void addConstructor(Class<?>[] parameters, int access) { - String sig = makeSig(Void.TYPE, parameters); - Code code = classfile.addMethod("<init>", sig, access); - callSuper(code, "<init>", mapClass(superclass), parameters, Void.TYPE, true); - } /** - * Visits constructors from this proxy's superclass. + * Called for every constructor on the proxy's superclass that can be overridden by + * the proxy class. */ - protected Set<ConstructorDescr> visitConstructors() { - Set<ConstructorDescr> added = Generic.set(); - for (Constructor<?> constructor : superclass.getDeclaredConstructors()) { - int access = constructor.getModifiers(); - if (Modifier.isPrivate(access)) { - continue; - } - if (Modifier.isNative(access)) { - access = access & ~Modifier.NATIVE; - } - if (Modifier.isProtected(access)) { - access = access & ~Modifier.PROTECTED | Modifier.PUBLIC; - } - addConstructor(constructor.getParameterTypes(), access); - added.add(new ConstructorDescr(constructor)); - } - return added; + protected void visitConstructor(Constructor<?> constructor) { + addConstructor(constructor); } // Super methods are added for the following three reasons: @@ -568,11 +313,11 @@ addSuperMethod(methodName, superName, superClass, parameters, ret); } - protected void addSuperMethod(String methodName, - String superName, - String declClass, - Class<?>[] parameters, - Class<?> ret) { + private void addSuperMethod(String methodName, + String superName, + String declClass, + Class<?>[] parameters, + Class<?> ret) { if (methodName.startsWith("super__")) { /* rationale: JC java-class, P proxy-class subclassing JC in order to avoid infinite recursion P should define super__foo @@ -597,7 +342,7 @@ /** * Adds the methods and fields necessary to implement PyProxy. */ - protected void addProxy() { + private void addProxy() { classfile.addField("__proxy", $pyObj, Modifier.PROTECTED); Code code = classfile.addMethod("_setPyInstance", makeSig("V", $pyObj), Modifier.PUBLIC); code.aload(0); @@ -628,7 +373,7 @@ /** * Adds the classDictInit static method to fill in __supernames__ on the class' dict */ - protected void addClassDictInit() { + private void addClassDictInit() { classfile.addInterface(mapClass(org.python.core.ClassDictInit.class)); Code code = classfile.addMethod("classDictInit", makeSig("V", $pyObj), Modifier.PUBLIC | Modifier.STATIC); @@ -643,7 +388,50 @@ code.return_(); } - protected Set<MethodDescr> visitMethods() { + /** + * Visits all methods declared on the given class and classes in its inheritance hierarchy. + * Methods visible to subclasses are added to <code>seen</code>. + */ + void visitMethods(Class<?> klass, Set<MethodDescr> seen) { + for (Method method : klass.getDeclaredMethods()) { + + int access = method.getModifiers(); + if (Modifier.isStatic(access) || Modifier.isPrivate(access) || + PyReflectedFunction.isPackagedProtected(access)) { + // package protected and private aren't visible to our class, so they don't enter + // into the namespace, and likewise for static methods, regardless of their access. + + // TODO - allow overriding of package protected methods if the generated class is in + // the same package, throw an exception otherwise. + continue; + } + + if (!seen.add(new MethodDescr(method))) { + // A method with the same signature has already been added, skip this. + continue; + } + + // TODO - Track accessible final methods in their own Set, protect from overrides + if (Modifier.isFinal(access)) { + if (Modifier.isProtected(access)) { + addSuperMethod(method); + } + continue; + } + visitMethod(method); + } + + Class<?> superClass = klass.getSuperclass(); + if (superClass != null) { + visitMethods(superClass, seen); + } + + for (Class<?> iface : klass.getInterfaces()) { + visitMethods(iface, seen); + } + } + + private Set<MethodDescr> visitMethods() { Set<MethodDescr> seenmethods = Generic.set(); visitMethods(superclass, seenmethods); for (Class<?> iface : interfaces) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |