From: <cg...@us...> - 2009-09-06 09:42:15
|
Revision: 6760 http://jython.svn.sourceforge.net/jython/?rev=6760&view=rev Author: cgroves Date: 2009-09-06 09:42:02 +0000 (Sun, 06 Sep 2009) Log Message: ----------- Kill the JavaMaker/ProxyMaker distinction to collect the set of proxy code generation methods together, and unify the actual code generation around visit methods for each type of thing a proxy class might be interested in. Hopefully this is leading to more straightforward subclasses. Modified Paths: -------------- branches/customizable-proxymaker/Lib/javaproxymaker.py branches/customizable-proxymaker/Lib/test/test_class_jy.py branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java branches/customizable-proxymaker/src/org/python/compiler/ClassFile.java branches/customizable-proxymaker/src/org/python/compiler/Module.java branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java branches/customizable-proxymaker/src/org/python/core/MakeProxies.java Added Paths: ----------- branches/customizable-proxymaker/src/org/python/compiler/VerifyingClassFile.java Removed Paths: ------------- branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java Modified: branches/customizable-proxymaker/Lib/javaproxymaker.py =================================================================== --- branches/customizable-proxymaker/Lib/javaproxymaker.py 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/Lib/javaproxymaker.py 2009-09-06 09:42:02 UTC (rev 6760) @@ -1,15 +1,15 @@ from java.lang.reflect import Modifier from org.python.compiler import JavaMaker as NamedProxyMaker +from org.python.core.util import StringUtil def make_proxynamer(classname): '''Creates a callable for use in __proxymaker__ that names the generated classes the given name - If the given name is an invalid Java class name, an exception will be raised at class definition - time.''' + If the given name is an invalid Java class name, a ValueError will be raised.''' + if not StringUtil.isJavaClassName(classname): + raise ValueError("%s is not a valid Java class name. See http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625" % classname) def make_proxymaker(superclass, interfaces, pythonClassName, pythonClassDict): - proxymaker = NamedProxyMaker(superclass, interfaces, pythonClassName, pythonClassDict) - proxymaker.proxyClassName = classname - return proxymaker + return NamedProxyMaker(superclass, interfaces, pythonClassName, pythonClassDict, classname) return make_proxymaker class StrictProxyMaker(NamedProxyMaker): @@ -30,4 +30,4 @@ handle it from __getattribute__ unlike from regular proxy classes. Also, if the overriden method is abstract and isn't handled by the Python class, a noop return will be performed.''' def visitMethod(self, meth): - self.addMethod(meth) + self.addOverrideMethod(meth) Modified: branches/customizable-proxymaker/Lib/test/test_class_jy.py =================================================================== --- branches/customizable-proxymaker/Lib/test/test_class_jy.py 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/Lib/test/test_class_jy.py 2009-09-06 09:42:02 UTC (rev 6760) @@ -39,7 +39,7 @@ self.assertEqual(str(cls), "<class '%s.%s'>" % (__name__, cls.__name__)) self.assertEqual(repr(cls), "<class '%s.%s'>" % (__name__, cls.__name__)) self.assert_(str(Bar()).startswith('<%s.Bar object at' % __name__)) - self.assert_(str(Baz()).startswith("org.python.proxies.%s$Baz" % __name__)) + self.assert_(str(Baz()).startswith("org.python.proxies.%s.Baz$" % __name__)) def test_builtin_attributes(self): for attr, val in dict(__name__='foo', __module__='bar', __dict__={}, Modified: branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/AdapterMaker.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -1,9 +1,8 @@ // Copyright (c) Corporation for National Research Initiatives package org.python.compiler; +import java.lang.reflect.Constructor; import java.lang.reflect.Method; -import java.util.HashSet; - import org.objectweb.asm.Label; public class AdapterMaker extends ProxyMaker { @@ -13,23 +12,19 @@ } @Override - protected void build() { - classfile.addInterface(mapClass(interfaces[0])); - visitMethods(interfaces[0], new HashSet<MethodDescr>()); - try { - addConstructor(Object.class.getConstructor()); - } catch (NoSuchMethodException e) { - throw new RuntimeException( - "Object.class doesn't have a no-arg constructor? What the dickens?", e); - } + public void visitConstructor(Constructor<?> constructor) { + doReturn(addOpenConstructor(constructor), superclass); } @Override - protected void addOverrideMethod(Method method) { + protected void visitMethod(Method method) { + if (!method.getDeclaringClass().isInterface()) { + return; + } Class<?>[] parameters = method.getParameterTypes(); Class<?> ret = method.getReturnType(); String name = method.getName(); - Code code = classfile.addMethod(name, makeSig(ret, parameters), ACC_PUBLIC); + Code code = classfile.addMethod(ACC_PUBLIC, ret, name, parameters); code.aload(0); code.getfield(classfile.name, name, $pyObj); code.dup(); Modified: branches/customizable-proxymaker/src/org/python/compiler/ClassFile.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/ClassFile.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/ClassFile.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -9,7 +9,6 @@ import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; - import org.python.core.imp; import org.python.util.Generic; @@ -34,18 +33,6 @@ * - The name of the class in internal form. * @param superclass * - The name of the superclass of the generated class in internal form. - */ - public ClassFile(String name, String superclass) { - this(name, superclass, imp.NO_MTIME, null); - } - - /** - * Creates a generator for a class of the given name. - * - * @param name - * - The name of the class in internal form. - * @param superclass - * - The name of the superclass of the generated class in internal form. * @param mtime * - the time the source was last modified, or {@link imp#NO_MTIME} if it's unknown. * @param sourceFilename @@ -77,7 +64,7 @@ * @param access * - the method's access level as constructed from {@link Opcodes}. */ - public Code addMethod(String name, String descriptor, int access, String... exceptions) { + protected Code addMethod(String name, String descriptor, int access, String... exceptions) { MethodVisitor mv = cw.visitMethod(access, name, descriptor, null, exceptions); Code pmv = new Code(mv, descriptor, access); methodVisitors.add(pmv); @@ -106,8 +93,6 @@ cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, name, null, superclass, interfaces.toArray(new String[interfaces.size()])); AnnotationVisitor av = cw.visitAnnotation("Lorg/python/compiler/APIVersion;", true); - // XXX: should imp.java really house this value or should imp.java point into - // org.python.compiler? av.visit("value", imp.getAPIVersion()); av.visitEnd(); Deleted: branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/JavaMaker.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -1,88 +0,0 @@ -// 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; - -import org.python.core.PyObject; - -public class JavaMaker extends ProxyMaker { - - public final String pythonClass, pythonModule; - - public PyObject dict; - - private final boolean proxyNeeded; - - public JavaMaker(Class<?> superclass, - Class<?>[] interfaces, - String qualifiedPythonClassName, - PyObject pythonClassDict) { - super(qualifiedPythonClassName, superclass, interfaces); - proxyNeeded = superclass != null || interfaces.length > 0; - int lastDot = qualifiedPythonClassName.lastIndexOf('.'); - if (lastDot != -1) { - pythonClass = qualifiedPythonClassName.substring(lastDot + 1); - pythonModule = qualifiedPythonClassName.substring(0, lastDot); - } else { - pythonClass = qualifiedPythonClassName; - pythonModule = ""; - } - this.dict = pythonClassDict; - } - - @Override - protected void build() { - super.build(); - - addInitProxy(); - } - - @Override - public void visitConstructor(Constructor<?> constructor) - { - /* Need a fancy constructor for the Java side of things */ - Code code = addOpenConstructor(constructor); - callInitProxy(constructor.getParameterTypes(), code); - } - - /** - * Calls __initProxy__ on this class with the given given types of parameters, which must be - * available as arguments to the currently called method in the order of the parameters. - */ - protected void callInitProxy(Class<?>[] parameters, Code code) { - code.visitVarInsn(ALOAD, 0); - getArgs(code, parameters); - code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr)); - code.visitInsn(RETURN); - } - - protected void addInitProxy() { - Code code = classfile.addMethod("__initProxy__", makeSig("V", $objArr), Modifier.PUBLIC); - - code.visitVarInsn(ALOAD, 0); - code.visitLdcInsn(pythonModule); - code.visitLdcInsn(pythonClass); - code.visitVarInsn(ALOAD, 1); - code.visitMethodInsn(INVOKESTATIC, "org/python/core/Py", "initProxy", - makeSig("V", $pyProxy, $str, $str, $objArr)); - code.visitInsn(RETURN); - - } - - @Override - public void visitMethod(Method method) { - if (Modifier.isAbstract(method.getModifiers())) { - super.visitMethod(method); - } else if (dict.__finditem__(method.getName().intern()) != null) { - super.visitMethod(method); - } else if (Modifier.isProtected(method.getModifiers())) { - addSuperMethod(method); - } - } - - public boolean isProxyNeeded() { - return proxyNeeded; - } -} Modified: branches/customizable-proxymaker/src/org/python/compiler/Module.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/Module.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/Module.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -24,6 +24,7 @@ import org.python.core.Py; import org.python.core.PyException; import org.python.core.PyRunnableBootstrap; +import org.python.core.imp; import org.python.core.util.StringUtil; class PyIntegerConstant extends Constant implements ClassConstants, Opcodes @@ -306,7 +307,8 @@ public Module(String name, String filename, boolean linenumbers, long mtime) { this.linenumbers = linenumbers; this.mtime = mtime; - classfile = new ClassFile(name, "org/python/core/PyFunctionTable", mtime, sfilename); + classfile = new ClassFile(ProxyCodeHelpers.mapClass(name), + "org/python/core/PyFunctionTable", mtime, sfilename); constants = new Hashtable<Constant,Constant>(); sfilename = filename; codes = new ArrayList<PyCodeConstant>(); @@ -622,13 +624,15 @@ } throw new ParseException(msg,node); } - public static void compile(mod node, OutputStream ostream, - String name, String filename, - boolean linenumbers, boolean printResults, - CompilerFlags cflags) - throws Exception - { - compile(node, ostream, name, filename, linenumbers, printResults, cflags, org.python.core.imp.NO_MTIME); + + public static void compile(mod node, + OutputStream ostream, + String name, + String filename, + boolean linenumbers, + boolean printResults, + CompilerFlags cflags) throws Exception { + compile(node, ostream, name, filename, linenumbers, printResults, cflags, imp.NO_MTIME); } public static void compile(mod node, OutputStream ostream, Modified: branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/ProxyCodeHelpers.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -251,7 +251,7 @@ public static void callSuper(Code code, String name, - String superclass, + Class<?> superclass, Class<?>[] parameters, Class<?> ret, boolean doReturn) { @@ -286,7 +286,7 @@ break; } } - code.invokespecial(superclass, name, makeSig(ret, parameters)); + code.invokespecial(mapClass(superclass), name, makeSig(ret, parameters)); if (doReturn) { doReturn(code, ret); Modified: branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/compiler/ProxyMaker.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -4,15 +4,20 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; + +import java.util.List; import java.util.Set; import org.objectweb.asm.Label; +import org.python.core.ClassDictInit; import org.python.core.Py; import org.python.core.PyMethod; import org.python.core.PyObject; import org.python.core.PyProxy; import org.python.core.PyReflectedFunction; +import org.python.core.PySystemState; import org.python.util.Generic; +import org.python.util.Preconditions; public class ProxyMaker extends ProxyCodeHelpers { /** @@ -42,72 +47,141 @@ return ret; } + /** The name of the class to build. */ + public final String proxyClassName; + protected VerifyingClassFile classfile; protected final Class<?> superclass; - protected final Class<?>[] interfaces; - private final Set<String> names = Generic.set(); + protected final List<Class<?>> interfaces = Generic.list(); private final Set<String> supernames = Generic.set(); - protected ClassFile classfile; - /** The name of the class to build. */ - public String proxyClassName; + private final boolean proxyNeeded; + public final String pythonClass, pythonModule; + public final PyObject dict; + /** * 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>. */ - public ProxyMaker(String proxyClassName, Class<?> superclass, Class<?>... interfaces) { + ProxyMaker(String proxyClassName, Class<?> superclass, Class<?>... interfaces) { + this(superclass, interfaces, null, null, proxyClassName); + } + + public ProxyMaker(Class<?> superclass, + Class<?>[] interfaces, + String qualifiedPythonClassName, + PyObject pythonClassDict) { + this(superclass, interfaces, qualifiedPythonClassName, pythonClassDict, + qualifiedPythonClassName); + } + + public ProxyMaker(Class<?> superclass, + Class<?>[] interfaces, + String qualifiedPythonClassName, + PyObject pythonClassDict, + String proxyClassName) { this.proxyClassName = proxyClassName; + proxyNeeded = superclass != null || interfaces.length > 0; if (superclass == null) { superclass = Object.class; } - if (superclass.isInterface()) { - throw new IllegalArgumentException("Given an interface, " + superclass.getName() - + ", for a proxy superclass"); - } else if ((superclass.getModifiers() & Modifier.FINAL) != 0) { - throw new IllegalArgumentException("Can't subclass final class " + superclass.getName()); - } + Preconditions.checkArgument(!superclass.isInterface(), "Given an interface, " + + superclass.getName() + ", for a proxy superclass"); + Preconditions.checkArgument((superclass.getModifiers() & Modifier.FINAL) == 0, + "Can't subclass final class " + superclass.getName()); this.superclass = superclass; - if (interfaces == null) { - interfaces = new Class[0]; - } - for (Class<?> interfac : interfaces) { - if (!interfac.isInterface()) { - throw new IllegalArgumentException( - "All classes in the interfaces array must be interfaces, unlike " - + interfac.getName()); + for (Class<?> iface : interfaces) { + Preconditions.checkArgument(iface.isInterface(), + "Asked to add non-interface to proxy class as interface: " + iface.getName()); + if (iface.isAssignableFrom(superclass)) { + Py.writeWarning("compiler", "discarding redundant interface: " + iface.getName()); } + this.interfaces.add(iface); } - this.interfaces = interfaces; + int lastDot = qualifiedPythonClassName.lastIndexOf('.'); + if (lastDot != -1) { + pythonClass = qualifiedPythonClassName.substring(lastDot + 1); + pythonModule = qualifiedPythonClassName.substring(0, lastDot); + } else { + pythonClass = qualifiedPythonClassName; + pythonModule = ""; + } + this.dict = pythonClassDict; } + public boolean isProxyNeeded() { + return proxyNeeded; + } + /** * Builds this proxy and returns its bytecode. */ public synchronized byte[] make() { - classfile = new ClassFile(proxyClassName, mapClass(superclass)); - build(); + classfile = new VerifyingClassFile(mapClass(proxyClassName), mapClass(superclass)); + addProxy(); + for (Constructor<?> constructor : superclass.getDeclaredConstructors()) { + if (Modifier.isPrivate(constructor.getModifiers())) { + continue; + } + classfile.noteSuperclassConstructor(constructor); + visitConstructor(constructor); + } + visitMethods(superclass); + for (Class<?> iface : interfaces) { + classfile.addInterface(mapClass(iface)); + visitMethods(iface); + } + didVisits(); + addClassDictInit(); + supernames.clear(); byte[] result = classfile.create(); classfile = null; return result; } /** - * Called once per created proxy class. Should fill in the necessary methods, constructors and - * interfaces on <code>classfile</code>. Only one call to build will be active at a time, so - * data can be collected in the class as the call proceed, but it should be cleaned up before - * returning to keep later calls to build functioning properly. + * Called for every constructor on the proxy's superclass that can be overridden by + * the proxy class. */ - protected void build() { - addProxy(); - visitConstructors(); - classfile.addInterface("org/python/core/PyProxy"); + protected void visitConstructor(Constructor<?> constructor) + { + /* Need a fancy constructor for the Java side of things */ + callInitProxy(constructor.getParameterTypes(), addOpenConstructor(constructor)); + } - visitMethods(); - addClassDictInit(); - names.clear(); - supernames.clear(); + /** + * 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, a method matching + * this signature must be added to the proxy class. + * <p> + * ProxyMaker's implementation of this method calls <code>addOverrideMethod</code> if the given + * method is abstract or if the Python dict contains an item for the method's name. If the + * method is protected, a super method is added. Otherwise, it doesn't add a method with this + * signature on the proxy class. + */ + protected void visitMethod(Method method) { + if (Modifier.isAbstract(method.getModifiers())) { + addOverrideMethod(method); + } else if (dict.__finditem__(method.getName().intern()) != null) { + addOverrideMethod(method); + } else if (Modifier.isProtected(method.getModifiers())) { + addSuperMethod(method, false); + } } + protected void visitFinalMethod(Method method) { + if (Modifier.isProtected(method.getModifiers())) { + addSuperMethod(method, true); + } + } + /** + * Called as part of {@link #make} after the visit methods have been called for every + * constructor and method. + */ + protected void didVisits() {} + + /** * 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 @@ -115,7 +189,6 @@ */ protected void addOverrideMethod(Method method) { boolean isAbstract = Modifier.isAbstract(method.getModifiers()); - addMethod(method.getName(), method.getReturnType(), method.getParameterTypes(), method.getExceptionTypes(), Modifier.PUBLIC, isAbstract ? null : method.getDeclaringClass()); @@ -123,33 +196,113 @@ /** * Adds a method to the class being implemented with the given signature. The generated method - * will expect to find an object of the method's name in the Python object and call it. - * - * @param - the modifier to be used on the generated method. + * will call an object of the method's name in the Python object. */ - protected void addMethod(String name, - Class<?> ret, - Class<?>[] parameters, + protected void addMethod(String name, Class<?> ret, Class<?>[] parameters, Class<?>[] exceptions) { addMethod(name, ret, parameters, exceptions, Modifier.PUBLIC, null); } /** - * Adds a method of the given name to the class being implemented. If - * <code>declaringClass</code> is null, 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 null, if an object is found - * 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. + * Adds a "super" method to the class being generated. A super method is a public method that + * calls through to the method with the same signature on a superclass. If + * <code>prefixWithSuper</code> is given, super__ is prefixed to the method name on this class. + * <p> + * ProxyMaker automatically generates super methods with the prefix in two cases: + * <p> + * <ol> + * <li>for protected final methods to expose the method to Python without overriding a final + * method.</li> + * <li>for methods overridden for Python to give access to the superclass method from Python.</li> + * </ol> + * + * All other super method generation is under the control of subclasses. */ + protected void addSuperMethod(Method method, boolean prefixWithSuper) { + String methodName = method.getName(); + if (prefixWithSuper) { + methodName = "super__" + methodName; + } + addSuperMethod(methodName, method.getName(), method.getDeclaringClass(), + method.getParameterTypes(), method.getReturnType()); + } + + + /** + * Calls __initProxy__ on this class with the given given types of parameters, which must be + * available as arguments to the currently called method in the order of the parameters. + */ + protected void callInitProxy(Class<?>[] parameters, Code code) { + code.visitVarInsn(ALOAD, 0); + getArgs(code, parameters); + code.visitMethodInsn(INVOKEVIRTUAL, classfile.name, "__initProxy__", makeSig("V", $objArr)); + code.visitInsn(RETURN); + } + + /** + * Adds a constructor that calls through to the superclass constructor with the same signature + * and leaves the returned Code open for more operations. The caller of this method must add a + * return to the Code. + */ + protected Code addOpenConstructor(Constructor<?> constructor) { + Code code = classfile.addMethod(ACC_PUBLIC, Void.TYPE, "<init>", constructor + .getParameterTypes(), constructor.getExceptionTypes()); + callSuper(code, "<init>", superclass, constructor.getParameterTypes(), Void.TYPE, false); + return code; + } + + /** + * Visits all methods declared on the given class and classes in its inheritance hierarchy. + * Methods visible to subclasses are added to the classfile. + */ + private void visitMethods(Class<?> klass) { + 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; + } else if (classfile.noteSuperclassMethod(method)) { + // No method with the same signature has been added, check if we want to + if (Modifier.isFinal(access)) { + visitFinalMethod(method); + } else { + visitMethod(method); + } + } + } + + Class<?> superClass = klass.getSuperclass(); + if (superClass != null) { + visitMethods(superClass); + } + + for (Class<?> iface : klass.getInterfaces()) { + visitMethods(iface); + } + } + + /** + * Adds a method of the given name to the class being implemented that attempts to find a + * callable with the given name in the Python instance and calls through to it. + * <p> + * If <code>declaringClass</code> is null, the Python instance must provide an implementation. + * If it isn't null, a super__ method will be added for this method, and if a Python callable + * isn't found under the method's name, the super method will be called. No checking is done to + * guarantee that the superclass has a method with the same signature. + */ 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)); + Code code = classfile.addMethod(access, ret, name, parameters, exceptions); code.aload(0); code.ldc(name); if (declaringClass != null) { @@ -160,12 +313,11 @@ code.aload(tmp); Label callPython = new Label(); code.ifnonnull(callPython); - String superClass = mapClass(declaringClass); - callSuper(code, name, superClass, parameters, ret, true); + callSuper(code, name, declaringClass, parameters, ret, true); code.label(callPython); code.aload(tmp); callMethod(code, name, parameters, ret, exceptions); - addSuperMethod("super__" + name, name, superClass, parameters, ret); + addSuperMethod("super__" + name, name, declaringClass, parameters, ret); } else { code.invokestatic("org/python/compiler/ProxyMaker", "findPython", makeSig($pyObj, $pyProxy, $str)); @@ -179,143 +331,9 @@ } } - protected static class MethodDescr { - - public final Class<?> returnType; - - public final String name; - - public final Class<?>[] parameters; - - public final Class<?>[] exceptions; - - public MethodDescr(Method m) { - this(m.getName(), m.getReturnType(), m.getParameterTypes(), m.getExceptionTypes()); - } - - public MethodDescr(String name, - Class<?> returnType, - Class<?>[] parameters, - Class<?>[] exceptions) { - this.name = name; - this.returnType = returnType; - this.parameters = parameters; - this.exceptions = exceptions; - } - - @Override - public int hashCode() { - return name.hashCode() + parameters.length; - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof MethodDescr)) { - return false; - } - MethodDescr oDescr = (MethodDescr)obj; - if (!name.equals(oDescr.name) || parameters.length != oDescr.parameters.length) { - return false; - } - for (int i = 0; i < parameters.length; i++) { - if (!parameters[i].equals(oDescr.parameters[i])) { - return false; - } - } - return true; - } - } - - protected static class ConstructorDescr extends MethodDescr { - - public ConstructorDescr(Constructor<?> cons) { - this(cons.getParameterTypes(), cons.getExceptionTypes()); - } - - public ConstructorDescr(Class<?>[] parameters, Class<?>[] exceptions) { - super("<init>", Void.TYPE, parameters, exceptions); - } - } - - /** Adds a constructor that calls through to superclass and returns immediately. */ - protected void addConstructor(Constructor<?> constructor) { - Code code = addOpenConstructor(constructor); - doReturn(code, superclass); - } - - /** - * 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 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; - } - - /** - * Visits constructors from this proxy's superclass. - */ - private void visitConstructors() { - for (Constructor<?> constructor : superclass.getDeclaredConstructors()) { - if (Modifier.isPrivate(constructor.getModifiers())) { - continue; - } - visitConstructor(constructor); - } - } - - /** - * 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) { - addOverrideMethod(method); - } - - - /** - * Called for every constructor on the proxy's superclass that can be overridden by - * the proxy class. - */ - protected void visitConstructor(Constructor<?> constructor) { - addConstructor(constructor); - } - - // Super methods are added for the following three reasons: - // - // 1) for a protected non-final method add a public method with no - // super__ prefix. This gives needed access to this method for - // subclasses - // - // 2) for protected final methods, add a public method with the - // super__ prefix. This avoids the danger of trying to override a - // final method - // - // 3) For any other method that is overridden, add a method with the - // super__ prefix. This gives access to super. version or the - // method. - // - protected void addSuperMethod(Method method) { - Class<?>[] parameters = method.getParameterTypes(); - Class<?> ret = method.getReturnType(); - String superClass = mapClass(method.getDeclaringClass()); - String superName = method.getName(); - String methodName = superName; - if (Modifier.isFinal(method.getModifiers())) { - methodName = "super__" + superName; - } - addSuperMethod(methodName, superName, superClass, parameters, ret); - } - private void addSuperMethod(String methodName, String superName, - String declClass, + Class<?> declClass, Class<?>[] parameters, Class<?> ret) { if (methodName.startsWith("super__")) { @@ -330,53 +348,59 @@ return; } catch (NoSuchMethodException e) { // OK, no one else defines it, so we need to - } catch (SecurityException e) { - return; } } supernames.add(methodName); - Code code = classfile.addMethod(methodName, makeSig(ret, parameters), Modifier.PUBLIC); + Code code = classfile.addMethod(ACC_PUBLIC, ret, methodName, parameters); callSuper(code, superName, declClass, parameters, ret, true); } - /** - * Adds the methods and fields necessary to implement PyProxy. - */ private void addProxy() { + if (dict == null) { + return; + } + classfile.addInterface(mapClass(PyProxy.class)); classfile.addField("__proxy", $pyObj, Modifier.PROTECTED); - Code code = classfile.addMethod("_setPyInstance", makeSig("V", $pyObj), Modifier.PUBLIC); + Code code = classfile.addMethod(ACC_PUBLIC, Void.TYPE, "_setPyInstance", PyObject.class); code.aload(0); code.aload(1); code.putfield(classfile.name, "__proxy", $pyObj); code.return_(); - - code = classfile.addMethod("_getPyInstance", makeSig($pyObj), Modifier.PUBLIC); + code = classfile.addMethod(ACC_PUBLIC, PyObject.class, "_getPyInstance"); code.aload(0); code.getfield(classfile.name, "__proxy", $pyObj); code.areturn(); - - String pySys = "Lorg/python/core/PySystemState;"; + String pySys = "Lorg/python/core/PySystemState;"; classfile.addField("__systemState", pySys, Modifier.PROTECTED | Modifier.TRANSIENT); - - code = classfile.addMethod("_setPySystemState", makeSig("V", pySys), Modifier.PUBLIC); + code = classfile.addMethod(ACC_PUBLIC, Void.TYPE, "_setPySystemState", PySystemState.class); code.aload(0); code.aload(1); code.putfield(classfile.name, "__systemState", pySys); code.return_(); - - code = classfile.addMethod("_getPySystemState", makeSig(pySys), Modifier.PUBLIC); + code = classfile.addMethod(ACC_PUBLIC, PySystemState.class, "_getPySystemState"); code.aload(0); code.getfield(classfile.name, "__systemState", pySys); code.areturn(); + code = classfile.addMethod(ACC_PUBLIC, Void.TYPE, "__initProxy__", Object[].class); + code.visitVarInsn(ALOAD, 0); + code.visitLdcInsn(pythonModule); + code.visitLdcInsn(pythonClass); + code.visitVarInsn(ALOAD, 1); + code.visitMethodInsn(INVOKESTATIC, "org/python/core/Py", "initProxy", + makeSig("V", $pyProxy, $str, $str, $objArr)); + code.visitInsn(RETURN); } /** * Adds the classDictInit static method to fill in __supernames__ on the class' dict */ private void addClassDictInit() { - classfile.addInterface(mapClass(org.python.core.ClassDictInit.class)); - Code code = classfile.addMethod("classDictInit", makeSig("V", $pyObj), - Modifier.PUBLIC | Modifier.STATIC); + if (dict == null) { + return; + } + classfile.addInterface(mapClass(ClassDictInit.class)); + Code code = classfile.addMethod(ACC_PUBLIC | ACC_STATIC, Void.TYPE, "classDictInit", + PyObject.class); code.aload(0); code.ldc("__supernames__"); @@ -387,61 +411,4 @@ code.invokevirtual("org/python/core/PyObject", "__setitem__", makeSig("V", $str, $pyObj)); code.return_(); } - - /** - * 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) { - if (iface.isAssignableFrom(superclass)) { - Py.writeWarning("compiler", "discarding redundant interface: " + iface.getName()); - continue; - } - classfile.addInterface(mapClass(iface)); - visitMethods(iface, seenmethods); - } - return seenmethods; - } } Added: branches/customizable-proxymaker/src/org/python/compiler/VerifyingClassFile.java =================================================================== --- branches/customizable-proxymaker/src/org/python/compiler/VerifyingClassFile.java (rev 0) +++ branches/customizable-proxymaker/src/org/python/compiler/VerifyingClassFile.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -0,0 +1,109 @@ +package org.python.compiler; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +import java.util.Set; + +import org.python.core.imp; +import org.python.util.Generic; + + +public class VerifyingClassFile extends ClassFile { + + public VerifyingClassFile(String name, String superclass) { + super(name, superclass, imp.NO_MTIME, null); + } + + public boolean noteSuperclassMethod(Method meth) { + return superclassMeths.add(new MethodDescr(meth)); + } + + public boolean hasMethod(String name, Class<?> returns, Class<?>[] parameters, + Class<?>[] thrown) { + // TODO Auto-generated method stub + return false; + } + + public boolean hasConstructor(Class<?>[] parameterClasses, Class<?>[] thrownClasses) { + // TODO Auto-generated method stub + return false; + } + + public void noteSuperclassConstructor(Constructor<?> constructor) { + // TODO Auto-generated method stub + + } + + public Code addMethod(int access, Class<?> returns, String name, Class<?>...parameters) { + return addMethod(access, returns, name, parameters, new Class<?>[0]); + } + + public Code addMethod(int access, + Class<?> returns, + String name, + Class<?>[] parameters, + Class<?>... exceptions) { + return addMethod(name, ProxyCodeHelpers.makeSig(returns, parameters), access, + ProxyCodeHelpers.mapClasses(exceptions)); + } + + private static class MethodDescr { + + public final Class<?> returnType; + + public final String name; + + public final Class<?>[] parameters; + + public final Class<?>[] exceptions; + + public MethodDescr(Method m) { + this(m.getName(), m.getReturnType(), m.getParameterTypes(), m.getExceptionTypes()); + } + + public MethodDescr(String name, + Class<?> returnType, + Class<?>[] parameters, + Class<?>[] exceptions) { + this.name = name; + this.returnType = returnType; + this.parameters = parameters; + this.exceptions = exceptions; + } + + @Override + public int hashCode() { + return name.hashCode() + parameters.length; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MethodDescr)) { + return false; + } + MethodDescr oDescr = (MethodDescr)obj; + if (!name.equals(oDescr.name) || parameters.length != oDescr.parameters.length) { + return false; + } + for (int i = 0; i < parameters.length; i++) { + if (!parameters[i].equals(oDescr.parameters[i])) { + return false; + } + } + return true; + } + } + + private static class ConstructorDescr extends MethodDescr { + public ConstructorDescr(Constructor<?> cons) { + this(cons.getParameterTypes(), cons.getExceptionTypes()); + } + + public ConstructorDescr(Class<?>[] parameters, Class<?>[] exceptions) { + super("<init>", Void.TYPE, parameters, exceptions); + } + } + + protected final Set<MethodDescr> superclassMeths = Generic.set(); +} Modified: branches/customizable-proxymaker/src/org/python/core/MakeProxies.java =================================================================== --- branches/customizable-proxymaker/src/org/python/core/MakeProxies.java 2009-09-06 07:34:32 UTC (rev 6759) +++ branches/customizable-proxymaker/src/org/python/core/MakeProxies.java 2009-09-06 09:42:02 UTC (rev 6760) @@ -6,7 +6,7 @@ import java.util.List; import org.python.compiler.AdapterMaker; -import org.python.compiler.JavaMaker; +import org.python.compiler.ProxyMaker; import org.python.core.util.StringUtil; class MakeProxies { @@ -34,45 +34,44 @@ } Class<?>[] interfacesArr = interfaces.toArray(new Class<?>[interfaces.size()]); - JavaMaker javaMaker; - // Grab the proxy maker from the class if it exists, and if it does, use the proxy class - // name from the maker + ProxyMaker maker; + // Use the proxy maker from the class if it exists PyObject customProxyMaker = dict.__finditem__("__proxymaker__"); if (customProxyMaker != null) { if (module == null) { throw Py.TypeError("Classes using __proxymaker__ must define __module__"); } PyObject[] args = Py.javas2pys(superclass, interfacesArr, qualifiedClassName, dict); - javaMaker = Py.tojava(customProxyMaker.__call__(args), JavaMaker.class); - if (!StringUtil.isJavaClassName(javaMaker.proxyClassName)) { - throw Py.TypeError(javaMaker.proxyClassName + " isn't a valid Java class name. " + - "Classes must be valid Java identifiers: " + - "http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625"); + maker = Py.tojava(customProxyMaker.__call__(args), ProxyMaker.class); + if (!StringUtil.isJavaClassName(maker.proxyClassName)) { + throw Py.TypeError(maker.proxyClassName + " isn't a valid Java class name. Classes " + + "must be valid Java identifiers: " + + "http://java.sun.com/docs/books/jls/second_edition/html/lexical.doc.html#40625"); } // If we've gotten a proxy name, check if it's available on the classpath - Class<?> proxy = Py.findClass(javaMaker.proxyClassName); + Class<?> proxy = Py.findClass(maker.proxyClassName); // TODO - check proxy class version if (proxy != null) { return proxy; } } else { - javaMaker = new JavaMaker(superclass, interfacesArr, qualifiedClassName, dict); // This is a purely dynamic proxy - javaMaker.proxyClassName = proxyPrefix + qualifiedClassName + "$" + proxyNumber++; + maker = new ProxyMaker(superclass, interfacesArr, qualifiedClassName, dict, + proxyPrefix + qualifiedClassName + "$" + proxyNumber++); } - if (!javaMaker.isProxyNeeded()) { + if (!maker.isProxyNeeded()) { return null; } - byte[] bytecode = javaMaker.make(); + byte[] bytecode = maker.make(); if (customProxyMaker != null) { - saveBytecode(javaMaker.proxyClassName, bytecode, Py.getSystemState().javaproxy_dir); + saveBytecode(maker.proxyClassName, bytecode, Py.getSystemState().javaproxy_dir); } else { - saveDebugBytecode(javaMaker.proxyClassName, bytecode); + saveDebugBytecode(maker.proxyClassName, bytecode); } - return makeClass(superclass, interfaces, javaMaker.proxyClassName, bytecode); + return makeClass(superclass, interfaces, maker.proxyClassName, bytecode); } private static Class<?> makeClass(Class<?> referent, This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |