From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Move_ctypes_invoker_invalida?= =?utf8?q?tion_sequence_into_a_method=2E?= Message-ID: http://hg.python.org/jython/rev/2e7c700ddaf7 changeset: 6235:2e7c700ddaf7 user: Wayne Meissner date: Fri Jun 17 10:55:12 2011 +1000 summary: Move ctypes invoker invalidation sequence into a method. files: src/org/python/modules/jffi/Function.java | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/org/python/modules/jffi/Function.java b/src/org/python/modules/jffi/Function.java --- a/src/org/python/modules/jffi/Function.java +++ b/src/org/python/modules/jffi/Function.java @@ -110,7 +110,7 @@ @ExposedSet(name = "restype") public void setResultType(PyObject restype) { - this.invoker = null; // invalidate old invoker + invalidateInvoker(); this.restype = restype; } @@ -121,7 +121,7 @@ @ExposedSet(name = "argtypes") public void setArgTypes(PyObject parameterTypes) { - this.invoker = null; // invalidate old invoker + invalidateInvoker(); // Removing the parameter types defaults back to varargs if (parameterTypes == Py.None) { @@ -142,7 +142,7 @@ @ExposedSet(name = "errcheck") public void errcheck(PyObject errcheck) { - this.invoker = null; // invalidate old invoker + invalidateInvoker(); this.errcheck = errcheck; } @Override @@ -157,6 +157,11 @@ return createInvoker(); } + private synchronized void invalidateInvoker() { + // null out the invoker - it will be regenerated on next invocation + this.invoker = null; + } + private synchronized final Invoker createInvoker() { if (argtypes == null) { throw Py.NotImplementedError("variadic functions not supported yet; specify a parameter list"); -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Add_asm-utils_to_the_build?= Message-ID: http://hg.python.org/jython/rev/2cde62dc9425 changeset: 6237:2cde62dc9425 user: Wayne Meissner date: Fri Jun 17 21:42:19 2011 +1000 summary: Add asm-utils to the build files: build.xml | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-) diff --git a/build.xml b/build.xml --- a/build.xml +++ b/build.xml @@ -188,6 +188,7 @@ + @@ -219,6 +220,7 @@ + -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Extend_ctypes_Invoker=23invo?= =?utf8?q?ke=28=29_up_to_arity_6?= Message-ID: http://hg.python.org/jython/rev/e99b0b6a6a9a changeset: 6238:e99b0b6a6a9a user: Wayne Meissner date: Fri Jun 17 22:09:57 2011 +1000 summary: Extend ctypes Invoker#invoke() up to arity 6 files: src/org/python/modules/jffi/DefaultInvokerFactory.java | 14 ++++++- src/org/python/modules/jffi/Function.java | 19 +++++++++- src/org/python/modules/jffi/Invoker.java | 16 ++++--- src/org/python/modules/jffi/JITInvoker.java | 6 +-- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/org/python/modules/jffi/DefaultInvokerFactory.java b/src/org/python/modules/jffi/DefaultInvokerFactory.java --- a/src/org/python/modules/jffi/DefaultInvokerFactory.java +++ b/src/org/python/modules/jffi/DefaultInvokerFactory.java @@ -178,7 +178,7 @@ void marshal(HeapInvocationBuffer buffer, PyObject arg); } - private static abstract class BaseInvoker implements Invoker { + private static abstract class BaseInvoker extends Invoker { final Function jffiFunction; final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); final ParameterMarshaller[] marshallers; @@ -217,6 +217,18 @@ return invoke(new PyObject[] { arg0, arg1, arg2 }); } + public final PyObject invoke(PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3) { + return invoke(new PyObject[] { arg0, arg1, arg2, arg3 }); + } + + public final PyObject invoke(PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invoke(new PyObject[] { arg0, arg1, arg2, arg3, arg4 }); + } + + public final PyObject invoke(PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invoke(new PyObject[] { arg0, arg1, arg2, arg3, arg4, arg5 }); + } + final void checkArity(PyObject[] args) { checkArity(args.length); } diff --git a/src/org/python/modules/jffi/Function.java b/src/org/python/modules/jffi/Function.java --- a/src/org/python/modules/jffi/Function.java +++ b/src/org/python/modules/jffi/Function.java @@ -106,6 +106,11 @@ return getInvoker().invoke(arg0, arg1, arg2); } + @Override + public PyObject __call__(PyObject arg0, PyObject arg1, PyObject arg2, PyObject arg3) { + return getInvoker().invoke(arg0, arg1, arg2, arg3); + } + @ExposedGet(name = "restype") public PyObject getResultType() { @@ -216,7 +221,7 @@ this.jffiFunction = null; } - private static final class ErrCheckInvoker implements Invoker { + private static final class ErrCheckInvoker extends Invoker { private final Invoker invoker; private final PyObject errcheck; @@ -244,5 +249,17 @@ public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { return errcheck.__call__(invoker.invoke(arg1, arg2, arg3)); } + + public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return errcheck.__call__(invoker.invoke(arg1, arg2, arg3, arg4)); + } + + public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return errcheck.__call__(invoker.invoke(arg1, arg2, arg3, arg4, arg5)); + } + + public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return errcheck.__call__(invoker.invoke(arg1, arg2, arg3, arg4, arg5, arg6)); + } } } diff --git a/src/org/python/modules/jffi/Invoker.java b/src/org/python/modules/jffi/Invoker.java --- a/src/org/python/modules/jffi/Invoker.java +++ b/src/org/python/modules/jffi/Invoker.java @@ -3,11 +3,13 @@ import org.python.core.PyObject; -public interface Invoker { - public PyObject invoke(PyObject[] args); - public PyObject invoke(); - public PyObject invoke(PyObject arg1); - public PyObject invoke(PyObject arg1, PyObject arg2); - public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3); - +abstract public class Invoker { + abstract public PyObject invoke(PyObject[] args); + abstract public PyObject invoke(); + abstract public PyObject invoke(PyObject arg1); + abstract public PyObject invoke(PyObject arg1, PyObject arg2); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6); } diff --git a/src/org/python/modules/jffi/JITInvoker.java b/src/org/python/modules/jffi/JITInvoker.java --- a/src/org/python/modules/jffi/JITInvoker.java +++ b/src/org/python/modules/jffi/JITInvoker.java @@ -7,7 +7,7 @@ /** * */ -abstract public class JITInvoker implements Invoker { +abstract public class JITInvoker extends Invoker { protected static final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); private final int arity; @@ -59,8 +59,4 @@ throw Py.RuntimeError("invalid fast-int arity"); } } - - abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4); - abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5); - abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6); } -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Add_a_WeakReference_from_the?= =?utf8?q?_generated_class_back_to_the_JITHandle=2C_so_the_same?= Message-ID: http://hg.python.org/jython/rev/5d45171d9824 changeset: 6240:5d45171d9824 user: Wayne Meissner date: Fri Jun 17 23:16:31 2011 +1000 summary: Add a WeakReference from the generated class back to the JITHandle, so the same JITHandle is re-used as long as the generated class is alive. files: src/org/python/modules/jffi/JITCompiler.java | 13 ++++++++- src/org/python/modules/jffi/JITHandle.java | 12 ++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/org/python/modules/jffi/JITCompiler.java b/src/org/python/modules/jffi/JITCompiler.java --- a/src/org/python/modules/jffi/JITCompiler.java +++ b/src/org/python/modules/jffi/JITCompiler.java @@ -8,8 +8,10 @@ import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.WeakHashMap; /** * @@ -18,9 +20,12 @@ private final Map handles = new HashMap(); + + private final Map classes = Collections.synchronizedMap(new WeakHashMap()); + private final ReferenceQueue referenceQueue = new ReferenceQueue(); - private final JITHandle failedHandle = new JITHandle( + private final JITHandle failedHandle = new JITHandle(this, new JITSignature(NativeType.VOID, new NativeType[0], false, new boolean[0], CallingConvention.DEFAULT, false), true); @@ -90,11 +95,15 @@ HandleRef ref = handles.get(jitSignature); JITHandle handle = ref != null ? ref.get() : null; if (handle == null) { - handle = new JITHandle(jitSignature, false); + handle = new JITHandle(this, jitSignature, false); handles.put(jitSignature, new HandleRef(handle, jitSignature, referenceQueue)); } return handle; } } + + void registerClass(JITHandle handle, Class klass) { + classes.put(klass, handle); + } } diff --git a/src/org/python/modules/jffi/JITHandle.java b/src/org/python/modules/jffi/JITHandle.java --- a/src/org/python/modules/jffi/JITHandle.java +++ b/src/org/python/modules/jffi/JITHandle.java @@ -3,6 +3,7 @@ */ package org.python.modules.jffi; +import java.lang.ref.WeakReference; import java.lang.reflect.Constructor; import java.util.concurrent.atomic.AtomicInteger; @@ -15,9 +16,11 @@ private final JITSignature jitSignature; private volatile boolean compilationFailed = false; private final AtomicInteger counter = new AtomicInteger(0); - private volatile Class compiledClass = null; + private final JITCompiler compiler; + private WeakReference> compiledClassRef = null; - JITHandle(JITSignature signature, boolean compilationFailed) { + JITHandle(JITCompiler compiler, JITSignature signature, boolean compilationFailed) { + this.compiler = compiler; this.jitSignature = signature; this.compilationFailed = compilationFailed; } @@ -31,13 +34,16 @@ return null; } + Class compiledClass; synchronized (this) { - if (compiledClass == null) { + if (compiledClassRef == null || (compiledClass = compiledClassRef.get()) == null) { compiledClass = newInvokerClass(jitSignature); if (compiledClass == null) { compilationFailed = true; return null; } + compiler.registerClass(this, compiledClass); + compiledClassRef = new WeakReference>(compiledClass); } } -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Crunch_down_the_size_of_the_?= =?utf8?q?generated_JITInvoker_constructors_by_moving_data?= Message-ID: http://hg.python.org/jython/rev/6eb18d708f8d changeset: 6239:6eb18d708f8d user: Wayne Meissner date: Fri Jun 17 22:44:42 2011 +1000 summary: Crunch down the size of the generated JITInvoker constructors by moving data initialization up into JITInvoker files: src/org/python/modules/jffi/AbstractNumericMethodGenerator.java | 9 ++- src/org/python/modules/jffi/AsmClassBuilder.java | 23 ++------- src/org/python/modules/jffi/JITInvoker.java | 6 ++- src/org/python/modules/jffi/JITInvoker0.java | 5 +- src/org/python/modules/jffi/JITInvoker1.java | 4 +- src/org/python/modules/jffi/JITInvoker2.java | 4 +- src/org/python/modules/jffi/JITInvoker3.java | 4 +- src/org/python/modules/jffi/JITInvoker4.java | 4 +- src/org/python/modules/jffi/JITInvoker5.java | 4 +- src/org/python/modules/jffi/JITInvoker6.java | 4 +- 10 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java --- a/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java +++ b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java @@ -33,9 +33,10 @@ fallback[i] = new Label(); } - mv.getstatic(builder.getClassName(), "jffiInvoker", ci(com.kenai.jffi.Invoker.class)); + mv.getstatic(p(JITInvoker.class), "jffiInvoker", ci(com.kenai.jffi.Invoker.class)); + // [ stack now contains: Invoker ] mv.aload(0); - mv.getfield(builder.getClassName(), builder.getFunctionFieldName(), ci(com.kenai.jffi.Function.class)); + mv.getfield(p(JITInvoker.class), "jffiFunction", ci(com.kenai.jffi.Function.class)); // [ stack now contains: Invoker, Function ] final int firstParam = 1; @@ -44,7 +45,7 @@ if (signature.hasParameterConverter(i)) { mv.aload(0); // this mv.getfield(builder.getClassName(), builder.getParameterConverterFieldName(i), ci(NativeDataConverter.class)); - mv.aload(firstParam + i); // PyObject + mv.aload(firstParam + i); // PyObject parameter mv.invokevirtual(p(NativeDataConverter.class), "toNative", sig(PyObject.class, PyObject.class)); mv.astore(firstParam + i); } @@ -175,7 +176,7 @@ // Call the fallback invoker mv.aload(0); - mv.getfield(builder.getClassName(), builder.getFallbackInvokerFieldName(), ci(Invoker.class)); + mv.getfield(p(JITInvoker.class), "fallbackInvoker", ci(Invoker.class)); for (int i = 0; i < signature.getParameterCount(); i++) { mv.aload(firstParam + i); diff --git a/src/org/python/modules/jffi/AsmClassBuilder.java b/src/org/python/modules/jffi/AsmClassBuilder.java --- a/src/org/python/modules/jffi/AsmClassBuilder.java +++ b/src/org/python/modules/jffi/AsmClassBuilder.java @@ -75,16 +75,11 @@ // Invokes the super class constructor as super(Library) init.aload(0); + init.aload(1); // jffi Function + init.aload(4); // fallback Invoker - init.invokespecial(p(parentClass), "", sig(void.class)); - - // Save the function argument in a field - classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getFunctionFieldName(), - ci(com.kenai.jffi.Function.class), null, null); - init.aload(0); - init.aload(1); - init.putfield(className, getFunctionFieldName(), ci(com.kenai.jffi.Function.class)); - + init.invokespecial(p(parentClass), "", sig(void.class, com.kenai.jffi.Function.class, Invoker.class)); + if (signature.hasResultConverter()) { // Save the result converter argument in a field classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getResultConverterFieldName(), @@ -106,13 +101,7 @@ init.putfield(className, getParameterConverterFieldName(i), ci(NativeDataConverter.class)); } } - - classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getFallbackInvokerFieldName(), - ci(Invoker.class), null, null); - init.aload(0); - init.aload(4); - init.putfield(className, getFallbackInvokerFieldName(), ci(Invoker.class)); - + init.voidreturn(); init.visitMaxs(10, 10); init.visitEnd(); @@ -160,7 +149,7 @@ final String getFunctionFieldName() { - return "function"; + return "jffiFunction"; } final String getResultConverterFieldName() { diff --git a/src/org/python/modules/jffi/JITInvoker.java b/src/org/python/modules/jffi/JITInvoker.java --- a/src/org/python/modules/jffi/JITInvoker.java +++ b/src/org/python/modules/jffi/JITInvoker.java @@ -9,10 +9,14 @@ */ abstract public class JITInvoker extends Invoker { protected static final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); + protected final com.kenai.jffi.Function jffiFunction; + protected final Invoker fallbackInvoker; private final int arity; - protected JITInvoker(int arity) { + protected JITInvoker(int arity, com.kenai.jffi.Function function, Invoker fallbackInvoker) { this.arity = arity; + this.jffiFunction = function; + this.fallbackInvoker = fallbackInvoker; } protected final PyObject invalidArity(int got) { diff --git a/src/org/python/modules/jffi/JITInvoker0.java b/src/org/python/modules/jffi/JITInvoker0.java --- a/src/org/python/modules/jffi/JITInvoker0.java +++ b/src/org/python/modules/jffi/JITInvoker0.java @@ -1,13 +1,14 @@ package org.python.modules.jffi; +import com.kenai.jffi.*; import org.python.core.PyObject; /** * */ abstract public class JITInvoker0 extends JITInvoker { - public JITInvoker0() { - super(0); + public JITInvoker0(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(0, function, fallbackInvoker); } public final PyObject invoke(PyObject arg1) { diff --git a/src/org/python/modules/jffi/JITInvoker1.java b/src/org/python/modules/jffi/JITInvoker1.java --- a/src/org/python/modules/jffi/JITInvoker1.java +++ b/src/org/python/modules/jffi/JITInvoker1.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker1 extends JITInvoker { - public JITInvoker1() { - super(1); + public JITInvoker1(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(1, function, fallbackInvoker); } public final PyObject invoke() { diff --git a/src/org/python/modules/jffi/JITInvoker2.java b/src/org/python/modules/jffi/JITInvoker2.java --- a/src/org/python/modules/jffi/JITInvoker2.java +++ b/src/org/python/modules/jffi/JITInvoker2.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker2 extends JITInvoker { - public JITInvoker2() { - super(2); + public JITInvoker2(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(2, function, fallbackInvoker); } public final PyObject invoke() { diff --git a/src/org/python/modules/jffi/JITInvoker3.java b/src/org/python/modules/jffi/JITInvoker3.java --- a/src/org/python/modules/jffi/JITInvoker3.java +++ b/src/org/python/modules/jffi/JITInvoker3.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker3 extends JITInvoker { - public JITInvoker3() { - super(3); + public JITInvoker3(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(3, function, fallbackInvoker); } public final PyObject invoke() { diff --git a/src/org/python/modules/jffi/JITInvoker4.java b/src/org/python/modules/jffi/JITInvoker4.java --- a/src/org/python/modules/jffi/JITInvoker4.java +++ b/src/org/python/modules/jffi/JITInvoker4.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker4 extends JITInvoker { - public JITInvoker4() { - super(4); + public JITInvoker4(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(4, function, fallbackInvoker); } public final PyObject invoke() { diff --git a/src/org/python/modules/jffi/JITInvoker5.java b/src/org/python/modules/jffi/JITInvoker5.java --- a/src/org/python/modules/jffi/JITInvoker5.java +++ b/src/org/python/modules/jffi/JITInvoker5.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker5 extends JITInvoker { - public JITInvoker5() { - super(5); + public JITInvoker5(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(5, function, fallbackInvoker); } public final PyObject invoke() { diff --git a/src/org/python/modules/jffi/JITInvoker6.java b/src/org/python/modules/jffi/JITInvoker6.java --- a/src/org/python/modules/jffi/JITInvoker6.java +++ b/src/org/python/modules/jffi/JITInvoker6.java @@ -6,8 +6,8 @@ * */ abstract public class JITInvoker6 extends JITInvoker { - public JITInvoker6() { - super(6); + public JITInvoker6(com.kenai.jffi.Function function, Invoker fallbackInvoker) { + super(6, function, fallbackInvoker); } public final PyObject invoke() { -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:26 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:26 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Bump_ctypes_jit_compilation_?= =?utf8?q?threshold_to_100?= Message-ID: http://hg.python.org/jython/rev/6792a9cea71d changeset: 6243:6792a9cea71d user: Wayne Meissner date: Sun Sep 04 11:25:51 2011 +1000 summary: Bump ctypes jit compilation threshold to 100 files: src/org/python/modules/jffi/JITHandle.java | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/src/org/python/modules/jffi/JITHandle.java b/src/org/python/modules/jffi/JITHandle.java --- a/src/org/python/modules/jffi/JITHandle.java +++ b/src/org/python/modules/jffi/JITHandle.java @@ -12,7 +12,7 @@ */ final class JITHandle { - private static final int THRESHOLD = Integer.getInteger("jython.ctypes.compile.threshold", 10); + private static final int THRESHOLD = Integer.getInteger("jython.ctypes.compile.threshold", 100); private final JITSignature jitSignature; private volatile boolean compilationFailed = false; private final AtomicInteger counter = new AtomicInteger(0); -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Rework_and_simplify_some_of_?= =?utf8?q?the_generated_code_for_ctypes=2C_and_the_associated?= Message-ID: http://hg.python.org/jython/rev/d5690b8327ad changeset: 6241:d5690b8327ad user: Wayne Meissner date: Sat Jun 18 18:52:00 2011 +1000 summary: Rework and simplify some of the generated code for ctypes, and the associated JITRuntime methods. files: src/org/python/modules/jffi/AbstractNumericMethodGenerator.java | 52 +-- src/org/python/modules/jffi/JITRuntime.java | 117 ++++++++- src/org/python/modules/jffi/ScalarCData.java | 9 +- 3 files changed, 132 insertions(+), 46 deletions(-) diff --git a/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java --- a/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java +++ b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java @@ -135,11 +135,11 @@ break; case FLOAT: - unbox(mv, "float2int"); + unbox(mv, "f32Value"); break; case DOUBLE: - unbox(mv, "double2long"); + unbox(mv, "f64Value"); break; default: @@ -197,90 +197,84 @@ mv.invokevirtual(p(NativeDataConverter.class), "fromNative", sig(PyObject.class, PyObject.class)); } } - - private void boxResult(SkinnyMethodAdapter mv, NativeType type, - String boxMethodName, Class primitiveType) { - // convert to the appropriate primitive result type - narrow(mv, getInvokerIntType(), primitiveType); - widen(mv, getInvokerIntType(), primitiveType); - + + private void boxResult(SkinnyMethodAdapter mv, String boxMethodName) { mv.invokestatic(p(JITRuntime.class), boxMethodName, - sig(PyObject.class, primitiveType)); + sig(PyObject.class, getInvokerIntType())); } private void boxResult(SkinnyMethodAdapter mv, NativeType type) { switch (type) { case BOOL: - boxResult(mv, type, "newBoolean", getInvokerIntType()); + boxResult(mv, "newBoolean"); break; case BYTE: - boxResult(mv, type, "newSigned8", byte.class); + boxResult(mv, "newSigned8"); break; case UBYTE: - boxResult(mv, type, "newUnsigned8", byte.class); + boxResult(mv, "newUnsigned8"); break; case SHORT: - boxResult(mv, type, "newSigned16", short.class); + boxResult(mv, "newSigned16"); break; case USHORT: - boxResult(mv, type, "newUnsigned16", short.class); + boxResult(mv, "newUnsigned16"); break; case INT: - boxResult(mv, type, "newSigned32", int.class); + boxResult(mv, "newSigned32"); break; case UINT: - boxResult(mv, type, "newUnsigned32", int.class); + boxResult(mv, "newUnsigned32"); break; case LONG: if (Platform.getPlatform().longSize() == 32) { - boxResult(mv, type, "newSigned32", int.class); + boxResult(mv, "newSigned32"); } else { - boxResult(mv, type, "newSigned64", long.class); + boxResult(mv, "newSigned64"); } break; case ULONG: if (Platform.getPlatform().longSize() == 32) { - boxResult(mv, type, "newUnsigned32", int.class); + boxResult(mv, "newUnsigned32"); } else { - boxResult(mv, type, "newUnsigned64", long.class); + boxResult(mv, "newUnsigned64"); } break; case LONGLONG: - boxResult(mv, type, "newSigned64", long.class); + boxResult(mv, "newSigned64"); break; case ULONGLONG: - boxResult(mv, type, "newUnsigned64", long.class); + boxResult(mv, "newUnsigned64"); break; case FLOAT: - boxResult(mv, type, "newFloat32", int.class); + boxResult(mv, "newFloat32"); break; case DOUBLE: - boxResult(mv, type, "newFloat64", long.class); + boxResult(mv, "newFloat64"); break; case VOID: - boxResult(mv, type, "newNil", getInvokerIntType()); + boxResult(mv, "newNone"); break; case POINTER: - boxResult(mv, type, "newPointer" + Platform.getPlatform().addressSize(), - getInvokerIntType()); + boxResult(mv, "newPointer" + Platform.getPlatform().addressSize()); break; case STRING: - boxResult(mv, type, "newString", getInvokerIntType()); + boxResult(mv, "newString"); break; diff --git a/src/org/python/modules/jffi/JITRuntime.java b/src/org/python/modules/jffi/JITRuntime.java --- a/src/org/python/modules/jffi/JITRuntime.java +++ b/src/org/python/modules/jffi/JITRuntime.java @@ -11,6 +11,8 @@ * */ public final class JITRuntime { + private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); + private JITRuntime() {} public static int pointerValue32(PyObject ptr) { @@ -28,10 +30,14 @@ } else if (parameter instanceof PyLong) { return ((PyLong) parameter).getValue().intValue(); + } else if (parameter instanceof ScalarCData) { + return intValue(((ScalarCData) parameter).getValue()); + } else { return (int) __long__value(parameter); } } + public static long longValue(PyObject parameter) { if (parameter instanceof PyInteger) { return ((PyInteger) parameter).getValue(); @@ -39,6 +45,9 @@ } else if (parameter instanceof PyLong) { return ((PyLong) parameter).getValue().longValue(); + } else if (parameter instanceof ScalarCData) { + return longValue(((ScalarCData) parameter).getValue()); + } else { return __long__value(parameter); } @@ -78,7 +87,7 @@ } public static long u8Value64(PyObject parameter) { - return ((long) intValue(parameter)) & 0xffL; + return intValue(parameter) & 0xff; } public static int s16Value32(PyObject parameter) { @@ -94,7 +103,7 @@ } public static long u16Value64(PyObject parameter) { - return ((long) intValue(parameter)) & 0xffffL; + return intValue(parameter) & 0xffff; } @@ -111,7 +120,7 @@ } public static long u32Value64(PyObject parameter) { - return ((long) intValue(parameter)) & 0xffffffffL; + return intValue(parameter) & 0xffffffffL; } public static long s64Value64(PyObject parameter) { @@ -122,41 +131,75 @@ return longValue(parameter); } - public static int float2int32(PyObject parameter) { + public static int f32Value32(PyObject parameter) { return Float.floatToRawIntBits((float) parameter.asDouble()); } - public static long float2int64(PyObject parameter) { + public static long f32Value64(PyObject parameter) { return Float.floatToRawIntBits((float) parameter.asDouble()); } - public static long double2long64(PyObject parameter) { + public static long f64Value64(PyObject parameter) { return Double.doubleToRawLongBits(parameter.asDouble()); } - public static PyObject newSigned8(byte value) { - return Py.newInteger(value); + public static PyObject newSigned8(int value) { + return Py.newInteger((byte) value); } - public static PyObject newUnsigned8(byte value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FL) + 0x80L) : value); + public static PyObject newSigned8(long value) { + return Py.newInteger((byte) value); } - public static PyObject newSigned16(short value) { - return Py.newInteger(value); + public static PyObject newUnsigned8(int value) { + int n = (byte) value; // sign-extend the low 8 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7F) + 0x80) : n); } - public static PyObject newUnsigned16(short value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FFFL) + 0x8000L) : value); + public static PyObject newUnsigned8(long value) { + int n = (byte) value; // sign-extend the low 8 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7F) + 0x80) : n); + } + + public static PyObject newSigned16(int value) { + return Py.newInteger((short) value); + } + + public static PyObject newSigned16(long value) { + return Py.newInteger((short) value); + } + + public static PyObject newUnsigned16(int value) { + int n = (short) value; // sign-extend the low 16 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7FFF) + 0x8000) : n); + } + + public static PyObject newUnsigned16(long value) { + int n = (short) value; // sign-extend the low 16 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7FFF) + 0x8000) : n); } public static PyObject newSigned32(int value) { return Py.newInteger(value); } + public static PyObject newSigned32(long value) { + return Py.newInteger((int) value); + } + public static PyObject newUnsigned32(int value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FFFFFFFL) + 0x80000000L) : value); + int n = value; + return n < 0 ? Py.newInteger(((n & 0x7FFFFFFFL) + 0x80000000L)) : Py.newInteger(n); + } + + public static PyObject newUnsigned32(long value) { + long n = (int) value; // only keep the low 32 bits + return n < 0 ? Py.newInteger(((n & 0x7FFFFFFFL) + 0x80000000L)) : Py.newInteger(n); + } + + public static PyObject newSigned64(int value) { + return Py.newInteger(value); } public static PyObject newSigned64(long value) { @@ -174,7 +217,51 @@ return Py.newFloat(Float.intBitsToFloat(value)); } + public static PyObject newFloat32(long value) { + return Py.newFloat(Float.intBitsToFloat((int) value)); + } + public static PyObject newFloat64(long value) { return Py.newFloat(Double.longBitsToDouble(value)); } + + public static PyObject newBoolean(int value) { + return (value & 0x1) != 0 ? Py.True : Py.False; + } + + public static PyObject newBoolean(long value) { + return (value & 0x1) != 0 ? Py.True : Py.False; + } + + public static PyObject newNone(int unused) { + return Py.None; + } + + public static PyObject newNone(long unused) { + return Py.None; + } + + public static PyObject newPointer32(int value) { + return Py.newLong(value); + } + + public static PyObject newPointer32(long value) { + return Py.newLong(value & 0xffffffffL); + } + + public static PyObject newPointer64(long value) { + return Py.newLong(value); + } + + public static PyObject newString(int address) { + return address != 0 + ? Py.newString(new String(IO.getZeroTerminatedByteArray(address))) + : Py.None; + } + + public static PyObject newString(long address) { + return address != 0L + ? Py.newString(new String(IO.getZeroTerminatedByteArray(address))) + : Py.None; + } } diff --git a/src/org/python/modules/jffi/ScalarCData.java b/src/org/python/modules/jffi/ScalarCData.java --- a/src/org/python/modules/jffi/ScalarCData.java +++ b/src/org/python/modules/jffi/ScalarCData.java @@ -22,7 +22,7 @@ static { // TYPE.fastGetDict().__setitem__("in_dll", new InDll()); } - private PyObject value = Py.None; + private PyObject value; @ExposedNew public static PyObject ScalarCData_new(PyNewWrapper new_, boolean init, PyType subtype, @@ -65,12 +65,13 @@ @ExposedGet(name = "value") public PyObject getValue() { + // If native memory has been allocated, read the value from there if (hasReferenceMemory()) { return getMemoryOp().get(getReferenceMemory(), 0); } - return value; + return value != null ? value : Py.None; } @@ -94,6 +95,10 @@ return getValue().asLong(index); } + public long asLong() { + return getValue().asLong(); + } + @ExposedMethod @Override public PyObject __int__() { -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Move_some_of_the_common_meth?= =?utf8?q?ods_from_JITRuntime_to_Util_and_fixup_the_Util?= Message-ID: http://hg.python.org/jython/rev/9c75ec1c71f5 changeset: 6242:9c75ec1c71f5 user: Wayne Meissner date: Sat Jun 18 19:16:53 2011 +1000 summary: Move some of the common methods from JITRuntime to Util and fixup the Util equivalents of some JITRuntime helper methods files: src/org/python/modules/jffi/DefaultInvokerFactory.java | 14 +- src/org/python/modules/jffi/JITRuntime.java | 73 +------- src/org/python/modules/jffi/Util.java | 84 ++++++--- 3 files changed, 73 insertions(+), 98 deletions(-) diff --git a/src/org/python/modules/jffi/DefaultInvokerFactory.java b/src/org/python/modules/jffi/DefaultInvokerFactory.java --- a/src/org/python/modules/jffi/DefaultInvokerFactory.java +++ b/src/org/python/modules/jffi/DefaultInvokerFactory.java @@ -282,7 +282,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newSigned16(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); + return JITRuntime.newSigned16(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); } } @@ -293,7 +293,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newUnsigned16(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); + return JITRuntime.newUnsigned16(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); } } @@ -304,7 +304,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newSigned32(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); + return JITRuntime.newSigned32(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); } } @@ -315,7 +315,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newUnsigned32(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); + return JITRuntime.newUnsigned32(jffiInvoker.invokeInt(jffiFunction, convertArguments(args))); } } @@ -326,7 +326,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newSigned64(jffiInvoker.invokeLong(jffiFunction, convertArguments(args))); + return JITRuntime.newSigned64(jffiInvoker.invokeLong(jffiFunction, convertArguments(args))); } } @@ -337,7 +337,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newUnsigned64(jffiInvoker.invokeLong(jffiFunction, convertArguments(args))); + return JITRuntime.newUnsigned64(jffiInvoker.invokeLong(jffiFunction, convertArguments(args))); } } @@ -381,7 +381,7 @@ } public final PyObject invoke(PyObject[] args) { - return Util.newString(jffiInvoker.invokeAddress(jffiFunction, convertArguments(args))); + return JITRuntime.newString(jffiInvoker.invokeAddress(jffiFunction, convertArguments(args))); } } diff --git a/src/org/python/modules/jffi/JITRuntime.java b/src/org/python/modules/jffi/JITRuntime.java --- a/src/org/python/modules/jffi/JITRuntime.java +++ b/src/org/python/modules/jffi/JITRuntime.java @@ -1,8 +1,6 @@ package org.python.modules.jffi; import org.python.core.Py; -import org.python.core.PyInteger; -import org.python.core.PyLong; import org.python.core.PyObject; import java.math.BigInteger; @@ -23,49 +21,6 @@ return ((Pointer) ptr).getMemory().getAddress(); } - public static int intValue(PyObject parameter) { - if (parameter instanceof PyInteger) { - return ((PyInteger) parameter).getValue(); - - } else if (parameter instanceof PyLong) { - return ((PyLong) parameter).getValue().intValue(); - - } else if (parameter instanceof ScalarCData) { - return intValue(((ScalarCData) parameter).getValue()); - - } else { - return (int) __long__value(parameter); - } - } - - public static long longValue(PyObject parameter) { - if (parameter instanceof PyInteger) { - return ((PyInteger) parameter).getValue(); - - } else if (parameter instanceof PyLong) { - return ((PyLong) parameter).getValue().longValue(); - - } else if (parameter instanceof ScalarCData) { - return longValue(((ScalarCData) parameter).getValue()); - - } else { - return __long__value(parameter); - } - } - - static final long __long__value(PyObject parameter) { - PyObject value = parameter.__long__(); - - if (value instanceof PyLong) { - return ((PyLong) value).getValue().longValue(); - - } else if (value instanceof PyInteger) { - return ((PyInteger) value).getValue(); - } - - throw Py.TypeError("invalid __long__() result"); - } - public static int boolValue32(PyObject parameter) { return parameter.__nonzero__() ? 1 : 0; } @@ -75,60 +30,60 @@ } public static int s8Value32(PyObject parameter) { - return (byte) intValue(parameter); + return (byte) Util.intValue(parameter); } public static long s8Value64(PyObject parameter) { - return (byte) intValue(parameter); + return (byte) Util.intValue(parameter); } public static int u8Value32(PyObject parameter) { - return intValue(parameter) & 0xff; + return Util.intValue(parameter) & 0xff; } public static long u8Value64(PyObject parameter) { - return intValue(parameter) & 0xff; + return Util.intValue(parameter) & 0xff; } public static int s16Value32(PyObject parameter) { - return (short) intValue(parameter); + return (short) Util.intValue(parameter); } public static long s16Value64(PyObject parameter) { - return (short) intValue(parameter); + return (short) Util.intValue(parameter); } public static int u16Value32(PyObject parameter) { - return intValue(parameter) & 0xffff; + return Util.intValue(parameter) & 0xffff; } public static long u16Value64(PyObject parameter) { - return intValue(parameter) & 0xffff; + return Util.intValue(parameter) & 0xffff; } public static int s32Value32(PyObject parameter) { - return intValue(parameter); + return Util.intValue(parameter); } public static long s32Value64(PyObject parameter) { - return intValue(parameter); + return Util.intValue(parameter); } public static int u32Value32(PyObject parameter) { - return intValue(parameter); + return Util.intValue(parameter); } public static long u32Value64(PyObject parameter) { - return intValue(parameter) & 0xffffffffL; + return Util.intValue(parameter) & 0xffffffffL; } public static long s64Value64(PyObject parameter) { - return longValue(parameter); + return Util.longValue(parameter); } public static long u64Value64(PyObject parameter) { - return longValue(parameter); + return Util.longValue(parameter); } public static int f32Value32(PyObject parameter) { diff --git a/src/org/python/modules/jffi/Util.java b/src/org/python/modules/jffi/Util.java --- a/src/org/python/modules/jffi/Util.java +++ b/src/org/python/modules/jffi/Util.java @@ -2,8 +2,7 @@ package org.python.modules.jffi; import java.math.BigInteger; -import java.util.HashMap; -import java.util.Map; + import org.python.core.Py; import org.python.core.PyInteger; import org.python.core.PyLong; @@ -13,23 +12,23 @@ private static final com.kenai.jffi.MemoryIO IO = com.kenai.jffi.MemoryIO.getInstance(); private Util() {} - + public static final PyObject newSigned8(int value) { - value &= 0xff; - return Py.newInteger(value < 0x80 ? value : -0x80 + (value - 0x80)); + return Py.newInteger((byte) value); } public static final PyObject newUnsigned8(int value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FL) + 0x80L) : value); + int n = (byte) value; // sign-extend the low 8 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7F) + 0x80) : n); } public static final PyObject newSigned16(int value) { - value &= 0xffff; - return Py.newInteger(value < 0x8000 ? value : -0x8000 + (value - 0x8000)); + return Py.newInteger((short) value); } public static final PyObject newUnsigned16(int value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FFFL) + 0x8000L) : value); + int n = (short) value; // sign-extend the low 16 bits to 32 + return Py.newInteger(n < 0 ? ((n & 0x7FFF) + 0x8000) : n); } public static final PyObject newSigned32(int value) { @@ -37,7 +36,8 @@ } public static final PyObject newUnsigned32(int value) { - return Py.newInteger(value < 0 ? (long)((value & 0x7FFFFFFFL) + 0x80000000L) : value); + int n = value; + return n < 0 ? Py.newInteger(((n & 0x7FFFFFFFL) + 0x80000000L)) : Py.newInteger(n); } public static final PyObject newSigned64(long value) { @@ -58,47 +58,35 @@ } public static final byte int8Value(PyObject parameter) { - return (byte) parameter.asInt(); + return (byte) intValue(parameter); } public static final byte uint8Value(PyObject parameter) { - return (byte) parameter.asInt(); + return (byte) intValue(parameter); } public static final short int16Value(PyObject parameter) { - return (short) parameter.asInt(); + return (short) intValue(parameter); } public static final short uint16Value(PyObject parameter) { - return (short) parameter.asInt(); + return (short) intValue(parameter); } public static final int int32Value(PyObject parameter) { - return parameter.asInt(); + return intValue(parameter); } - public static final int uint32Value(PyObject value) { - if (value instanceof PyInteger) { - return value.asInt(); - } else if (value instanceof PyLong) { - return (int) ((PyLong) value).asLong(0); - } else { - return (int) __long__value(value); - } + public static final int uint32Value(PyObject parameter) { + return intValue(parameter); } public static final long int64Value(PyObject value) { - return value.asLong(); + return longValue(value); } public static final long uint64Value(PyObject value) { - if (value instanceof PyLong) { - return ((PyLong) value).getValue().longValue(); - } else if (value instanceof PyInteger) { - return value.asInt(); - } else { - return __long__value(value); - } + return longValue(value); } public static final float floatValue(PyObject parameter) { @@ -113,9 +101,11 @@ PyObject l = value.__long__(); if (l instanceof PyLong) { return ((PyLong) l).getValue().longValue(); + } else if (l instanceof PyInteger) { - return value.asInt(); + return ((PyInteger) l).getValue(); } + throw Py.TypeError("invalid __long__() result"); } @@ -140,4 +130,34 @@ static final com.kenai.jffi.Type jffiType(CType type) { return (com.kenai.jffi.Type) type.jffiType(); } + + public static int intValue(PyObject parameter) { + if (parameter instanceof PyInteger) { + return ((PyInteger) parameter).getValue(); + + } else if (parameter instanceof PyLong) { + return ((PyLong) parameter).getValue().intValue(); + + } else if (parameter instanceof ScalarCData) { + return intValue(((ScalarCData) parameter).getValue()); + + } else { + return (int) __long__value(parameter); + } + } + + public static long longValue(PyObject parameter) { + if (parameter instanceof PyInteger) { + return ((PyInteger) parameter).getValue(); + + } else if (parameter instanceof PyLong) { + return ((PyLong) parameter).getValue().longValue(); + + } else if (parameter instanceof ScalarCData) { + return longValue(((ScalarCData) parameter).getValue()); + + } else { + return __long__value(parameter); + } + } } -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Sun Sep 4 03:55:25 2011 From: jython-checkins at python.org (wayne.meissner) Date: Sun, 04 Sep 2011 03:55:25 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Implement_a_simple_JIT_for_c?= =?utf8?q?types_functions=2E?= Message-ID: http://hg.python.org/jython/rev/e3b713cd58c9 changeset: 6236:e3b713cd58c9 user: Wayne Meissner date: Fri Jun 17 21:41:57 2011 +1000 summary: Implement a simple JIT for ctypes functions. files: src/org/python/modules/jffi/AbstractNumericMethodGenerator.java | 359 +++ src/org/python/modules/jffi/AsmClassBuilder.java | 203 ++ src/org/python/modules/jffi/CodegenUtils.java | 255 ++ src/org/python/modules/jffi/DefaultInvokerFactory.java | 102 +- src/org/python/modules/jffi/FastIntInvokerFactory.java | 656 ------- src/org/python/modules/jffi/FastIntMethodGenerator.java | 141 + src/org/python/modules/jffi/FastLongMethodGenerator.java | 129 + src/org/python/modules/jffi/FastNumericMethodGenerator.java | 128 + src/org/python/modules/jffi/Function.java | 88 +- src/org/python/modules/jffi/JITCompiler.java | 100 + src/org/python/modules/jffi/JITHandle.java | 86 + src/org/python/modules/jffi/JITInvoker.java | 66 + src/org/python/modules/jffi/JITInvoker0.java | 36 + src/org/python/modules/jffi/JITInvoker1.java | 36 + src/org/python/modules/jffi/JITInvoker2.java | 36 + src/org/python/modules/jffi/JITInvoker3.java | 36 + src/org/python/modules/jffi/JITInvoker4.java | 36 + src/org/python/modules/jffi/JITInvoker5.java | 36 + src/org/python/modules/jffi/JITInvoker6.java | 40 + src/org/python/modules/jffi/JITMethodGenerator.java | 11 + src/org/python/modules/jffi/JITRuntime.java | 180 + src/org/python/modules/jffi/JITSignature.java | 81 + src/org/python/modules/jffi/NativeDataConverter.java | 35 + src/org/python/modules/jffi/NativeType.java | 3 + src/org/python/modules/jffi/SkinnyMethodAdapter.java | 915 ++++++++++ 25 files changed, 3067 insertions(+), 727 deletions(-) diff --git a/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/AbstractNumericMethodGenerator.java @@ -0,0 +1,359 @@ +package org.python.modules.jffi; + +import com.kenai.jffi.Platform; +import org.objectweb.asm.Label; +import org.python.core.PyObject; + +import static org.python.modules.jffi.CodegenUtils.*; +import static org.objectweb.asm.Opcodes.ACC_FINAL; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; + +/** + * + */ +abstract class AbstractNumericMethodGenerator implements JITMethodGenerator { + + public void generate(AsmClassBuilder builder, String functionName, JITSignature signature) { + SkinnyMethodAdapter mv = new SkinnyMethodAdapter(builder.getClassVisitor(), + ACC_PUBLIC | ACC_FINAL, functionName, + sig(PyObject.class, params(PyObject.class, signature.getParameterCount())), + null, null); + + mv.start(); + generate(builder, mv, signature); + mv.visitMaxs(10, 10); + mv.visitEnd(); + } + + public void generate(AsmClassBuilder builder, SkinnyMethodAdapter mv, JITSignature signature) { + final Class nativeIntType = getInvokerIntType(); + int maxPointerIndex = -1; + Label[] fallback = new Label[signature.getParameterCount()]; + for (int i = 0; i < signature.getParameterCount(); i++) { + fallback[i] = new Label(); + } + + mv.getstatic(builder.getClassName(), "jffiInvoker", ci(com.kenai.jffi.Invoker.class)); + mv.aload(0); + mv.getfield(builder.getClassName(), builder.getFunctionFieldName(), ci(com.kenai.jffi.Function.class)); + // [ stack now contains: Invoker, Function ] + final int firstParam = 1; + + // Perform any generic data conversions on the parameters + for (int i = 0; i < signature.getParameterCount(); ++i) { + if (signature.hasParameterConverter(i)) { + mv.aload(0); // this + mv.getfield(builder.getClassName(), builder.getParameterConverterFieldName(i), ci(NativeDataConverter.class)); + mv.aload(firstParam + i); // PyObject + mv.invokevirtual(p(NativeDataConverter.class), "toNative", sig(PyObject.class, PyObject.class)); + mv.astore(firstParam + i); + } + } + + // Load and un-box parameters + for (int i = 0; i < signature.getParameterCount(); ++i) { + final NativeType parameterType = signature.getParameterType(i); + final int paramVar = i + firstParam; + mv.aload(paramVar); + switch (parameterType) { + case BOOL: + unbox(mv, "boolValue"); + break; + + case BYTE: + unbox(mv, "s8Value"); + break; + + case UBYTE: + unbox(mv, "u8Value"); + break; + + case SHORT: + unbox(mv, "s16Value"); + break; + + case USHORT: + unbox(mv, "u16Value"); + break; + + case INT: + unbox(mv, "s32Value"); + break; + + case UINT: + unbox(mv, "u32Value"); + break; + + case LONG: + if (Platform.getPlatform().longSize() == 32) { + unbox(mv, "s32Value"); + } else { + unbox(mv, "s64Value"); + } + break; + + case ULONG: + if (Platform.getPlatform().longSize() == 32) { + unbox(mv, "u32Value"); + } else { + unbox(mv, "u64Value"); + } + break; + + case LONGLONG: + unbox(mv, "s64Value"); + break; + + case ULONGLONG: + unbox(mv, "u64Value"); + break; + + case POINTER: + maxPointerIndex = i; + Label direct = new Label(); + Label done = new Label(); + Label converted = new Label(); + + // If a direct pointer is passed in, jump straight to conversion + mv.instance_of(p(Pointer.class)); + mv.iftrue(direct); + + mv.aload(paramVar); + mv.invokestatic(p(JITRuntime.class), "other2ptr", sig(PyObject.class, PyObject.class)); + mv.label(converted); + mv.dup(); + mv.astore(paramVar); + mv.instance_of(p(Pointer.class)); + mv.iffalse(fallback[i]); + + mv.label(direct); + // The parameter is guaranteed to be a direct pointer now + mv.aload(paramVar); + unbox(mv, "pointerValue"); + mv.label(done); + break; + + case FLOAT: + unbox(mv, "float2int"); + break; + + case DOUBLE: + unbox(mv, "double2long"); + break; + + default: + throw new UnsupportedOperationException("unsupported parameter type " + parameterType); + } + } + + // stack now contains [ Invoker, Function, int/long args ] + mv.invokevirtual(p(com.kenai.jffi.Invoker.class), + getInvokerMethodName(signature), + getInvokerSignature(signature.getParameterCount())); + + + // box up the raw int/long result + boxResult(mv, signature.getResultType()); + emitResultConversion(mv, builder, signature);; + mv.areturn(); + + // Generate code to pop all the converted arguments off the stack + // when falling back to buffer-invocation + if (maxPointerIndex >= 0) { + for (int i = maxPointerIndex; i > 0; i--) { + mv.label(fallback[i]); + if (int.class == nativeIntType) { + mv.pop(); + } else { + mv.pop2(); + } + } + + mv.label(fallback[0]); + // Pop ThreadContext, Invoker and Function + mv.pop(); mv.pop(); + + // Call the fallback invoker + mv.aload(0); + mv.getfield(builder.getClassName(), builder.getFallbackInvokerFieldName(), ci(Invoker.class)); + + for (int i = 0; i < signature.getParameterCount(); i++) { + mv.aload(firstParam + i); + } + + mv.invokevirtual(p(Invoker.class), "invoke", + sig(PyObject.class, params(PyObject.class, signature.getParameterCount()))); + emitResultConversion(mv, builder, signature); + mv.areturn(); + } + } + + private void emitResultConversion(SkinnyMethodAdapter mv, AsmClassBuilder builder, JITSignature signature) { + if (signature.hasResultConverter()) { + mv.aload(0); // [ result, this ] + mv.getfield(builder.getClassName(), builder.getResultConverterFieldName(), ci(NativeDataConverter.class)); + mv.swap(); // [ converter, result ] + mv.invokevirtual(p(NativeDataConverter.class), "fromNative", sig(PyObject.class, PyObject.class)); + } + } + + private void boxResult(SkinnyMethodAdapter mv, NativeType type, + String boxMethodName, Class primitiveType) { + // convert to the appropriate primitive result type + narrow(mv, getInvokerIntType(), primitiveType); + widen(mv, getInvokerIntType(), primitiveType); + + mv.invokestatic(p(JITRuntime.class), boxMethodName, + sig(PyObject.class, primitiveType)); + } + + private void boxResult(SkinnyMethodAdapter mv, NativeType type) { + switch (type) { + case BOOL: + boxResult(mv, type, "newBoolean", getInvokerIntType()); + break; + + case BYTE: + boxResult(mv, type, "newSigned8", byte.class); + break; + + case UBYTE: + boxResult(mv, type, "newUnsigned8", byte.class); + break; + + case SHORT: + boxResult(mv, type, "newSigned16", short.class); + break; + + case USHORT: + boxResult(mv, type, "newUnsigned16", short.class); + break; + + case INT: + boxResult(mv, type, "newSigned32", int.class); + break; + + case UINT: + boxResult(mv, type, "newUnsigned32", int.class); + break; + + case LONG: + if (Platform.getPlatform().longSize() == 32) { + boxResult(mv, type, "newSigned32", int.class); + } else { + boxResult(mv, type, "newSigned64", long.class); + } + break; + + case ULONG: + if (Platform.getPlatform().longSize() == 32) { + boxResult(mv, type, "newUnsigned32", int.class); + } else { + boxResult(mv, type, "newUnsigned64", long.class); + } + break; + + case LONGLONG: + boxResult(mv, type, "newSigned64", long.class); + break; + + case ULONGLONG: + boxResult(mv, type, "newUnsigned64", long.class); + break; + + case FLOAT: + boxResult(mv, type, "newFloat32", int.class); + break; + + case DOUBLE: + boxResult(mv, type, "newFloat64", long.class); + break; + + case VOID: + boxResult(mv, type, "newNil", getInvokerIntType()); + break; + + case POINTER: + boxResult(mv, type, "newPointer" + Platform.getPlatform().addressSize(), + getInvokerIntType()); + break; + + case STRING: + boxResult(mv, type, "newString", getInvokerIntType()); + break; + + + default: + throw new UnsupportedOperationException("native return type not supported: " + type); + + } + } + + private void unbox(SkinnyMethodAdapter mv, String method) { + mv.invokestatic(p(JITRuntime.class), getRuntimeMethod(method), sig(getInvokerIntType(), PyObject.class)); + } + + private String getRuntimeMethod(String method) { + return method + (int.class == getInvokerIntType() ? "32" : "64"); + } + + abstract String getInvokerMethodName(JITSignature signature); + + abstract String getInvokerSignature(int parameterCount); + + abstract Class getInvokerIntType(); + + + public static boolean isPrimitiveInt(Class c) { + return byte.class == c || char.class == c || short.class == c || int.class == c || boolean.class == c; + } + + public static final void widen(SkinnyMethodAdapter mv, Class from, Class to) { + if (long.class == to && long.class != from && isPrimitiveInt(from)) { + mv.i2l(); + } + } + + public static final void narrow(SkinnyMethodAdapter mv, Class from, Class to) { + if (!from.equals(to) && isPrimitiveInt(to)) { + if (long.class == from) { + mv.l2i(); + } + + if (byte.class == to) { + mv.i2b(); + + } else if (short.class == to) { + mv.i2s(); + + } else if (char.class == to) { + mv.i2c(); + + } else if (boolean.class == to) { + // Ensure only 0x0 and 0x1 values are used for boolean + mv.iconst_1(); + mv.iand(); + } + } + } + + protected static String[] buildSignatures(Class nativeIntClass, int maxParameters) { + char sigChar = int.class == nativeIntClass ? 'I' : 'J'; + + String[] signatures = new String[maxParameters + 1]; + for (int i = 0; i < signatures.length; i++) { + + StringBuilder sb = new StringBuilder(); + + sb.append('(').append(ci(com.kenai.jffi.Function.class)); + + for (int n = 0; n < i; n++) { + sb.append(sigChar); + } + + signatures[i] = sb.append(")").append(sigChar).toString(); + } + + return signatures; + } +} diff --git a/src/org/python/modules/jffi/AsmClassBuilder.java b/src/org/python/modules/jffi/AsmClassBuilder.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/AsmClassBuilder.java @@ -0,0 +1,203 @@ +package org.python.modules.jffi; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.commons.EmptyVisitor; + +import java.io.PrintWriter; +import java.lang.reflect.Constructor; +import java.util.concurrent.atomic.AtomicLong; + +import static org.python.modules.jffi.CodegenUtils.*; +import static org.objectweb.asm.Opcodes.*; + +/** + * + */ +final class AsmClassBuilder { + public static final boolean DEBUG = false || Boolean.getBoolean("jython.ctypes.compile.dump"); + private static final AtomicLong nextClassID = new AtomicLong(0); + private final JITSignature signature; + private final ClassWriter classWriter; + private final ClassVisitor classVisitor; + private final String className; + private final Class parentClass; + private final JITMethodGenerator generator; + + AsmClassBuilder(JITMethodGenerator generator, JITSignature signature) { + this.generator = generator; + this.signature = signature; + + switch (signature.getParameterCount()) { + case 0: + parentClass = JITInvoker0.class; + break; + case 1: + parentClass = JITInvoker1.class; + break; + case 2: + parentClass = JITInvoker2.class; + break; + case 3: + parentClass = JITInvoker3.class; + break; + case 4: + parentClass = JITInvoker4.class; + break; + case 5: + parentClass = JITInvoker5.class; + break; + case 6: + parentClass = JITInvoker6.class; + break; + default: + throw new UnsupportedOperationException("arity " + + signature.getParameterCount() + " not supported"); + } + + className = p(Invoker.class) + "$ffi$" + nextClassID.getAndIncrement(); + + classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + classVisitor = DEBUG ? newCheckClassAdapter(classWriter) : classWriter; + classVisitor.visit(V1_5, ACC_PUBLIC | ACC_FINAL, className, null, + p(parentClass), new String[0]); + } + + Class build() { + // Create the constructor to set the 'library' & functions fields + SkinnyMethodAdapter init = new SkinnyMethodAdapter(classVisitor, ACC_PUBLIC, "", + sig(void.class, com.kenai.jffi.Function.class, NativeDataConverter.class, + NativeDataConverter[].class, Invoker.class), + null, null); + + init.start(); + // Invokes the super class constructor as super(Library) + + init.aload(0); + + init.invokespecial(p(parentClass), "", sig(void.class)); + + // Save the function argument in a field + classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getFunctionFieldName(), + ci(com.kenai.jffi.Function.class), null, null); + init.aload(0); + init.aload(1); + init.putfield(className, getFunctionFieldName(), ci(com.kenai.jffi.Function.class)); + + if (signature.hasResultConverter()) { + // Save the result converter argument in a field + classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getResultConverterFieldName(), + ci(NativeDataConverter.class), null, null); + init.aload(0); + init.aload(2); + init.putfield(className, getResultConverterFieldName(), ci(NativeDataConverter.class)); + } + + // Now load & store the parameter converter array + for (int i = 0; i < signature.getParameterCount(); i++) { + if (signature.hasParameterConverter(i)) { + classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getParameterConverterFieldName(i), + ci(NativeDataConverter.class), null, null); + init.aload(0); + init.aload(3); + init.pushInt(i); + init.aaload(); + init.putfield(className, getParameterConverterFieldName(i), ci(NativeDataConverter.class)); + } + } + + classVisitor.visitField(ACC_PRIVATE | ACC_FINAL, getFallbackInvokerFieldName(), + ci(Invoker.class), null, null); + init.aload(0); + init.aload(4); + init.putfield(className, getFallbackInvokerFieldName(), ci(Invoker.class)); + + init.voidreturn(); + init.visitMaxs(10, 10); + init.visitEnd(); + + generator.generate(this, "invoke", signature); + + classVisitor.visitEnd(); + + try { + byte[] bytes = classWriter.toByteArray(); + if (DEBUG) { + ClassVisitor trace = newTraceClassVisitor(new PrintWriter(System.err)); + new ClassReader(bytes).accept(trace, 0); + } + + JITClassLoader loader = new JITClassLoader(getClass().getClassLoader()); + + return loader.defineClass(c(className), bytes); + + } catch (Throwable ex) { + throw new RuntimeException(ex); + } + } + + public static ClassVisitor newCheckClassAdapter(ClassVisitor cv) { + try { + Class tmvClass = Class.forName("org.objectweb.asm.util.CheckClassAdapter").asSubclass(ClassVisitor.class); + Constructor c = tmvClass.getDeclaredConstructor(ClassVisitor.class); + return c.newInstance(cv); + } catch (Throwable t) { + return cv; + } + } + + public static final ClassVisitor newTraceClassVisitor(PrintWriter out) { + try { + + Class tmvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor").asSubclass(ClassVisitor.class); + Constructor c = tmvClass.getDeclaredConstructor(PrintWriter.class); + return c.newInstance(out); + } catch (Throwable t) { + return new EmptyVisitor(); + } + } + + + final String getFunctionFieldName() { + return "function"; + } + + final String getResultConverterFieldName() { + return "resultConverter"; + } + + final String getParameterConverterFieldName(int i) { + return "parameterConverter" + i; + } + + final String getFallbackInvokerFieldName() { + return "fallbackInvoker"; + } + + final ClassVisitor getClassVisitor() { + return classVisitor; + } + + final String getClassName() { + return className; + } + + + static final class JITClassLoader extends ClassLoader { + + public JITClassLoader() { + } + + public JITClassLoader(ClassLoader parent) { + super(parent); + } + + public Class defineClass(String name, byte[] b) { + Class klass = defineClass(name, b, 0, b.length); + resolveClass(klass); + return klass; + } + + } +} diff --git a/src/org/python/modules/jffi/CodegenUtils.java b/src/org/python/modules/jffi/CodegenUtils.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/CodegenUtils.java @@ -0,0 +1,255 @@ +/* + * CodegenUtils.java + * + * Created on January 31, 2007, 11:54 AM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package org.python.modules.jffi; + +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.Type; + +import java.util.Arrays; +import java.util.Map; + +/** + * + * @author headius + */ +public class CodegenUtils { + /** + * Creates a dotted class name from a path/package name + */ + public static String c(String p) { + return p.replace('/', '.'); + } + + /** + * Creates a class path name, from a Class. + */ + public static String p(Class n) { + return n.getName().replace('.','/'); + } + + /** + * Creates a class identifier of form Labc/abc;, from a Class. + */ + public static String ci(Class n) { + if (n.isArray()) { + n = n.getComponentType(); + if (n.isPrimitive()) { + if (n == Byte.TYPE) { + return "[B"; + } else if (n == Boolean.TYPE) { + return "[Z"; + } else if (n == Short.TYPE) { + return "[S"; + } else if (n == Character.TYPE) { + return "[C"; + } else if (n == Integer.TYPE) { + return "[I"; + } else if (n == Float.TYPE) { + return "[F"; + } else if (n == Double.TYPE) { + return "[D"; + } else if (n == Long.TYPE) { + return "[J"; + } else { + throw new RuntimeException("Unrecognized type in compiler: " + n.getName()); + } + } else { + return "[" + ci(n); + } + } else { + if (n.isPrimitive()) { + if (n == Byte.TYPE) { + return "B"; + } else if (n == Boolean.TYPE) { + return "Z"; + } else if (n == Short.TYPE) { + return "S"; + } else if (n == Character.TYPE) { + return "C"; + } else if (n == Integer.TYPE) { + return "I"; + } else if (n == Float.TYPE) { + return "F"; + } else if (n == Double.TYPE) { + return "D"; + } else if (n == Long.TYPE) { + return "J"; + } else if (n == Void.TYPE) { + return "V"; + } else { + throw new RuntimeException("Unrecognized type in compiler: " + n.getName()); + } + } else { + return "L" + p(n) + ";"; + } + } + } + + /** + * Creates a human-readable representation, from a Class. + */ + public static String human(Class n) { + return n.getCanonicalName(); + } + + public static String humanShort(Class n) { + return n.getSimpleName(); + } + + /** + * Create a method signature from the given param types and return values + */ + public static String sig(Class retval, Class... params) { + return sigParams(params) + ci(retval); + } + + public static String sig(Class[] retvalParams) { + Class[] justParams = new Class[retvalParams.length - 1]; + System.arraycopy(retvalParams, 1, justParams, 0, justParams.length); + return sigParams(justParams) + ci(retvalParams[0]); + } + + public static String sig(Class retval, String descriptor, Class... params) { + return sigParams(descriptor, params) + ci(retval); + } + + public static String sigParams(Class... params) { + StringBuilder signature = new StringBuilder("("); + + for (int i = 0; i < params.length; i++) { + signature.append(ci(params[i])); + } + + signature.append(")"); + + return signature.toString(); + } + + public static String sigParams(String descriptor, Class... params) { + StringBuilder signature = new StringBuilder("("); + + signature.append(descriptor); + + for (int i = 0; i < params.length; i++) { + signature.append(ci(params[i])); + } + + signature.append(")"); + + return signature.toString(); + } + + public static String pretty(Class retval, Class... params) { + return prettyParams(params) + human(retval); + } + + public static String prettyParams(Class... params) { + StringBuilder signature = new StringBuilder("("); + + for (int i = 0; i < params.length; i++) { + signature.append(human(params[i])); + if (i < params.length - 1) signature.append(','); + } + + signature.append(")"); + + return signature.toString(); + } + + public static String prettyShortParams(Class... params) { + StringBuilder signature = new StringBuilder("("); + + for (int i = 0; i < params.length; i++) { + signature.append(humanShort(params[i])); + if (i < params.length - 1) signature.append(','); + } + + signature.append(")"); + + return signature.toString(); + } + + public static Class[] params(Class... classes) { + return classes; + } + + public static Class[] params(Class cls, int times) { + Class[] classes = new Class[times]; + Arrays.fill(classes, cls); + return classes; + } + + public static Class[] params(Class cls1, Class clsFill, int times) { + Class[] classes = new Class[times + 1]; + Arrays.fill(classes, clsFill); + classes[0] = cls1; + return classes; + } + + public static Class[] params(Class cls1, Class cls2, Class clsFill, int times) { + Class[] classes = new Class[times + 2]; + Arrays.fill(classes, clsFill); + classes[0] = cls1; + classes[1] = cls2; + return classes; + } + + public static String getAnnotatedBindingClassName(String javaMethodName, String typeName, boolean isStatic, int required, int optional, boolean multi, boolean framed) { + String commonClassSuffix; + if (multi) { + commonClassSuffix = (isStatic ? "$s$" : "$i$" ) + javaMethodName; + } else { + commonClassSuffix = (isStatic ? "$s$" : "$i$" ) + required + "$" + optional + "$" + javaMethodName; + } + return typeName + commonClassSuffix; + } + + public static void visitAnnotationFields(AnnotationVisitor visitor, Map fields) { + for (Map.Entry fieldEntry : fields.entrySet()) { + Object value = fieldEntry.getValue(); + if (value.getClass().isArray()) { + Object[] values = (Object[]) value; + AnnotationVisitor arrayV = visitor.visitArray(fieldEntry.getKey()); + for (int i = 0; i < values.length; i++) { + arrayV.visit(null, values[i]); + } + arrayV.visitEnd(); + } else if (value.getClass().isEnum()) { + visitor.visitEnum(fieldEntry.getKey(), ci(value.getClass()), value.toString()); + } else if (value instanceof Class) { + visitor.visit(fieldEntry.getKey(), Type.getType((Class) value)); + } else { + visitor.visit(fieldEntry.getKey(), value); + } + } + } + + public static Class getBoxType(Class type) { + if (type == int.class) { + return Integer.class; + } else if (type == byte.class) { + return Byte.class; + } else if (type == short.class) { + return Short.class; + } else if (type == char.class) { + return Character.class; + } else if (type == long.class) { + return Long.class; + } else if (type == float.class) { + return Float.class; + } else if (type == double.class) { + return Double.class; + } else if (type == boolean.class) { + return Boolean.class; + } else { + throw new RuntimeException("Not a native type: " + type); + } + } +} diff --git a/src/org/python/modules/jffi/DefaultInvokerFactory.java b/src/org/python/modules/jffi/DefaultInvokerFactory.java --- a/src/org/python/modules/jffi/DefaultInvokerFactory.java +++ b/src/org/python/modules/jffi/DefaultInvokerFactory.java @@ -38,67 +38,83 @@ return createInvoker(function, returnType, marshallers); } + + final Invoker createInvoker(com.kenai.jffi.Function function, NativeType[] parameterTypes, NativeType returnType) { + ParameterMarshaller[] marshallers = new ParameterMarshaller[parameterTypes.length]; + + for (int i = 0; i < marshallers.length; ++i) { + marshallers[i] = getMarshaller(parameterTypes[i]); + } + + return createInvoker(function, returnType, marshallers); + } + final Invoker createInvoker(com.kenai.jffi.Function function, PyObject returnType, ParameterMarshaller[] marshallers) { CType cReturnType = CType.typeOf(returnType); if (cReturnType instanceof CType.Builtin) { - switch (cReturnType.getNativeType()) { - case VOID: - return new VoidInvoker(function, marshallers); + return createInvoker(function, cReturnType.getNativeType(), marshallers); + } - case BYTE: - return new Signed8Invoker(function, marshallers); + throw Py.RuntimeError("Unsupported return type: " + returnType); + } - case UBYTE: - return new Unsigned8Invoker(function, marshallers); + final Invoker createInvoker(com.kenai.jffi.Function function, NativeType returnType, ParameterMarshaller[] marshallers) { + switch (returnType) { + case VOID: + return new VoidInvoker(function, marshallers); - case SHORT: - return new Signed16Invoker(function, marshallers); + case BYTE: + return new Signed8Invoker(function, marshallers); - case USHORT: - return new Unsigned16Invoker(function, marshallers); + case UBYTE: + return new Unsigned8Invoker(function, marshallers); - case INT: - return new Signed32Invoker(function, marshallers); + case SHORT: + return new Signed16Invoker(function, marshallers); - case UINT: - return new Unsigned32Invoker(function, marshallers); + case USHORT: + return new Unsigned16Invoker(function, marshallers); - case LONGLONG: - return new Signed64Invoker(function, marshallers); + case INT: + return new Signed32Invoker(function, marshallers); - case ULONGLONG: - return new Unsigned64Invoker(function, marshallers); + case UINT: + return new Unsigned32Invoker(function, marshallers); - case LONG: - return Platform.getPlatform().longSize() == 32 - ? new Signed32Invoker(function, marshallers) - : new Signed64Invoker(function, marshallers); + case LONGLONG: + return new Signed64Invoker(function, marshallers); - case ULONG: - return Platform.getPlatform().longSize() == 32 - ? new Unsigned32Invoker(function, marshallers) - : new Unsigned64Invoker(function, marshallers); - case FLOAT: - return new FloatInvoker(function, marshallers); + case ULONGLONG: + return new Unsigned64Invoker(function, marshallers); - case DOUBLE: - return new DoubleInvoker(function, marshallers); + case LONG: + return Platform.getPlatform().longSize() == 32 + ? new Signed32Invoker(function, marshallers) + : new Signed64Invoker(function, marshallers); - case POINTER: - return new PointerInvoker(function, marshallers); + case ULONG: + return Platform.getPlatform().longSize() == 32 + ? new Unsigned32Invoker(function, marshallers) + : new Unsigned64Invoker(function, marshallers); + case FLOAT: + return new FloatInvoker(function, marshallers); - case STRING: - return new StringInvoker(function, marshallers); + case DOUBLE: + return new DoubleInvoker(function, marshallers); - default: - break; - } + case POINTER: + return new PointerInvoker(function, marshallers); + + case STRING: + return new StringInvoker(function, marshallers); + + default: + break; } throw Py.RuntimeError("Unsupported return type: " + returnType); - } - private static final ParameterMarshaller getMarshaller(NativeType type) { + static final ParameterMarshaller getMarshaller(NativeType type) { switch (type) { case BYTE: @@ -144,7 +160,7 @@ } } - private static final ParameterMarshaller getMarshaller(CType type) { + static final ParameterMarshaller getMarshaller(CType type) { if (type instanceof CType.Builtin) { return getMarshaller(type.getNativeType()); } else if (type instanceof CType.Pointer) { @@ -154,11 +170,11 @@ } } - private static final ParameterMarshaller getMarshaller(PyObject type) { + static final ParameterMarshaller getMarshaller(PyObject type) { return getMarshaller(CType.typeOf(type)); } - private static interface ParameterMarshaller { + static interface ParameterMarshaller { void marshal(HeapInvocationBuffer buffer, PyObject arg); } diff --git a/src/org/python/modules/jffi/FastIntInvokerFactory.java b/src/org/python/modules/jffi/FastIntInvokerFactory.java deleted file mode 100644 --- a/src/org/python/modules/jffi/FastIntInvokerFactory.java +++ /dev/null @@ -1,656 +0,0 @@ - -package org.python.modules.jffi; - -import com.kenai.jffi.Function; -import com.kenai.jffi.Platform; -import org.python.core.Py; -import org.python.core.PyObject; - - -/** - * A factory which generates {@link Invoker} instances that are optimized for - * 32 bit integer and float parameters / result types with 3 or less parameters. - * - * Technical background: Instead of trying to cram all calls down a generic call - * path, then figuring out how to convert the parameters in the native code on - * each call, jffi supplies arity and type specific call paths that can be - * optimized ahead of time by the native code. - * - * The downside of this approach is more java code to wire up the functions and - * call them using the arity+type specific paths, but in the case of int and float - * parameters, it can result in more than a 100% speed boost over the generic path. - */ -public class FastIntInvokerFactory { - private static final class SingletonHolder { - private static final FastIntInvokerFactory INSTANCE = new FastIntInvokerFactory(); - } - - private FastIntInvokerFactory() {} - - public static final FastIntInvokerFactory getFactory() { - return SingletonHolder.INSTANCE; - } - - /** - * Interface used to convert from a python object to a native integer - */ - private static interface IntParameterConverter { - int intValue(PyObject value); - } - - /** - * Interface used to convert from a native integer to a python object - */ - private static interface IntResultConverter { - PyObject pyValue(int value); - } - - /** - * Tests if a combination of result and parameter types can be called using - * an {@link Invoker} created by this factory. - * - * @param returnType The return type of the native function. - * @param parameterTypes The parameter types of the native function. - * @return true if the method can be handled as a fast int method. - */ - final boolean isFastIntMethod(CType returnType, CType[] parameterTypes) { - for (int i = 0; i < parameterTypes.length; ++i) { - if (!isFastIntParam(parameterTypes[i])) { - return false; - } - } - return parameterTypes.length <= 3 && isFastIntResult(returnType); - } - - /** - * Tests if a combination of result and parameter types can be called using - * an {@link Invoker} created by this factory. - * - * @param returnType The return type of the native function. - * @param parameterTypes The parameter types of the native function. - * @return true if the method can be handled as a fast int method. - */ - final boolean isFastIntMethod(PyObject returnType, PyObject[] parameterTypes) { - for (int i = 0; i < parameterTypes.length; ++i) { - if (!isFastIntParam(parameterTypes[i])) { - return false; - } - } - return parameterTypes.length <= 3 && isFastIntResult(returnType); - } - - /** - * Tests if the type can be returned as an integer result. - * - * @param type The result type. - * @return true if type can be returned as an integer. - */ - final boolean isFastIntResult(CType type) { - if (type instanceof CType.Builtin) { - switch (type.getNativeType()) { - case VOID: - case BYTE: - case UBYTE: - case SHORT: - case USHORT: - case INT: - case UINT: - return true; - - case LONG: - case ULONG: - return Platform.getPlatform().longSize() == 32; - - case STRING: - return Platform.getPlatform().addressSize() == 32; - } - } - return false; - } - - /** - * Tests if the type can be returned as an integer result. - * - * @param type The result type. - * @return true if type can be returned as an integer. - */ - final boolean isFastIntResult(PyObject type) { - return isFastIntResult(CType.typeOf(type)); - } - - /** - * Tests if the type can be passed as an integer parameter. - * - * @param type The parameter type. - * @return true if type can be passed as an integer. - */ - final boolean isFastIntParam(CType paramType) { - if (paramType instanceof CType.Builtin) { - switch (paramType.getNativeType()) { - case BYTE: - case UBYTE: - case SHORT: - case USHORT: - case INT: - case UINT: - return true; - - case LONG: - case ULONG: - return Platform.getPlatform().longSize() == 32; - } - } - - return false; - } - - /** - * Tests if the type can be passed as an integer parameter. - * - * @param type The parameter type. - * @return true if type can be passed as an integer. - */ - final boolean isFastIntParam(PyObject paramType) { - return isFastIntParam(CType.typeOf(paramType)); - } - - /** - * Creates a new Invoker instance for the given function, with the - * given parameter types and return type. - * - * @param function The JFFI function to wrap - * @param parameterTypes The parameter types the function will be called with - * @param returnType The result type the function will return - * @return A new {@link Invoker} instance. - */ - final Invoker createInvoker(Function function, CType[] parameterTypes, CType returnType) { - IntParameterConverter[] parameterConverters = new IntParameterConverter[parameterTypes.length]; - - for (int i = 0; i < parameterConverters.length; ++i) { - parameterConverters[i] = getIntParameterConverter(parameterTypes[i]); - } - - return createIntInvoker(function, getIntResultConverter(returnType), parameterConverters); - } - - /** - * Creates a new Invoker instance for the given function, with the - * given parameter types and return type. - * - * @param function The JFFI function to wrap - * @param parameterTypes The parameter types the function will be called with - * @param returnType The result type the function will return - * @return A new {@link Invoker} instance. - */ - final Invoker createInvoker(Function function, PyObject returnType, PyObject[] parameterTypes) { - IntParameterConverter[] parameterConverters = new IntParameterConverter[parameterTypes.length]; - - for (int i = 0; i < parameterConverters.length; ++i) { - parameterConverters[i] = getIntParameterConverter(parameterTypes[i]); - } - - return createIntInvoker(function, getIntResultConverter(returnType), parameterConverters); - } - - final Invoker createIntInvoker(Function function, IntResultConverter resultConverter, IntParameterConverter[] parameterConverters) { - switch (parameterConverters.length) { - case 0: - return new FastIntInvokerZero(function, resultConverter, parameterConverters); - case 1: - return new FastIntInvokerOne(function, resultConverter, parameterConverters); - case 2: - return new FastIntInvokerTwo(function, resultConverter, parameterConverters); - case 3: - return new FastIntInvokerThree(function, resultConverter, parameterConverters); - } - throw Py.RuntimeError("fast int invoker does not support functions with arity=" + parameterConverters.length); - } - - - /** - * Gets a python object to integer parameter converter. - * - * @param type The python C type - * @return An IntParameterConverter instance. - */ - final IntParameterConverter getIntParameterConverter(CType type) { - if (type instanceof CType.Builtin) { - return getIntParameterConverter(type.getNativeType()); - } - throw Py.TypeError("cannot convert objects of type " + type + " to int"); - } - - /** - * Gets a python object to integer parameter converter. - * - * @param type The python C type - * @return An IntParameterConverter instance. - */ - final IntParameterConverter getIntParameterConverter(PyObject type) { - return getIntParameterConverter(CType.typeOf(type)); - } - - /** - * Gets a python object to integer parameter converter. - * - * @param type The object type. - * @return An IntParameterConverter instance. - */ - final IntParameterConverter getIntParameterConverter(NativeType type) { - switch (type) { - case BYTE: - return Signed8ParameterConverter.INSTANCE; - - case UBYTE: - return Unsigned8ParameterConverter.INSTANCE; - - case SHORT: - return Signed16ParameterConverter.INSTANCE; - - case USHORT: - return Unsigned16ParameterConverter.INSTANCE; - - case INT: - return Signed32ParameterConverter.INSTANCE; - - case UINT: - return Unsigned32ParameterConverter.INSTANCE; - - case LONG: - if (Platform.getPlatform().longSize() == 32) { - return Signed32ParameterConverter.INSTANCE; - } - break; - - case ULONG: - if (Platform.getPlatform().longSize() == 32) { - return Unsigned32ParameterConverter.INSTANCE; - } - break; - - case FLOAT: - if (Platform.getPlatform().getCPU() == Platform.CPU.I386 - || Platform.getPlatform().getCPU() == Platform.CPU.X86_64) { - return Float32ParameterConverter.INSTANCE; - } - break; - default: - break; - } - - throw Py.TypeError("cannot convert objects of type " + type + " to int"); - } - - - /** - * Gets a int to python object result converter for the type. - * - * @param type The object type. - * @return An IntResultConverter instance. - */ - final IntResultConverter getIntResultConverter(PyObject type) { - return getIntResultConverter(CType.typeOf(type)); - } - - /** - * Gets a int to python object result converter for the type. - * - * @param type The object type. - * @return An IntResultConverter instance. - */ - final IntResultConverter getIntResultConverter(CType type) { - return type instanceof CType.Builtin ? getIntResultConverter(type.getNativeType()) : null; - } - - - /** - * Gets a int to python object result converter for the type. - * - * @param type The object type. - * @return An IntResultConverter instance. - */ - final IntResultConverter getIntResultConverter(NativeType type) { - switch (type) { - case VOID: - return VoidResultConverter.INSTANCE; - - case BYTE: - return Signed8ResultConverter.INSTANCE; - - case UBYTE: - return Unsigned8ResultConverter.INSTANCE; - - case SHORT: - return Signed16ResultConverter.INSTANCE; - - case USHORT: - return Unsigned16ResultConverter.INSTANCE; - - case INT: - return Signed32ResultConverter.INSTANCE; - - case UINT: - return Unsigned32ResultConverter.INSTANCE; - - case LONG: - if (Platform.getPlatform().longSize() == 32) { - return Signed32ResultConverter.INSTANCE; - } - break; - - case ULONG: - if (Platform.getPlatform().longSize() == 32) { - return Unsigned32ResultConverter.INSTANCE; - } - break; - - case STRING: - if (Platform.getPlatform().addressSize() == 32) { - return StringResultConverter.INSTANCE; - } - break; - - default: - break; - } - throw new IllegalArgumentException("Cannot convert objects of type " + type + " from int"); - } - - /** - * Base class for all fast-int {@link Invoker} subclasses - */ - private static abstract class BaseFastIntInvoker implements Invoker { - final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); - final Function function; - final IntResultConverter resultConverter; - final int arity; - final IntParameterConverter c0, c1, c2; - - BaseFastIntInvoker(Function function, IntResultConverter resultConverter, - IntParameterConverter[] parameterConverters) { - this.function = function; - this.resultConverter = resultConverter; - this.arity = parameterConverters.length; - c0 = parameterConverters.length > 0 ? parameterConverters[0] : null; - c1 = parameterConverters.length > 1 ? parameterConverters[1] : null; - c2 = parameterConverters.length > 2 ? parameterConverters[2] : null; - } - - final void checkArity(PyObject[] args) { - checkArity(args.length); - } - - final void checkArity(int got) { - if (got != arity) { - throw Py.TypeError(String.format("__call__() takes exactly %d arguments (%d given)", arity, got)); - } - } - public PyObject invoke(PyObject[] args) { - checkArity(args); - switch (arity) { - case 0: - return invoke(); - case 1: - return invoke(args[0]); - case 2: - return invoke(args[0], args[1]); - case 3: - return invoke(args[0], args[1], args[2]); - default: - throw Py.RuntimeError("invalid fast-int arity"); - } - } - - public PyObject invoke() { - checkArity(0); - return Py.None; - } - - public PyObject invoke(PyObject arg1) { - checkArity(1); - return Py.None; - } - - public PyObject invoke(PyObject arg1, PyObject arg2) { - checkArity(2); - return Py.None; - } - - public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { - checkArity(3); - return Py.None; - } - - } - - /** - * Fast-int invoker that takes no parameters. - */ - private static final class FastIntInvokerZero extends BaseFastIntInvoker { - - public FastIntInvokerZero(Function function, IntResultConverter resultConverter, - IntParameterConverter parameterConverters[]) { - super(function, resultConverter, parameterConverters); - } - - @Override - public final PyObject invoke() { - return resultConverter.pyValue(jffiInvoker.invokeVrI(function)); - } - } - - /** - * Fast-int invoker that takes a single parameter - */ - private static final class FastIntInvokerOne extends BaseFastIntInvoker { - public FastIntInvokerOne(Function function, IntResultConverter resultConverter, - IntParameterConverter parameterConverters[]) { - super(function, resultConverter, parameterConverters); - - } - - @Override - public final PyObject invoke(PyObject arg0) { - return resultConverter.pyValue(jffiInvoker.invokeIrI(function, - c0.intValue(arg0))); - } - } - - - /** - * Fast-int invoker that takes two parameters - */ - private static final class FastIntInvokerTwo extends BaseFastIntInvoker { - - public FastIntInvokerTwo(Function function, IntResultConverter resultConverter, - IntParameterConverter parameterConverters[]) { - super(function, resultConverter, parameterConverters); - } - - @Override - public PyObject invoke(PyObject arg0, PyObject arg1) { - return resultConverter.pyValue(jffiInvoker.invokeIIrI(function, - c0.intValue(arg0), c1.intValue(arg1))); - } - } - - /** - * Fast-int invoker that takes three parameters - */ - private static final class FastIntInvokerThree extends BaseFastIntInvoker { - - public FastIntInvokerThree(Function function, IntResultConverter resultConverter, - IntParameterConverter parameterConverters[]) { - super(function, resultConverter, parameterConverters); - } - - @Override - public PyObject invoke(PyObject arg0, PyObject arg1, PyObject arg2) { - return resultConverter.pyValue(jffiInvoker.invokeIIIrI(function, - c0.intValue(arg0), c1.intValue(arg1), c2.intValue(arg2))); - } - } - - /** - * Base class for all fast-int result converters - */ - static abstract class BaseResultConverter implements IntResultConverter { - - } - - /** - * Converts a native void result into into a python None instance - */ - static final class VoidResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new VoidResultConverter(); - public final PyObject pyValue(int value) { - return Py.None; - } - } - - /** - * Converts a native signed byte result into into a python integer instance - */ - static final class Signed8ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Signed8ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newSigned8(value); - } - } - - /** - * Converts a native unsigned byte result into into a python integer instance - */ - static final class Unsigned8ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Unsigned8ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newUnsigned8(value); - } - } - - /** - * Converts a native signed short result into into a python integer instance - */ - static final class Signed16ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Signed16ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newSigned16(value); - } - } - - /** - * Converts a native unsigned short result into into a python integer instance - */ - static final class Unsigned16ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Unsigned16ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newUnsigned16(value); - } - } - - /** - * Converts a native signed int result into into a python integer instance - */ - static final class Signed32ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Signed32ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newSigned32(value); - } - } - - /** - * Converts a native unsigned int result into into a python integer instance - */ - static final class Unsigned32ResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new Unsigned32ResultConverter(); - public final PyObject pyValue(int value) { - return Util.newUnsigned32(value); - } - } - - /** - * Converts a native string address result into into a python string instance - */ - static final class StringResultConverter extends BaseResultConverter { - public static final IntResultConverter INSTANCE = new StringResultConverter(); - public final PyObject pyValue(int value) { - return Util.newString(value); - } - } - - /** - * Base class for all integer parameter converters. - */ - static abstract class BaseParameterConverter implements IntParameterConverter { - } - - /** - * Converter for python signed byte to native int - */ - static final class Signed8ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Signed8ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.int8Value(obj); - } - } - - /** - * Converter for python unsigned byte to native int - */ - static final class Unsigned8ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Unsigned8ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.uint8Value(obj); - } - } - - /** - * Converter for python signed short to native int - */ - static final class Signed16ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Signed16ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.int16Value(obj); - } - } - - /** - * Converter for python unsigned short to native int - */ - static final class Unsigned16ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Unsigned16ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.uint16Value(obj); - } - } - - /** - * Converter for python signed int to native int - */ - static final class Signed32ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Signed32ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.int32Value(obj); - } - } - - /** - * Converter for python unsigned int to native int - */ - static final class Unsigned32ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Unsigned32ParameterConverter(); - public final int intValue(PyObject obj) { - return Util.uint32Value(obj); - } - } - - /** - * Converter for python float to native int parameter - */ - static final class Float32ParameterConverter extends BaseParameterConverter { - public static final IntParameterConverter INSTANCE = new Float32ParameterConverter(); - public final int intValue(PyObject obj) { - return Float.floatToIntBits((float) obj.asDouble()); - } - } -} diff --git a/src/org/python/modules/jffi/FastIntMethodGenerator.java b/src/org/python/modules/jffi/FastIntMethodGenerator.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/FastIntMethodGenerator.java @@ -0,0 +1,141 @@ +package org.python.modules.jffi; + + +import com.kenai.jffi.CallingConvention; +import com.kenai.jffi.Platform; + +/** + * + */ +final class FastIntMethodGenerator extends AbstractNumericMethodGenerator { + private static final int MAX_PARAMETERS = getMaximumFastIntParameters(); + + private static final String[] signatures = buildSignatures(int.class, MAX_PARAMETERS); + + private static final String[] methodNames = { + "invokeVrI", "invokeIrI", "invokeIIrI", "invokeIIIrI", "invokeIIIIrI", "invokeIIIIIrI", "invokeIIIIIIrI" + }; + + private static final String[] noErrnoMethodNames = { + "invokeNoErrnoVrI", "invokeNoErrnoIrI", "invokeNoErrnoIIrI", "invokeNoErrnoIIIrI" + }; + + String getInvokerMethodName(JITSignature signature) { + + final int parameterCount = signature.getParameterCount(); + + if (signature.isIgnoreError() && parameterCount <= MAX_PARAMETERS && parameterCount <= noErrnoMethodNames.length) { + return noErrnoMethodNames[signature.getParameterCount()]; + + } else if (parameterCount <= MAX_PARAMETERS && parameterCount <= methodNames.length) { + return methodNames[parameterCount]; + + } else { + throw new IllegalArgumentException("invalid fast-int parameter count: " + parameterCount); + } + } + + String getInvokerSignature(int parameterCount) { + if (parameterCount <= MAX_PARAMETERS && parameterCount <= signatures.length) { + return signatures[parameterCount]; + } + throw new IllegalArgumentException("invalid fast-int parameter count: " + parameterCount); + } + + final Class getInvokerIntType() { + return int.class; + } + + public boolean isSupported(JITSignature signature) { + final int parameterCount = signature.getParameterCount(); + + if (!signature.getCallingConvention().equals(CallingConvention.DEFAULT) || parameterCount > MAX_PARAMETERS) { + return false; + } + + final Platform platform = Platform.getPlatform(); + + if (platform.getOS().equals(Platform.OS.WINDOWS)) { + return false; + } + + if (!platform.getCPU().equals(Platform.CPU.I386) && !platform.getCPU().equals(Platform.CPU.X86_64)) { + return false; + } + + for (int i = 0; i < parameterCount; i++) { + if (!isFastIntParameter(platform, signature.getParameterType(i))) { + return false; + } + } + + return isFastIntResult(platform, signature.getResultType()); + } + + + final static int getMaximumFastIntParameters() { + try { + com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeIIIIIIrI", com.kenai.jffi.Function.class, + int.class, int.class, int.class, int.class, int.class, int.class); + return 6; + } catch (NoSuchMethodException nex) { + try { + com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeIIIrI", com.kenai.jffi.Function.class, + int.class, int.class, int.class); + return 3; + } catch (NoSuchMethodException nex2) { + return -1; + } + } catch (Throwable t) { + return -1; + } + } + + + private static boolean isFastIntType(Platform platform, NativeType type) { + switch (type) { + case BOOL: + case BYTE: + case UBYTE: + case SHORT: + case USHORT: + case INT: + case UINT: + return true; + + case LONG: + case ULONG: + return platform.longSize() == 32; + + default: + return false; + } + } + + + static boolean isFastIntResult(Platform platform, NativeType type) { + switch (type) { + case VOID: + return true; + + case POINTER: + case STRING: + return platform.addressSize() == 32; + + default: + return isFastIntType(platform, type); + } + } + + static boolean isFastIntParameter(Platform platform, NativeType type) { + switch (type) { + case POINTER: + case BUFFER_IN: + case BUFFER_OUT: + case BUFFER_INOUT: + return platform.addressSize() == 32; + default: + return isFastIntType(platform, type); + } + } +} diff --git a/src/org/python/modules/jffi/FastLongMethodGenerator.java b/src/org/python/modules/jffi/FastLongMethodGenerator.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/FastLongMethodGenerator.java @@ -0,0 +1,129 @@ +package org.python.modules.jffi; + + +import com.kenai.jffi.CallingConvention; +import com.kenai.jffi.Platform; + +/** + * + */ +final class FastLongMethodGenerator extends AbstractNumericMethodGenerator { + private static final int MAX_PARAMETERS = getMaximumFastLongParameters(); + + private static final String[] signatures = buildSignatures(long.class, MAX_PARAMETERS); + + private static final String[] methodNames = { + "invokeVrL", "invokeLrL", "invokeLLrL", "invokeLLLrL", "invokeLLLLrL", "invokeLLLLLrL", "invokeLLLLLLrL" + }; + + String getInvokerMethodName(JITSignature signature) { + + final int parameterCount = signature.getParameterCount(); + + if (parameterCount <= MAX_PARAMETERS && parameterCount <= methodNames.length) { + return methodNames[parameterCount]; + + } else { + throw new IllegalArgumentException("invalid fast-long parameter count: " + parameterCount); + } + } + + String getInvokerSignature(int parameterCount) { + if (parameterCount <= MAX_PARAMETERS && parameterCount <= signatures.length) { + return signatures[parameterCount]; + } + throw new IllegalArgumentException("invalid fast-long parameter count: " + parameterCount); + } + + final Class getInvokerIntType() { + return long.class; + } + + public boolean isSupported(JITSignature signature) { + final int parameterCount = signature.getParameterCount(); + + if (!signature.getCallingConvention().equals(CallingConvention.DEFAULT) || parameterCount > MAX_PARAMETERS) { + return false; + } + + final Platform platform = Platform.getPlatform(); + + if (platform.getOS().equals(Platform.OS.WINDOWS)) { + return false; + } + + // Only supported on amd64 arches + if (!platform.getCPU().equals(Platform.CPU.X86_64)) { + return false; + } + + for (int i = 0; i < parameterCount; i++) { + if (!isFastLongParameter(platform, signature.getParameterType(i))) { + return false; + } + } + + return isFastLongResult(platform, signature.getResultType()); + } + + + final static int getMaximumFastLongParameters() { + try { + com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeLLLLLLrL", com.kenai.jffi.Function.class, + long.class, long.class, long.class, long.class, long.class, long.class); + return 6; + } catch (Throwable t) { + return -1; + } + } + + + private static boolean isFastLongType(Platform platform, NativeType type) { + switch (type) { + case BOOL: + case BYTE: + case UBYTE: + case SHORT: + case USHORT: + case INT: + case UINT: + case LONG: + case ULONG: + case LONGLONG: + case ULONGLONG: + case POINTER: + return true; + + default: + return false; + } + } + + + static boolean isFastLongResult(Platform platform, NativeType type) { + switch (type) { + case VOID: + return true; + + case POINTER: + case STRING: + return platform.addressSize() == 64; + + default: + return isFastLongType(platform, type); + } + } + + static boolean isFastLongParameter(Platform platform, NativeType type) { + switch (type) { + case POINTER: + case BUFFER_IN: + case BUFFER_OUT: + case BUFFER_INOUT: + return platform.addressSize() == 64; + + default: + return isFastLongType(platform, type); + } + } +} diff --git a/src/org/python/modules/jffi/FastNumericMethodGenerator.java b/src/org/python/modules/jffi/FastNumericMethodGenerator.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/FastNumericMethodGenerator.java @@ -0,0 +1,128 @@ +package org.python.modules.jffi; + + +import com.kenai.jffi.CallingConvention; +import com.kenai.jffi.Platform; + +/** + * + */ +final class FastNumericMethodGenerator extends AbstractNumericMethodGenerator { + private static final int MAX_PARAMETERS = getMaximumFastNumericParameters(); + + private static final String[] signatures = buildSignatures(long.class, MAX_PARAMETERS); + + private static final String[] methodNames = { + "invokeVrN", "invokeNrN", "invokeNNrN", "invokeNNNrN", "invokeNNNNrN", "invokeNNNNNrN", "invokeNNNNNNrN" + }; + + String getInvokerMethodName(JITSignature signature) { + + final int parameterCount = signature.getParameterCount(); + + if (parameterCount <= MAX_PARAMETERS && parameterCount <= methodNames.length) { + return methodNames[parameterCount]; + + } else { + throw new IllegalArgumentException("invalid fast-long parameter count: " + parameterCount); + } + } + + String getInvokerSignature(int parameterCount) { + if (parameterCount <= MAX_PARAMETERS && parameterCount <= signatures.length) { + return signatures[parameterCount]; + } + throw new IllegalArgumentException("invalid fast-long parameter count: " + parameterCount); + } + + final Class getInvokerIntType() { + return long.class; + } + + public boolean isSupported(JITSignature signature) { + final int parameterCount = signature.getParameterCount(); + + if (!signature.getCallingConvention().equals(CallingConvention.DEFAULT) || parameterCount > MAX_PARAMETERS) { + return false; + } + + final Platform platform = Platform.getPlatform(); + + if (platform.getOS().equals(Platform.OS.WINDOWS)) { + return false; + } + + // Only supported on amd64 arches + if (!platform.getCPU().equals(Platform.CPU.I386) && !platform.getCPU().equals(Platform.CPU.X86_64)) { + return false; + } + + for (int i = 0; i < parameterCount; i++) { + if (!isFastNumericParameter(platform, signature.getParameterType(i))) { + return false; + } + } + + return isFastNumericResult(platform, signature.getResultType()); + } + + + final static int getMaximumFastNumericParameters() { + try { + com.kenai.jffi.Invoker.class.getDeclaredMethod("invokeNNNNNNrN", com.kenai.jffi.Function.class, + long.class, long.class, long.class, long.class, long.class, long.class); + return 6; + } catch (Throwable t) { + return -1; + } + } + + + private static boolean isFastNumericType(Platform platform, NativeType type) { + switch (type) { + case BOOL: + case BYTE: + case UBYTE: + case SHORT: + case USHORT: + case INT: + case UINT: + case LONG: + case ULONG: + case LONGLONG: + case ULONGLONG: + case FLOAT: + case DOUBLE: + return true; + + default: + return false; + } + } + + + static boolean isFastNumericResult(Platform platform, NativeType type) { + switch (type) { + case VOID: + case POINTER: + case STRING: + return true; + + default: + return isFastNumericType(platform, type); + } + } + + static boolean isFastNumericParameter(Platform platform, NativeType type) { + switch (type) { + case POINTER: + case BUFFER_IN: + case BUFFER_OUT: + case BUFFER_INOUT: + return true; + + default: + return isFastNumericType(platform, type); + } + } +} diff --git a/src/org/python/modules/jffi/Function.java b/src/org/python/modules/jffi/Function.java --- a/src/org/python/modules/jffi/Function.java +++ b/src/org/python/modules/jffi/Function.java @@ -1,6 +1,7 @@ package org.python.modules.jffi; +import com.kenai.jffi.CallingConvention; import org.python.core.Py; import org.python.core.PyList; import org.python.core.PyNewWrapper; @@ -22,9 +23,12 @@ private final PyStringMap dict = new PyStringMap(); - private volatile PyObject restype = Py.None; + private volatile PyObject restype = CType.INT; private volatile PyObject[] argtypes = null; - private Invoker invoker = null; + private Invoker defaultInvoker; + private Invoker compiledInvoker; + private volatile JITHandle jitHandle; + private volatile com.kenai.jffi.Function jffiFunction; @ExposedGet public PyObject errcheck = Py.None; @@ -150,38 +154,66 @@ return !getMemory().isNull(); } - private final Invoker getInvoker() { + protected final Invoker getInvoker() { + return compiledInvoker != null ? compiledInvoker : tryCompilation(); + } + + private synchronized Invoker tryCompilation() { + if (compiledInvoker != null) { + return compiledInvoker; + } + + if (argtypes == null) { + throw Py.NotImplementedError("variadic functions not supported yet; specify a parameter list"); + } + + CType cResultType = CType.typeOf(restype); + CType[] cParameterTypes = new CType[argtypes.length]; + for (int i = 0; i < cParameterTypes.length; i++) { + cParameterTypes[i] = CType.typeOf(argtypes[i]); + } + + if (jitHandle == null) { + jitHandle = JITCompiler.getInstance().getHandle(cResultType, cParameterTypes, CallingConvention.DEFAULT, false); + } + + if (jffiFunction == null) { + com.kenai.jffi.Type jffiReturnType = Util.jffiType(cResultType); + com.kenai.jffi.Type[] jffiParamTypes = new com.kenai.jffi.Type[argtypes.length]; + + for (int i = 0; i < jffiParamTypes.length; ++i) { + jffiParamTypes[i] = Util.jffiType(cParameterTypes[i]); + } + + jffiFunction = new com.kenai.jffi.Function(getMemory().getAddress(), jffiReturnType, jffiParamTypes); + } + + if (defaultInvoker == null) { + Invoker invoker = DefaultInvokerFactory.getFactory().createInvoker(jffiFunction, restype, argtypes); + defaultInvoker = errcheck != Py.None ? new ErrCheckInvoker(invoker, errcheck) : invoker; + } + + Invoker invoker = jitHandle.compile(jffiFunction, null, new NativeDataConverter[0]); if (invoker != null) { - return invoker; + return compiledInvoker = errcheck != Py.None ? new ErrCheckInvoker(invoker, errcheck) : invoker; } - return createInvoker(); + + // + // Once compilation has failed, always fallback to the default invoker + // + if (jitHandle.compilationFailed()) { + compiledInvoker = defaultInvoker; + } + + return defaultInvoker; } private synchronized void invalidateInvoker() { // null out the invoker - it will be regenerated on next invocation - this.invoker = null; - } - - private synchronized final Invoker createInvoker() { - if (argtypes == null) { - throw Py.NotImplementedError("variadic functions not supported yet; specify a parameter list"); - } - - com.kenai.jffi.Type jffiReturnType = Util.jffiType(CType.typeOf(restype)); - com.kenai.jffi.Type[] jffiParamTypes = new com.kenai.jffi.Type[argtypes.length]; - for (int i = 0; i < jffiParamTypes.length; ++i) { - jffiParamTypes[i] = Util.jffiType(CType.typeOf(argtypes[i])); - } - com.kenai.jffi.Function jffiFunction = new com.kenai.jffi.Function(getMemory().getAddress(), jffiReturnType, jffiParamTypes); - - Invoker i; - if (FastIntInvokerFactory.getFactory().isFastIntMethod(restype, argtypes)) { - i = FastIntInvokerFactory.getFactory().createInvoker(jffiFunction, restype, argtypes); - } else { - i = DefaultInvokerFactory.getFactory().createInvoker(jffiFunction, restype, argtypes); - } - - return invoker = errcheck != Py.None ? new ErrCheckInvoker(i, errcheck) : i; + this.defaultInvoker = null; + this.compiledInvoker = null; + this.jitHandle = null; + this.jffiFunction = null; } private static final class ErrCheckInvoker implements Invoker { diff --git a/src/org/python/modules/jffi/JITCompiler.java b/src/org/python/modules/jffi/JITCompiler.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITCompiler.java @@ -0,0 +1,100 @@ +/* + * + */ +package org.python.modules.jffi; + +import com.kenai.jffi.CallingConvention; +import org.python.core.PyObject; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +class JITCompiler { + + private final Map + handles = new HashMap(); + private final ReferenceQueue referenceQueue = new ReferenceQueue(); + + private final JITHandle failedHandle = new JITHandle( + new JITSignature(NativeType.VOID, new NativeType[0], false, new boolean[0], CallingConvention.DEFAULT, false), + true); + + private static class SingletonHolder { + private static final JITCompiler INSTANCE = new JITCompiler(); + } + + public static JITCompiler getInstance() { + return SingletonHolder.INSTANCE; + } + + private static final class HandleRef extends WeakReference { + JITSignature signature; + + public HandleRef(JITHandle handle, JITSignature signature, ReferenceQueue refqueue) { + super(handle, refqueue); + this.signature = signature; + } + } + + private void cleanup() { + HandleRef ref; + while ((ref = (HandleRef) referenceQueue.poll()) != null) { + handles.remove(ref.signature); + } + } + + + JITHandle getHandle(PyObject resultType, PyObject[] parameterTypes, CallingConvention convention, boolean ignoreErrno) { + + boolean hasResultConverter = !(resultType instanceof CType.Builtin); + NativeType nativeResultType; + + if (resultType instanceof CType.Builtin) { + nativeResultType = ((CType) resultType).getNativeType(); + /* + } else if (resultType instanceof MappedType) { + nativeResultType = ((MappedType) resultType).getRealType().getNativeType(); + */ + } else { + return failedHandle; + } + + NativeType[] nativeParameterTypes = new NativeType[parameterTypes.length]; + boolean[] hasParameterConverter = new boolean[parameterTypes.length]; + + for (int i = 0; i < hasParameterConverter.length; i++) { + CType parameterType = CType.typeOf(parameterTypes[i]); + if (parameterType instanceof CType.Builtin) { + nativeParameterTypes[i] = parameterType.getNativeType(); + /* + } else if (parameterType instanceof MappedType) { + nativeParameterTypes[i] = ((MappedType) parameterType).getRealType().getNativeType(); + */ + } else { + return failedHandle; + } + + hasParameterConverter[i] = !(parameterType instanceof CType.Builtin); + } + + JITSignature jitSignature = new JITSignature(nativeResultType, nativeParameterTypes, + hasResultConverter, hasParameterConverter, convention, ignoreErrno); + + synchronized (this) { + cleanup(); + HandleRef ref = handles.get(jitSignature); + JITHandle handle = ref != null ? ref.get() : null; + if (handle == null) { + handle = new JITHandle(jitSignature, false); + handles.put(jitSignature, new HandleRef(handle, jitSignature, referenceQueue)); + } + + return handle; + } + } +} diff --git a/src/org/python/modules/jffi/JITHandle.java b/src/org/python/modules/jffi/JITHandle.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITHandle.java @@ -0,0 +1,86 @@ +/* + * + */ +package org.python.modules.jffi; + +import java.lang.reflect.Constructor; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * + */ +final class JITHandle { + + private static final int THRESHOLD = Integer.getInteger("jython.ctypes.compile.threshold", 10); + private final JITSignature jitSignature; + private volatile boolean compilationFailed = false; + private final AtomicInteger counter = new AtomicInteger(0); + private volatile Class compiledClass = null; + + JITHandle(JITSignature signature, boolean compilationFailed) { + this.jitSignature = signature; + this.compilationFailed = compilationFailed; + } + + final boolean compilationFailed() { + return compilationFailed; + } + + final Invoker compile(com.kenai.jffi.Function function, NativeDataConverter resultConverter, NativeDataConverter[] parameterConverters) { + if (compilationFailed || counter.incrementAndGet() < THRESHOLD) { + return null; + } + + synchronized (this) { + if (compiledClass == null) { + compiledClass = newInvokerClass(jitSignature); + if (compiledClass == null) { + compilationFailed = true; + return null; + } + } + } + + try { + Constructor cons = compiledClass.getDeclaredConstructor(com.kenai.jffi.Function.class, + NativeDataConverter.class, NativeDataConverter[].class, Invoker.class); + return cons.newInstance(function, resultConverter, parameterConverters, + createFallbackInvoker(function, jitSignature)); + } catch (Throwable t) { + t.printStackTrace(); + return null; + } + } + + Class newInvokerClass(JITSignature jitSignature) { + + JITMethodGenerator generator = null; + JITMethodGenerator[] generators = { + new FastIntMethodGenerator(), + new FastLongMethodGenerator(), + new FastNumericMethodGenerator(),}; + + for (int i = 0; i < generators.length; i++) { + if (generators[i].isSupported(jitSignature)) { + generator = generators[i]; + break; + } + } + + if (generator == null) { + return null; + } + + return new AsmClassBuilder(generator, jitSignature).build(); + } + + + static Invoker createFallbackInvoker(com.kenai.jffi.Function function, JITSignature signature) { + NativeType[] parameterTypes = new NativeType[signature.getParameterCount()]; + for (int i = 0; i < parameterTypes.length; i++) { + parameterTypes[i] = signature.getParameterType(i); + } + + return DefaultInvokerFactory.getFactory().createInvoker(function, parameterTypes, signature.getResultType()); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker.java b/src/org/python/modules/jffi/JITInvoker.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker.java @@ -0,0 +1,66 @@ +package org.python.modules.jffi; + +import com.kenai.jffi.*; +import org.python.core.Py; +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker implements Invoker { + protected static final com.kenai.jffi.Invoker jffiInvoker = com.kenai.jffi.Invoker.getInstance(); + private final int arity; + + protected JITInvoker(int arity) { + this.arity = arity; + } + + protected final PyObject invalidArity(int got) { + checkArity(arity, got); + return Py.None; + } + + protected final void checkArity(PyObject[] args) { + checkArity(arity, args.length); + } + + public static void checkArity(int arity, int got) { + if (got != arity) { + throw Py.TypeError(String.format("__call__() takes exactly %d arguments (%d given)", arity, got)); + } + } + + + public PyObject invoke(PyObject[] args) { + checkArity(args); + switch (arity) { + case 0: + return invoke(); + + case 1: + return invoke(args[0]); + + case 2: + return invoke(args[0], args[1]); + + case 3: + return invoke(args[0], args[1], args[2]); + + case 4: + return invoke(args[0], args[1], args[2], args[3]); + + case 5: + return invoke(args[0], args[1], args[2], args[3], args[4]); + + case 6: + return invoke(args[0], args[1], args[2], args[3], args[4], args[5]); + + default: + throw Py.RuntimeError("invalid fast-int arity"); + } + } + + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5); + abstract public PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6); +} diff --git a/src/org/python/modules/jffi/JITInvoker0.java b/src/org/python/modules/jffi/JITInvoker0.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker0.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker0 extends JITInvoker { + public JITInvoker0() { + super(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker1.java b/src/org/python/modules/jffi/JITInvoker1.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker1.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker1 extends JITInvoker { + public JITInvoker1() { + super(1); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker2.java b/src/org/python/modules/jffi/JITInvoker2.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker2.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker2 extends JITInvoker { + public JITInvoker2() { + super(2); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker3.java b/src/org/python/modules/jffi/JITInvoker3.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker3.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker3 extends JITInvoker { + public JITInvoker3() { + super(3); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker4.java b/src/org/python/modules/jffi/JITInvoker4.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker4.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker4 extends JITInvoker { + public JITInvoker4() { + super(4); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker5.java b/src/org/python/modules/jffi/JITInvoker5.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker5.java @@ -0,0 +1,36 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker5 extends JITInvoker { + public JITInvoker5() { + super(5); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITInvoker6.java b/src/org/python/modules/jffi/JITInvoker6.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITInvoker6.java @@ -0,0 +1,40 @@ +package org.python.modules.jffi; + +import org.python.core.PyObject; + +/** + * + */ +abstract public class JITInvoker6 extends JITInvoker { + public JITInvoker6() { + super(6); + } + + public final PyObject invoke() { + return invalidArity(0); + } + + public final PyObject invoke(PyObject arg1) { + return invalidArity(1); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2) { + return invalidArity(2); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3) { + return invalidArity(3); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4) { + return invalidArity(4); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5) { + return invalidArity(5); + } + + public final PyObject invoke(PyObject arg1, PyObject arg2, PyObject arg3, PyObject arg4, PyObject arg5, PyObject arg6) { + return invalidArity(6); + } +} diff --git a/src/org/python/modules/jffi/JITMethodGenerator.java b/src/org/python/modules/jffi/JITMethodGenerator.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITMethodGenerator.java @@ -0,0 +1,11 @@ +package org.python.modules.jffi; + +/** + * + */ +public interface JITMethodGenerator { + + public boolean isSupported(JITSignature signature); + + public void generate(AsmClassBuilder builder, String functionName, JITSignature signature); +} diff --git a/src/org/python/modules/jffi/JITRuntime.java b/src/org/python/modules/jffi/JITRuntime.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITRuntime.java @@ -0,0 +1,180 @@ +package org.python.modules.jffi; + +import org.python.core.Py; +import org.python.core.PyInteger; +import org.python.core.PyLong; +import org.python.core.PyObject; + +import java.math.BigInteger; + +/** + * + */ +public final class JITRuntime { + private JITRuntime() {} + + public static int pointerValue32(PyObject ptr) { + return (int) ((Pointer) ptr).getMemory().getAddress(); + } + + public static long pointerValue64(PyObject ptr) { + return ((Pointer) ptr).getMemory().getAddress(); + } + + public static int intValue(PyObject parameter) { + if (parameter instanceof PyInteger) { + return ((PyInteger) parameter).getValue(); + + } else if (parameter instanceof PyLong) { + return ((PyLong) parameter).getValue().intValue(); + + } else { + return (int) __long__value(parameter); + } + } + public static long longValue(PyObject parameter) { + if (parameter instanceof PyInteger) { + return ((PyInteger) parameter).getValue(); + + } else if (parameter instanceof PyLong) { + return ((PyLong) parameter).getValue().longValue(); + + } else { + return __long__value(parameter); + } + } + + static final long __long__value(PyObject parameter) { + PyObject value = parameter.__long__(); + + if (value instanceof PyLong) { + return ((PyLong) value).getValue().longValue(); + + } else if (value instanceof PyInteger) { + return ((PyInteger) value).getValue(); + } + + throw Py.TypeError("invalid __long__() result"); + } + + public static int boolValue32(PyObject parameter) { + return parameter.__nonzero__() ? 1 : 0; + } + + public static long boolValue64(PyObject parameter) { + return parameter.__nonzero__() ? 1L : 0L; + } + + public static int s8Value32(PyObject parameter) { + return (byte) intValue(parameter); + } + + public static long s8Value64(PyObject parameter) { + return (byte) intValue(parameter); + } + + public static int u8Value32(PyObject parameter) { + return intValue(parameter) & 0xff; + } + + public static long u8Value64(PyObject parameter) { + return ((long) intValue(parameter)) & 0xffL; + } + + public static int s16Value32(PyObject parameter) { + return (short) intValue(parameter); + } + + public static long s16Value64(PyObject parameter) { + return (short) intValue(parameter); + } + + public static int u16Value32(PyObject parameter) { + return intValue(parameter) & 0xffff; + } + + public static long u16Value64(PyObject parameter) { + return ((long) intValue(parameter)) & 0xffffL; + } + + + public static int s32Value32(PyObject parameter) { + return intValue(parameter); + } + + public static long s32Value64(PyObject parameter) { + return intValue(parameter); + } + + public static int u32Value32(PyObject parameter) { + return intValue(parameter); + } + + public static long u32Value64(PyObject parameter) { + return ((long) intValue(parameter)) & 0xffffffffL; + } + + public static long s64Value64(PyObject parameter) { + return longValue(parameter); + } + + public static long u64Value64(PyObject parameter) { + return longValue(parameter); + } + + public static int float2int32(PyObject parameter) { + return Float.floatToRawIntBits((float) parameter.asDouble()); + } + + public static long float2int64(PyObject parameter) { + return Float.floatToRawIntBits((float) parameter.asDouble()); + } + + public static long double2long64(PyObject parameter) { + return Double.doubleToRawLongBits(parameter.asDouble()); + } + + + public static PyObject newSigned8(byte value) { + return Py.newInteger(value); + } + + public static PyObject newUnsigned8(byte value) { + return Py.newInteger(value < 0 ? (long)((value & 0x7FL) + 0x80L) : value); + } + + public static PyObject newSigned16(short value) { + return Py.newInteger(value); + } + + public static PyObject newUnsigned16(short value) { + return Py.newInteger(value < 0 ? (long)((value & 0x7FFFL) + 0x8000L) : value); + } + + public static PyObject newSigned32(int value) { + return Py.newInteger(value); + } + + public static PyObject newUnsigned32(int value) { + return Py.newInteger(value < 0 ? (long)((value & 0x7FFFFFFFL) + 0x80000000L) : value); + } + + public static PyObject newSigned64(long value) { + return Py.newInteger(value); + } + + private static final BigInteger UINT64_BASE = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE); + public static PyObject newUnsigned64(long value) { + return value < 0 + ? Py.newLong(BigInteger.valueOf(value & 0x7fffffffffffffffL).add(UINT64_BASE)) + : Py.newInteger(value); + } + + public static PyObject newFloat32(int value) { + return Py.newFloat(Float.intBitsToFloat(value)); + } + + public static PyObject newFloat64(long value) { + return Py.newFloat(Double.longBitsToDouble(value)); + } +} diff --git a/src/org/python/modules/jffi/JITSignature.java b/src/org/python/modules/jffi/JITSignature.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/JITSignature.java @@ -0,0 +1,81 @@ +package org.python.modules.jffi; + +import com.kenai.jffi.CallingConvention; + +import java.util.Arrays; + +/** + * + */ +public final class JITSignature { + private final NativeType resultType; + private final NativeType[] parameterTypes; + private final boolean hasResultConverter; + private final boolean[] hasParameterConverter; + private final CallingConvention convention; + private final boolean ignoreError; + + public JITSignature(NativeType resultType, NativeType[] parameterTypes, + boolean hasResultConverter, boolean[] hasParameterConverter, + CallingConvention convention, boolean ignoreError) { + this.resultType = resultType; + this.parameterTypes = (NativeType[]) parameterTypes.clone(); + this.convention = convention; + this.ignoreError = ignoreError; + this.hasResultConverter = hasResultConverter; + this.hasParameterConverter = (boolean[]) hasParameterConverter.clone(); + } + + @Override + public boolean equals(Object o) { + if (o == null || !o.getClass().equals(getClass())) { + return false; + } + JITSignature rhs = (JITSignature) o; + return resultType.equals(rhs.resultType) && convention.equals(rhs.convention) + && ignoreError == rhs.ignoreError + && Arrays.equals(parameterTypes, rhs.parameterTypes) + && hasResultConverter == rhs.hasResultConverter + && Arrays.equals(hasParameterConverter, rhs.hasParameterConverter); + + } + + @Override + public int hashCode() { + return resultType.hashCode() + ^ convention.hashCode() + ^ Boolean.valueOf(ignoreError).hashCode() + ^ Arrays.hashCode(parameterTypes) + ^ Boolean.valueOf(hasResultConverter).hashCode() + ^ Arrays.hashCode(hasParameterConverter); + } + + public final NativeType getResultType() { + return resultType; + } + + public final NativeType getParameterType(int parameterIndex) { + return parameterTypes[parameterIndex]; + } + + public final CallingConvention getCallingConvention() { + return convention; + } + + public final int getParameterCount() { + return parameterTypes.length; + } + + public final boolean hasResultConverter() { + return hasResultConverter; + } + + public final boolean hasParameterConverter(int parameterIndex) { + return hasParameterConverter[parameterIndex]; + } + + public boolean isIgnoreError() { + return ignoreError; + } + +} diff --git a/src/org/python/modules/jffi/NativeDataConverter.java b/src/org/python/modules/jffi/NativeDataConverter.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/NativeDataConverter.java @@ -0,0 +1,35 @@ +package org.python.modules.jffi; + + +import org.python.core.PyObject; + +/** + * + */ +abstract public class NativeDataConverter { + private final boolean referenceRequired; + private final boolean postInvokeRequired; + + public NativeDataConverter() { + this.referenceRequired = false; + this.postInvokeRequired = false; + } + + public NativeDataConverter(boolean referenceRequired, boolean postInvokeRequired) { + this.referenceRequired = referenceRequired; + this.postInvokeRequired = postInvokeRequired; + } + + + public final boolean isReferenceRequired() { + return referenceRequired; + } + + public final boolean isPostInvokeRequired() { + return postInvokeRequired; + } + + abstract public PyObject fromNative(PyObject obj); + abstract public PyObject toNative(PyObject obj); + abstract public NativeType nativeType(); +} diff --git a/src/org/python/modules/jffi/NativeType.java b/src/org/python/modules/jffi/NativeType.java --- a/src/org/python/modules/jffi/NativeType.java +++ b/src/org/python/modules/jffi/NativeType.java @@ -18,6 +18,9 @@ FLOAT, DOUBLE, POINTER, + BUFFER_IN, + BUFFER_OUT, + BUFFER_INOUT, STRING, ARRAY, STRUCT; diff --git a/src/org/python/modules/jffi/SkinnyMethodAdapter.java b/src/org/python/modules/jffi/SkinnyMethodAdapter.java new file mode 100644 --- /dev/null +++ b/src/org/python/modules/jffi/SkinnyMethodAdapter.java @@ -0,0 +1,915 @@ +/* + * SkinnyMethodAdapter.java + * + * Created on March 10, 2007, 2:52 AM + * + * To change this template, choose Tools | Template Manager + * and open the template in the editor. + */ + +package org.python.modules.jffi; + +import org.objectweb.asm.*; +import org.objectweb.asm.util.TraceMethodVisitor; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.util.Map; + +import static org.python.modules.jffi.CodegenUtils.*; + +/** + * + * @author headius + */ +public class SkinnyMethodAdapter implements MethodVisitor, Opcodes { + private final static boolean DEBUG = Boolean.getBoolean("jython.compile.dump"); + private MethodVisitor method; + private String name; + private ClassVisitor cv; + + /** Creates a new instance of SkinnyMethodAdapter */ + public SkinnyMethodAdapter(MethodVisitor method) { + setMethodVisitor(method); + } + + public SkinnyMethodAdapter(ClassVisitor cv, int flags, String name, String signature, String something, String[] exceptions) { + setMethodVisitor(cv.visitMethod(flags, name, signature, something, exceptions)); + this.cv = cv; + this.name = name; + } + + public SkinnyMethodAdapter() { + } + + public MethodVisitor getMethodVisitor() { + return method; + } + + public void setMethodVisitor(MethodVisitor mv) { + if (DEBUG) { + this.method = new TraceMethodVisitor(mv); + } else { + this.method = mv; + } + } + + /** + * Short-hand for specifying a set of aloads + * + * @param args list of aloads you want + */ + public void aloadMany(int... args) { + for (int arg: args) { + aload(arg); + } + } + + public void aload(int arg0) { + getMethodVisitor().visitVarInsn(ALOAD, arg0); + } + + public void iload(int arg0) { + getMethodVisitor().visitVarInsn(ILOAD, arg0); + } + + public void lload(int arg0) { + getMethodVisitor().visitVarInsn(LLOAD, arg0); + } + + public void fload(int arg0) { + getMethodVisitor().visitVarInsn(FLOAD, arg0); + } + + public void dload(int arg0) { + getMethodVisitor().visitVarInsn(DLOAD, arg0); + } + + public void astore(int arg0) { + getMethodVisitor().visitVarInsn(ASTORE, arg0); + } + + public void istore(int arg0) { + getMethodVisitor().visitVarInsn(ISTORE, arg0); + } + + public void lstore(int arg0) { + getMethodVisitor().visitVarInsn(LSTORE, arg0); + } + + public void fstore(int arg0) { + getMethodVisitor().visitVarInsn(FSTORE, arg0); + } + + public void dstore(int arg0) { + getMethodVisitor().visitVarInsn(DSTORE, arg0); + } + + public void ldc(Object arg0) { + getMethodVisitor().visitLdcInsn(arg0); + } + + public void bipush(int arg) { + getMethodVisitor().visitIntInsn(BIPUSH, arg); + } + + public void sipush(int arg) { + getMethodVisitor().visitIntInsn(SIPUSH, arg); + } + + public void pushInt(int value) { + if (value <= Byte.MAX_VALUE && value >= Byte.MIN_VALUE) { + switch (value) { + case -1: + iconst_m1(); + break; + case 0: + iconst_0(); + break; + case 1: + iconst_1(); + break; + case 2: + iconst_2(); + break; + case 3: + iconst_3(); + break; + case 4: + iconst_4(); + break; + case 5: + iconst_5(); + break; + default: + bipush(value); + break; + } + } else if (value <= Short.MAX_VALUE && value >= Short.MIN_VALUE) { + sipush(value); + } else { + ldc(value); + } + } + + public void pushBoolean(boolean bool) { + if (bool) iconst_1(); else iconst_0(); + } + + public void invokestatic(String arg1, String arg2, String arg3) { + getMethodVisitor().visitMethodInsn(INVOKESTATIC, arg1, arg2, arg3); + } + + public void invokespecial(String arg1, String arg2, String arg3) { + getMethodVisitor().visitMethodInsn(INVOKESPECIAL, arg1, arg2, arg3); + } + + public void invokevirtual(String arg1, String arg2, String arg3) { + getMethodVisitor().visitMethodInsn(INVOKEVIRTUAL, arg1, arg2, arg3); + } + + public void invokeinterface(String arg1, String arg2, String arg3) { + getMethodVisitor().visitMethodInsn(INVOKEINTERFACE, arg1, arg2, arg3); + } + + public void aprintln() { + dup(); + getstatic(p(System.class), "out", ci(PrintStream.class)); + swap(); + invokevirtual(p(PrintStream.class), "println", sig(void.class, params(Object.class))); + } + + public void iprintln() { + dup(); + getstatic(p(System.class), "out", ci(PrintStream.class)); + swap(); + invokevirtual(p(PrintStream.class), "println", sig(void.class, params(int.class))); + } + + public void areturn() { + getMethodVisitor().visitInsn(ARETURN); + } + + public void ireturn() { + getMethodVisitor().visitInsn(IRETURN); + } + + public void freturn() { + getMethodVisitor().visitInsn(FRETURN); + } + + public void lreturn() { + getMethodVisitor().visitInsn(LRETURN); + } + + public void dreturn() { + getMethodVisitor().visitInsn(DRETURN); + } + + public void newobj(String arg0) { + getMethodVisitor().visitTypeInsn(NEW, arg0); + } + + public void dup() { + getMethodVisitor().visitInsn(DUP); + } + + public void swap() { + getMethodVisitor().visitInsn(SWAP); + } + + public void swap2() { + dup2_x2(); + pop2(); + } + + public void getstatic(String arg1, String arg2, String arg3) { + getMethodVisitor().visitFieldInsn(GETSTATIC, arg1, arg2, arg3); + } + + public void putstatic(String arg1, String arg2, String arg3) { + getMethodVisitor().visitFieldInsn(PUTSTATIC, arg1, arg2, arg3); + } + + public void getfield(String arg1, String arg2, String arg3) { + getMethodVisitor().visitFieldInsn(GETFIELD, arg1, arg2, arg3); + } + + public void putfield(String arg1, String arg2, String arg3) { + getMethodVisitor().visitFieldInsn(PUTFIELD, arg1, arg2, arg3); + } + + public void voidreturn() { + getMethodVisitor().visitInsn(RETURN); + } + + public void anewarray(String arg0) { + getMethodVisitor().visitTypeInsn(ANEWARRAY, arg0); + } + + public void multianewarray(String arg0, int dims) { + getMethodVisitor().visitMultiANewArrayInsn(arg0, dims); + } + + public void newarray(int arg0) { + getMethodVisitor().visitIntInsn(NEWARRAY, arg0); + } + + public void iconst_m1() { + getMethodVisitor().visitInsn(ICONST_M1); + } + + public void iconst_0() { + getMethodVisitor().visitInsn(ICONST_0); + } + + public void iconst_1() { + getMethodVisitor().visitInsn(ICONST_1); + } + + public void iconst_2() { + getMethodVisitor().visitInsn(ICONST_2); + } + + public void iconst_3() { + getMethodVisitor().visitInsn(ICONST_3); + } + + public void iconst_4() { + getMethodVisitor().visitInsn(ICONST_4); + } + + public void iconst_5() { + getMethodVisitor().visitInsn(ICONST_5); + } + + public void lconst_0() { + getMethodVisitor().visitInsn(LCONST_0); + } + + public void aconst_null() { + getMethodVisitor().visitInsn(ACONST_NULL); + } + + public void label(Label label) { + getMethodVisitor().visitLabel(label); + } + + public void nop() { + getMethodVisitor().visitInsn(NOP); + } + + public void pop() { + getMethodVisitor().visitInsn(POP); + } + + public void pop2() { + getMethodVisitor().visitInsn(POP2); + } + + public void arrayload() { + getMethodVisitor().visitInsn(AALOAD); + } + + public void arraystore() { + getMethodVisitor().visitInsn(AASTORE); + } + + public void iarrayload() { + getMethodVisitor().visitInsn(IALOAD); + } + + public void barrayload() { + getMethodVisitor().visitInsn(BALOAD); + } + + public void barraystore() { + getMethodVisitor().visitInsn(BASTORE); + } + + public void aaload() { + getMethodVisitor().visitInsn(AALOAD); + } + + public void aastore() { + getMethodVisitor().visitInsn(AASTORE); + } + + public void iaload() { + getMethodVisitor().visitInsn(IALOAD); + } + + public void iastore() { + getMethodVisitor().visitInsn(IASTORE); + } + + public void laload() { + getMethodVisitor().visitInsn(LALOAD); + } + + public void lastore() { + getMethodVisitor().visitInsn(LASTORE); + } + + public void baload() { + getMethodVisitor().visitInsn(BALOAD); + } + + public void bastore() { + getMethodVisitor().visitInsn(BASTORE); + } + + public void saload() { + getMethodVisitor().visitInsn(SALOAD); + } + + public void sastore() { + getMethodVisitor().visitInsn(SASTORE); + } + + public void caload() { + getMethodVisitor().visitInsn(CALOAD); + } + + public void castore() { + getMethodVisitor().visitInsn(CASTORE); + } + + public void faload() { + getMethodVisitor().visitInsn(FALOAD); + } + + public void fastore() { + getMethodVisitor().visitInsn(FASTORE); + } + + public void daload() { + getMethodVisitor().visitInsn(DALOAD); + } + + public void dastore() { + getMethodVisitor().visitInsn(DASTORE); + } + + public void fcmpl() { + getMethodVisitor().visitInsn(FCMPL); + } + + public void fcmpg() { + getMethodVisitor().visitInsn(FCMPG); + } + + public void dcmpl() { + getMethodVisitor().visitInsn(DCMPL); + } + + public void dcmpg() { + getMethodVisitor().visitInsn(DCMPG); + } + + public void dup_x2() { + getMethodVisitor().visitInsn(DUP_X2); + } + + public void dup_x1() { + getMethodVisitor().visitInsn(DUP_X1); + } + + public void dup2_x2() { + getMethodVisitor().visitInsn(DUP2_X2); + } + + public void dup2_x1() { + getMethodVisitor().visitInsn(DUP2_X1); + } + + public void dup2() { + getMethodVisitor().visitInsn(DUP2); + } + + public void trycatch(Label arg0, Label arg1, Label arg2, + String arg3) { + getMethodVisitor().visitTryCatchBlock(arg0, arg1, arg2, arg3); + } + + public void trycatch(String type, Runnable body, Runnable catchBody) { + Label before = new Label(); + Label after = new Label(); + Label catchStart = new Label(); + Label done = new Label(); + + trycatch(before, after, catchStart, type); + label(before); + body.run(); + label(after); + go_to(done); + if (catchBody != null) { + label(catchStart); + catchBody.run(); + } + label(done); + } + + public void go_to(Label arg0) { + getMethodVisitor().visitJumpInsn(GOTO, arg0); + } + + public void lookupswitch(Label arg0, int[] arg1, Label[] arg2) { + getMethodVisitor().visitLookupSwitchInsn(arg0, arg1, arg2); + } + + public void athrow() { + getMethodVisitor().visitInsn(ATHROW); + } + + public void instance_of(String arg0) { + getMethodVisitor().visitTypeInsn(INSTANCEOF, arg0); + } + + public void ifeq(Label arg0) { + getMethodVisitor().visitJumpInsn(IFEQ, arg0); + } + + public void iffalse(Label arg0) { + ifeq(arg0); + } + + public void ifne(Label arg0) { + getMethodVisitor().visitJumpInsn(IFNE, arg0); + } + + public void iftrue(Label arg0) { + ifne(arg0); + } + + public void if_acmpne(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ACMPNE, arg0); + } + + public void if_acmpeq(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ACMPEQ, arg0); + } + + public void if_icmple(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPLE, arg0); + } + + public void if_icmpgt(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPGT, arg0); + } + + public void if_icmplt(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPLT, arg0); + } + + public void if_icmpne(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPNE, arg0); + } + + public void if_icmpeq(Label arg0) { + getMethodVisitor().visitJumpInsn(IF_ICMPEQ, arg0); + } + + public void checkcast(String arg0) { + getMethodVisitor().visitTypeInsn(CHECKCAST, arg0); + } + + public void start() { + getMethodVisitor().visitCode(); + } + + public void end() { + if (DEBUG) { + PrintWriter pw = new PrintWriter(System.out); + String className = "(unknown class)"; + if (cv instanceof ClassWriter) { + className = new ClassReader(((ClassWriter)cv).toByteArray()).getClassName(); + } + if (name != null) { + pw.write("*** Dumping " + className + "." + name + " ***\n"); + } else { + pw.write("*** Dumping ***\n"); + } + ((TraceMethodVisitor)getMethodVisitor()).print(pw); + pw.flush(); + } + getMethodVisitor().visitMaxs(1, 1); + getMethodVisitor().visitEnd(); + } + + public void line(int line) { + Label label = new Label(); + label(label); + visitLineNumber(line, label); + } + + public void line(int line, Label label) { + visitLineNumber(line, label); + } + + public void ifnonnull(Label arg0) { + getMethodVisitor().visitJumpInsn(IFNONNULL, arg0); + } + + public void ifnull(Label arg0) { + getMethodVisitor().visitJumpInsn(IFNULL, arg0); + } + + public void iflt(Label arg0) { + getMethodVisitor().visitJumpInsn(IFLT, arg0); + } + + public void ifle(Label arg0) { + getMethodVisitor().visitJumpInsn(IFLE, arg0); + } + + public void ifgt(Label arg0) { + getMethodVisitor().visitJumpInsn(IFGT, arg0); + } + + public void ifge(Label arg0) { + getMethodVisitor().visitJumpInsn(IFGE, arg0); + } + + public void arraylength() { + getMethodVisitor().visitInsn(ARRAYLENGTH); + } + + public void ishr() { + getMethodVisitor().visitInsn(ISHR); + } + + public void ishl() { + getMethodVisitor().visitInsn(ISHL); + } + + public void iushr() { + getMethodVisitor().visitInsn(IUSHR); + } + + public void lshr() { + getMethodVisitor().visitInsn(LSHR); + } + + public void lshl() { + getMethodVisitor().visitInsn(LSHL); + } + + public void lushr() { + getMethodVisitor().visitInsn(LUSHR); + } + + public void lcmp() { + getMethodVisitor().visitInsn(LCMP); + } + + public void iand() { + getMethodVisitor().visitInsn(IAND); + } + + public void ior() { + getMethodVisitor().visitInsn(IOR); + } + + public void ixor() { + getMethodVisitor().visitInsn(IXOR); + } + + public void land() { + getMethodVisitor().visitInsn(LAND); + } + + public void lor() { + getMethodVisitor().visitInsn(LOR); + } + + public void lxor() { + getMethodVisitor().visitInsn(LXOR); + } + + public void iadd() { + getMethodVisitor().visitInsn(IADD); + } + + public void ladd() { + getMethodVisitor().visitInsn(LADD); + } + + public void fadd() { + getMethodVisitor().visitInsn(FADD); + } + + public void dadd() { + getMethodVisitor().visitInsn(DADD); + } + + public void isub() { + getMethodVisitor().visitInsn(ISUB); + } + + public void lsub() { + getMethodVisitor().visitInsn(LSUB); + } + + public void fsub() { + getMethodVisitor().visitInsn(FSUB); + } + + public void dsub() { + getMethodVisitor().visitInsn(DSUB); + } + + public void idiv() { + getMethodVisitor().visitInsn(IDIV); + } + + public void irem() { + getMethodVisitor().visitInsn(IREM); + } + + public void ineg() { + getMethodVisitor().visitInsn(INEG); + } + + public void i2d() { + getMethodVisitor().visitInsn(I2D); + } + + public void i2l() { + getMethodVisitor().visitInsn(I2L); + } + + public void i2f() { + getMethodVisitor().visitInsn(I2F); + } + + public void i2s() { + getMethodVisitor().visitInsn(I2S); + } + + public void i2c() { + getMethodVisitor().visitInsn(I2C); + } + + public void i2b() { + getMethodVisitor().visitInsn(I2B); + } + + public void ldiv() { + getMethodVisitor().visitInsn(LDIV); + } + + public void lrem() { + getMethodVisitor().visitInsn(LREM); + } + + public void lneg() { + getMethodVisitor().visitInsn(LNEG); + } + + public void l2d() { + getMethodVisitor().visitInsn(L2D); + } + + public void l2i() { + getMethodVisitor().visitInsn(L2I); + } + + public void l2f() { + getMethodVisitor().visitInsn(L2F); + } + + public void fdiv() { + getMethodVisitor().visitInsn(FDIV); + } + + public void frem() { + getMethodVisitor().visitInsn(FREM); + } + + public void fneg() { + getMethodVisitor().visitInsn(FNEG); + } + + public void f2d() { + getMethodVisitor().visitInsn(F2D); + } + + public void f2i() { + getMethodVisitor().visitInsn(F2D); + } + + public void f2l() { + getMethodVisitor().visitInsn(F2L); + } + + public void ddiv() { + getMethodVisitor().visitInsn(DDIV); + } + + public void drem() { + getMethodVisitor().visitInsn(DREM); + } + + public void dneg() { + getMethodVisitor().visitInsn(DNEG); + } + + public void d2f() { + getMethodVisitor().visitInsn(D2F); + } + + public void d2i() { + getMethodVisitor().visitInsn(D2I); + } + + public void d2l() { + getMethodVisitor().visitInsn(D2L); + } + + public void imul() { + getMethodVisitor().visitInsn(IMUL); + } + + public void lmul() { + getMethodVisitor().visitInsn(LMUL); + } + + public void fmul() { + getMethodVisitor().visitInsn(FMUL); + } + + public void dmul() { + getMethodVisitor().visitInsn(DMUL); + } + + public void iinc(int arg0, int arg1) { + getMethodVisitor().visitIincInsn(arg0, arg1); + } + + public void monitorenter() { + getMethodVisitor().visitInsn(MONITORENTER); + } + + public void monitorexit() { + getMethodVisitor().visitInsn(MONITOREXIT); + } + + public void jsr(Label branch) { + getMethodVisitor().visitJumpInsn(JSR, branch); + } + + public void ret(int arg0) { + getMethodVisitor().visitVarInsn(RET, arg0); + } + + public AnnotationVisitor visitAnnotationDefault() { + return getMethodVisitor().visitAnnotationDefault(); + } + + public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) { + return getMethodVisitor().visitAnnotation(arg0, arg1); + } + + public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1, + boolean arg2) { + return getMethodVisitor().visitParameterAnnotation(arg0, arg1, arg2); + } + + public void visitAttribute(Attribute arg0) { + getMethodVisitor().visitAttribute(arg0); + } + + public void visitCode() { + getMethodVisitor().visitCode(); + } + + public void visitInsn(int arg0) { + getMethodVisitor().visitInsn(arg0); + } + + public void visitIntInsn(int arg0, int arg1) { + getMethodVisitor().visitIntInsn(arg0, arg1); + } + + public void visitVarInsn(int arg0, int arg1) { + getMethodVisitor().visitVarInsn(arg0, arg1); + } + + public void visitTypeInsn(int arg0, String arg1) { + getMethodVisitor().visitTypeInsn(arg0, arg1); + } + + public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) { + getMethodVisitor().visitFieldInsn(arg0, arg1, arg2, arg3); + } + + public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) { + getMethodVisitor().visitMethodInsn(arg0, arg1, arg2, arg3); + } + + public void visitJumpInsn(int arg0, Label arg1) { + getMethodVisitor().visitJumpInsn(arg0, arg1); + } + + public void visitLabel(Label arg0) { + getMethodVisitor().visitLabel(arg0); + } + + public void visitLdcInsn(Object arg0) { + getMethodVisitor().visitLdcInsn(arg0); + } + + public void visitIincInsn(int arg0, int arg1) { + getMethodVisitor().visitIincInsn(arg0, arg1); + } + + public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, + Label[] arg3) { + getMethodVisitor().visitTableSwitchInsn(arg0, arg1, arg2, arg3); + } + + public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) { + getMethodVisitor().visitLookupSwitchInsn(arg0, arg1, arg2); + } + + public void visitMultiANewArrayInsn(String arg0, int arg1) { + getMethodVisitor().visitMultiANewArrayInsn(arg0, arg1); + } + + public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2, + String arg3) { + getMethodVisitor().visitTryCatchBlock(arg0, arg1, arg2, arg3); + } + + public void visitLocalVariable(String arg0, String arg1, String arg2, + Label arg3, Label arg4, int arg5) { + getMethodVisitor().visitLocalVariable(arg0, arg1, arg2, arg3, arg4, arg5); + } + + public void visitLineNumber(int arg0, Label arg1) { + getMethodVisitor().visitLineNumber(arg0, arg1); + } + + public void visitMaxs(int arg0, int arg1) { + if (DEBUG) { + PrintWriter pw = new PrintWriter(System.out); + pw.write("*** Dumping ***\n"); + ((TraceMethodVisitor)getMethodVisitor()).print(pw); + pw.flush(); + } + getMethodVisitor().visitMaxs(arg0, arg1); + } + + public void visitEnd() { + getMethodVisitor().visitEnd(); + } + + public void tableswitch(int min, int max, Label defaultLabel, Label[] cases) { + getMethodVisitor().visitTableSwitchInsn(min, max, defaultLabel, cases); + } + + public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4) { + getMethodVisitor().visitFrame(arg0, arg1, arg2, arg3, arg4); + } +} -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Mon Sep 5 01:48:42 2011 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 05 Sep 2011 01:48:42 +0200 Subject: [Jython-checkins] =?utf8?q?jython_=282=2E5=29=3A_Fix_http=3A//bug?= =?utf8?q?s=2Ejython=2Eorg/issue1764=3A_Broken_behavior_with_=28a_+_b=29?= =?utf8?b?LmZvbyA9IGJhci4=?= Message-ID: http://hg.python.org/jython/rev/dc4ebe0a697f changeset: 6244:dc4ebe0a697f branch: 2.5 parent: 6233:d75393f1eb8d user: Frank Wierzbicki date: Sun Sep 04 16:31:24 2011 -0700 summary: Fix http://bugs.jython.org/issue1764: Broken behavior with (a + b).foo = bar. Make left hand side argument recursively correct Store->Load in the case where there are child elements and a Call, Subscript, etc. files: ast/astview.py | Bin grammar/Python.g | 4 +--- src/org/python/antlr/GrammarActions.java | 1 - 3 files changed, 1 insertions(+), 4 deletions(-) diff --git a/ast/astview.py b/ast/astview.py old mode 100644 new mode 100755 diff --git a/grammar/Python.g b/grammar/Python.g --- a/grammar/Python.g +++ b/grammar/Python.g @@ -1588,9 +1588,7 @@ $etype = actions.castExpr($atom.tree); if ($t != null) { for(Object o : $t) { - if ($etype instanceof Context) { - ((Context)$etype).setContext(expr_contextType.Load); - } + actions.recurseSetContext($etype, expr_contextType.Load); if (o instanceof Call) { Call c = (Call)o; c.setFunc((PyObject)$etype); diff --git a/src/org/python/antlr/GrammarActions.java b/src/org/python/antlr/GrammarActions.java --- a/src/org/python/antlr/GrammarActions.java +++ b/src/org/python/antlr/GrammarActions.java @@ -615,7 +615,6 @@ } void checkDelete(expr e) { - //System.out.println("trying to del " + e); if (e instanceof Call) { errorHandler.error("can't delete function call", e); } else if (e instanceof Num) { -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Mon Sep 5 01:48:42 2011 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 05 Sep 2011 01:48:42 +0200 Subject: [Jython-checkins] =?utf8?q?jython_=282=2E5=29=3A_Add_=2Ehgignore_?= =?utf8?q?to_2=2E5=2E?= Message-ID: http://hg.python.org/jython/rev/8831af94a9fc changeset: 6245:8831af94a9fc branch: 2.5 user: Frank Wierzbicki date: Sun Sep 04 16:37:27 2011 -0700 summary: Add .hgignore to 2.5. files: .hgignore | 27 +++++++++++++++++++++++++++ 1 files changed, 27 insertions(+), 0 deletions(-) diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,27 @@ +syntax: glob +*.class +*.pyc +*.pyd +*.pyo +*.orig +*.rej +*.swp +*~ +# IntelliJ files +*.ipr +*.iml +*.iws + +.AppleDouble +.DS_Store +.classpath +.externalToolBuilders +.project +.settings +__pycache__ +ant.properties +bin +build +cachedir +dist +profile.txt -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Mon Sep 5 01:48:42 2011 From: jython-checkins at python.org (frank.wierzbicki) Date: Mon, 05 Sep 2011 01:48:42 +0200 Subject: [Jython-checkins] =?utf8?q?jython_=28merge_2=2E5_-=3E_default=29?= =?utf8?q?=3A_Merge_from_2=2E5=2E?= Message-ID: http://hg.python.org/jython/rev/8a8642e45433 changeset: 6246:8a8642e45433 parent: 6243:6792a9cea71d parent: 6245:8831af94a9fc user: Frank Wierzbicki date: Sun Sep 04 16:39:47 2011 -0700 summary: Merge from 2.5. files: ast/astview.py | Bin grammar/Python.g | 4 +--- src/org/python/antlr/GrammarActions.java | 1 - 3 files changed, 1 insertions(+), 4 deletions(-) diff --git a/ast/astview.py b/ast/astview.py old mode 100644 new mode 100755 diff --git a/grammar/Python.g b/grammar/Python.g --- a/grammar/Python.g +++ b/grammar/Python.g @@ -1633,9 +1633,7 @@ $etype = actions.castExpr($atom.tree); if ($t != null) { for(Object o : $t) { - if ($etype instanceof Context) { - ((Context)$etype).setContext(expr_contextType.Load); - } + actions.recurseSetContext($etype, expr_contextType.Load); if (o instanceof Call) { Call c = (Call)o; c.setFunc((PyObject)$etype); diff --git a/src/org/python/antlr/GrammarActions.java b/src/org/python/antlr/GrammarActions.java --- a/src/org/python/antlr/GrammarActions.java +++ b/src/org/python/antlr/GrammarActions.java @@ -626,7 +626,6 @@ } void checkDelete(expr e) { - //System.out.println("trying to del " + e); if (e instanceof Call) { errorHandler.error("can't delete function call", e); } else if (e instanceof Num) { -- Repository URL: http://hg.python.org/jython From jython-checkins at python.org Thu Sep 22 05:45:42 2011 From: jython-checkins at python.org (frank.wierzbicki) Date: Thu, 22 Sep 2011 05:45:42 +0200 Subject: [Jython-checkins] =?utf8?q?jython=3A_Make_cStringIO_throw_IOError?= =?utf8?q?_when_a_negative_argument_is_passed_to_truncate=2E?= Message-ID: http://hg.python.org/jython/rev/a95ffe555a27 changeset: 6247:a95ffe555a27 user: Frank Wierzbicki date: Sat Sep 17 20:37:43 2011 -0700 summary: Make cStringIO throw IOError when a negative argument is passed to truncate. files: src/org/python/modules/cStringIO.java | 9 ++++++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/org/python/modules/cStringIO.java b/src/org/python/modules/cStringIO.java --- a/src/org/python/modules/cStringIO.java +++ b/src/org/python/modules/cStringIO.java @@ -11,6 +11,7 @@ package org.python.modules; +import com.kenai.constantine.platform.Errno; import org.python.core.Py; import org.python.core.PyIterator; import org.python.core.PyList; @@ -298,14 +299,17 @@ /** * truncate the file at the current position. */ - public void truncate() { - truncate(-1); + public synchronized void truncate() { + buf.setLength(this.pos); } /** * truncate the file at the position pos. */ public synchronized void truncate(long pos) { + if (pos < 0) { + throw Py.IOError(Errno.EINVAL, "Negative size not allowed"); + } int pos_int = _convert_to_int(pos); if (pos_int < 0) pos_int = this.pos; @@ -313,7 +317,6 @@ this.pos = pos_int; } - /** * Write a string to the file. * @param obj The data to write. -- Repository URL: http://hg.python.org/jython