From: <wme...@us...> - 2009-08-26 05:25:27
|
Revision: 6720 http://jython.svn.sourceforge.net/jython/?rev=6720&view=rev Author: wmeissner Date: 2009-08-26 05:25:19 +0000 (Wed, 26 Aug 2009) Log Message: ----------- Experimental implementation of pointer and byref Modified Paths: -------------- branches/ctypes-jffi/CoreExposed.includes branches/ctypes-jffi/Lib/ctypes/__init__.py branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java branches/ctypes-jffi/src/org/python/modules/jffi/Pointer.java branches/ctypes-jffi/src/org/python/modules/jffi/ScalarCData.java branches/ctypes-jffi/src/org/python/modules/jffi/Type.java Added Paths: ----------- branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedDirectMemory.java branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedNativeMemory.java branches/ctypes-jffi/src/org/python/modules/jffi/CData.java branches/ctypes-jffi/src/org/python/modules/jffi/InvalidMemory.java branches/ctypes-jffi/src/org/python/modules/jffi/NullMemory.java Modified: branches/ctypes-jffi/CoreExposed.includes =================================================================== --- branches/ctypes-jffi/CoreExposed.includes 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/CoreExposed.includes 2009-08-26 05:25:19 UTC (rev 6720) @@ -52,6 +52,7 @@ org/python/modules/_csv/PyWriter.class org/python/modules/_functools/PyPartial.class org/python/modules/_hashlib$Hash.class +org/python/modules/jffi/CData.class org/python/modules/jffi/DynamicLibrary.class org/python/modules/jffi/DynamicLibrary$Symbol.class org/python/modules/jffi/Function.class @@ -59,6 +60,7 @@ org/python/modules/jffi/ScalarCData.class org/python/modules/jffi/Type.class org/python/modules/jffi/Type$Array.class +org/python/modules/jffi/Type$Pointer.class org/python/modules/_threading/Condition.class org/python/modules/_threading/Lock.class org/python/modules/_weakref/CallableProxyType.class Modified: branches/ctypes-jffi/Lib/ctypes/__init__.py =================================================================== --- branches/ctypes-jffi/Lib/ctypes/__init__.py 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/Lib/ctypes/__init__.py 2009-08-26 05:25:19 UTC (rev 6720) @@ -32,6 +32,15 @@ def alignment(type): return type._jffi_type.alignment +def byref(cdata): + return cdata.byref() + +def pointer(cdata): + return cdata.pointer() + +def POINTER(type): + return jffi.Type.Pointer(type._jffi_type, type) + class c_byte(_ScalarCData): _jffi_type = jffi.Type.BYTE Added: branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedDirectMemory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedDirectMemory.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedDirectMemory.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -0,0 +1,7 @@ + +package org.python.modules.jffi; + +public interface AllocatedDirectMemory extends DirectMemory { + public void free(); + public void setAutoRelease(boolean autorelease); +} Added: branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedNativeMemory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedNativeMemory.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/AllocatedNativeMemory.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -0,0 +1,67 @@ + +package org.python.modules.jffi; + +import org.python.core.Py; + +class AllocatedNativeMemory extends BoundedNativeMemory implements AllocatedDirectMemory { + private volatile boolean released = false; + private volatile boolean autorelease = true; + + /** The real memory address */ + private final long storage; + + /** + * Allocates native memory + * + * @param size The number of bytes to allocate + * @param clear Whether the memory should be cleared (zeroed) + * @return A new {@link AllocatedDirectMemory} + */ + static final AllocatedNativeMemory allocate(int size, boolean clear) { + return allocateAligned(size, 1, clear); + } + + /** + * Allocates native memory, aligned to a minimum boundary. + * + * @param size The number of bytes to allocate + * @param align The minimum alignment of the memory + * @param clear Whether the memory should be cleared (zeroed) + * @return A new {@link AllocatedDirectMemory} + */ + static final AllocatedNativeMemory allocateAligned(int size, int align, boolean clear) { + long memory = IO.allocateMemory(size + align - 1, clear); + if (memory == 0) { + throw Py.RuntimeError("failed to allocate " + size + " bytes"); + } + return new AllocatedNativeMemory(memory, size, align); + } + + private AllocatedNativeMemory(long address, int size, int align) { + super(((address - 1) & ~(align - 1)) + align, size); + this.storage = address; + } + + public void free() { + if (!released) { + IO.freeMemory(storage); + released = true; + } + } + + public void setAutoRelease(boolean release) { + this.autorelease = release; + } + + @Override + protected void finalize() throws Throwable { + try { + if (!released && autorelease) { + IO.freeMemory(storage); + released = true; + } + } finally { + super.finalize(); + } + } +} Added: branches/ctypes-jffi/src/org/python/modules/jffi/CData.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/CData.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/CData.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -0,0 +1,80 @@ + +package org.python.modules.jffi; + +import org.python.core.Py; +import org.python.core.PyObject; +import org.python.core.PyType; +import org.python.expose.ExposedGet; +import org.python.expose.ExposedMethod; +import org.python.expose.ExposedSet; +import org.python.expose.ExposedType; + +@ExposedType(name = "jffi.CData", base = PyObject.class) +public abstract class CData extends PyObject { + public static final PyType TYPE = PyType.fromClass(CData.class); + + final MemoryOp memoryOp; + final Type type; + + private Memory contentMemory; + private PyObject value; + + CData(PyType subtype, Type type, MemoryOp memoryOp) { + super(subtype); + this.type = type; + this.memoryOp = memoryOp; + this.value = Py.None; + this.contentMemory = null; + } + + @ExposedGet(name = "value") + public PyObject getValue() { + // If native memory has been allocated, read the value from there + if (contentMemory != null) { + return memoryOp.get(contentMemory, 0); + } + + return value; + } + + + @ExposedSet(name = "value") + public void setValue(PyObject value) { + this.value = value; + // If native memory has been allocated, sync the value to memory + if (contentMemory != null) { + memoryOp.put(contentMemory, 0, value); + } + } + + @ExposedMethod(names= { "byref", "pointer" }) + public PyObject byref() { + return new Pointer((DirectMemory) getContentMemory(), memoryOp); + } + + boolean hasValueMemory() { + return contentMemory != null; + } + + void setContentMemory(Memory memory) { + if (!(memory instanceof DirectMemory)) { + throw Py.TypeError("invalid memory"); + } + this.contentMemory = memory; + } + + Memory getContentMemory() { + if (contentMemory != null) { + return contentMemory; + } + + return allocateDirect(); + } + + private DirectMemory allocateDirect() { + DirectMemory m = AllocatedNativeMemory.allocate(type.size(), false); + memoryOp.put(m, 0, value); + contentMemory = m; + return m; + } +} Modified: branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/src/org/python/modules/jffi/DefaultInvokerFactory.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -426,7 +426,11 @@ public static final ParameterMarshaller INSTANCE = new PointerMarshaller(); public void marshal(HeapInvocationBuffer buffer, PyObject parameter) { - throw Py.NotImplementedError("POINTER parameters not implemented"); + if (parameter instanceof Pointer) { + buffer.putAddress(((Pointer) parameter).address); + } else { + throw Py.TypeError("expected pointer argument"); + } } } Added: branches/ctypes-jffi/src/org/python/modules/jffi/InvalidMemory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/InvalidMemory.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/InvalidMemory.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -0,0 +1,182 @@ + + +package org.python.modules.jffi; + +import org.python.core.Py; +import org.python.core.PyException; + +/** + * An implementation of Memory that throws an exception on any access. + */ +public abstract class InvalidMemory implements Memory { + private final String message; + + public InvalidMemory(String message) { + this.message = message; + } + + protected PyException ex() { + return Py.MemoryError(message); + } + + public Memory slice(long offset) { + return this; + } + + public java.nio.ByteBuffer asByteBuffer() { + throw ex(); + } + + public final byte getByte(long offset) { + throw ex(); + } + + public final short getShort(long offset) { + throw ex(); + } + + public final int getInt(long offset) { + throw ex(); + } + + public final long getLong(long offset) { + throw ex(); + } + + public final long getNativeLong(long offset) { + throw ex(); + } + + public final float getFloat(long offset) { + throw ex(); + } + + public final double getDouble(long offset) { + throw ex(); + } + + public final DirectMemory getMemory(long offset) { + throw ex(); + } + + public final long getAddress(long offset) { + throw ex(); + } + + public final void putByte(long offset, byte value) { + throw ex(); + } + + public final void putShort(long offset, short value) { + throw ex(); + } + + public final void putInt(long offset, int value) { + throw ex(); + } + + public final void putLong(long offset, long value) { + throw ex(); + } + + public final void putNativeLong(long offset, long value) { + throw ex(); + } + + public final void putFloat(long offset, float value) { + throw ex(); + } + + public final void putDouble(long offset, double value) { + throw ex(); + } + + public final void putMemory(long offset, Memory value) { + throw ex(); + } + + public final void putAddress(long offset, long value) { + throw ex(); + } + + public final void putAddress(long offset, Memory value) { + throw ex(); + } + + public final void get(long offset, byte[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, byte[] src, int off, int len) { + throw ex(); + } + + public final void get(long offset, short[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, short[] src, int off, int len) { + throw ex(); + } + + public final void get(long offset, int[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, int[] src, int off, int len) { + throw ex(); + } + + public final void get(long offset, long[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, long[] src, int off, int len) { + throw ex(); + } + + public final void get(long offset, float[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, float[] src, int off, int len) { + throw ex(); + } + + public final void get(long offset, double[] dst, int off, int len) { + throw ex(); + } + + public final void put(long offset, double[] src, int off, int len) { + throw ex(); + } + + public final int indexOf(long offset, byte value) { + throw ex(); + } + + public final int indexOf(long offset, byte value, int maxlen) { + throw ex(); + } + + public final void setMemory(long offset, long size, byte value) { + throw ex(); + } + + public final void clear() { + throw ex(); + } + + public byte[] getZeroTerminatedByteArray(long offset) { + throw ex(); + } + + public byte[] getZeroTerminatedByteArray(long offset, int maxlen) { + throw ex(); + } + + public void putZeroTerminatedByteArray(long offset, byte[] bytes, int off, int len) { + throw ex(); + } + +} Modified: branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/src/org/python/modules/jffi/MemoryOp.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -8,6 +8,7 @@ * Defines memory operations for a primitive type */ abstract class MemoryOp { + public static final MemoryOp INVALID = new InvalidOp(); public static final MemoryOp VOID = new VoidOp(); public static final MemoryOp INT8 = new Signed8(); public static final MemoryOp UINT8 = new Unsigned8(); @@ -64,6 +65,16 @@ abstract PyObject get(Memory mem, long offset); abstract void put(Memory mem, long offset, PyObject value); + private static final class InvalidOp extends MemoryOp { + public final void put(Memory mem, long offset, PyObject value) { + throw Py.TypeError("invalid memory access"); + } + + public final PyObject get(Memory mem, long offset) { + throw Py.TypeError("invalid memory access"); + } + } + private static final class VoidOp extends MemoryOp { public final void put(Memory mem, long offset, PyObject value) { throw Py.TypeError("Attempting to write void to memory"); @@ -166,11 +177,16 @@ } private static final class PointerOp extends MemoryOp { public final void put(Memory mem, long offset, PyObject value) { - mem.putAddress(offset, Util.int64Value(value)); + if (value instanceof Pointer) { + mem.putAddress(offset, ((Pointer) value).address); + } else { + mem.putAddress(offset, Util.int64Value(value)); + } } public final PyObject get(Memory mem, long offset) { - return Py.newLong(mem.getAddress(offset)); + DirectMemory dm = new NativeMemory(mem.getAddress(offset)); + return new Pointer(dm.getAddress(), dm); } } private static final class StringOp extends MemoryOp { Added: branches/ctypes-jffi/src/org/python/modules/jffi/NullMemory.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/NullMemory.java (rev 0) +++ branches/ctypes-jffi/src/org/python/modules/jffi/NullMemory.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -0,0 +1,35 @@ + + +package org.python.modules.jffi; + +/** + * An implementation of MemoryIO that throws an exception on any access. + */ +public class NullMemory extends InvalidMemory implements DirectMemory { + static final NullMemory INSTANCE = new NullMemory(); + public NullMemory() { + super("NULL pointer access"); + } + + public long getAddress() { + return 0L; + } + + public boolean isNull() { + return true; + } + public final boolean isDirect() { + return true; + } + + @Override + public boolean equals(Object obj) { + return obj instanceof DirectMemory && ((DirectMemory) obj).getAddress() == 0; + } + + @Override + public int hashCode() { + return 0; + } + +} Modified: branches/ctypes-jffi/src/org/python/modules/jffi/Pointer.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/Pointer.java 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/src/org/python/modules/jffi/Pointer.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -14,15 +14,35 @@ public final long address; final Memory memory; + final MemoryOp componentMemoryOp; public Pointer(PyType type, long address, Memory memory) { super(type); this.address = address; this.memory = memory; + this.componentMemoryOp = MemoryOp.INVALID; } public Pointer(long address, Memory memory) { this.address = address; this.memory = memory; + this.componentMemoryOp = MemoryOp.INVALID; } + + Pointer(DirectMemory memory, MemoryOp componentMemoryOp) { + this(TYPE, memory, componentMemoryOp); + } + + Pointer(PyType subtype, DirectMemory memory, MemoryOp componentMemoryOp) { + super(subtype); + this.address = memory.getAddress(); + this.memory = memory; + this.componentMemoryOp = componentMemoryOp; + } + + @ExposedGet(name="contents") + public PyObject contents() { + return componentMemoryOp.get(memory, 0); + } + } Modified: branches/ctypes-jffi/src/org/python/modules/jffi/ScalarCData.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/ScalarCData.java 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/src/org/python/modules/jffi/ScalarCData.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -7,21 +7,14 @@ import org.python.core.PyObject; import org.python.core.PyObject.ConversionException; import org.python.core.PyType; -import org.python.expose.ExposedGet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; -import org.python.expose.ExposedSet; import org.python.expose.ExposedType; -@ExposedType(name = "jffi.ScalarCData", base = PyObject.class) -public class ScalarCData extends PyObject { +@ExposedType(name = "jffi.ScalarCData", base = CData.class) +public class ScalarCData extends CData { public static final PyType TYPE = PyType.fromClass(ScalarCData.class); - final Type.Builtin type; - private PyObject value; - private Memory memory; - - @ExposedNew public static PyObject ScalarCData_new(PyNewWrapper new_, boolean init, PyType subtype, PyObject[] args, String[] keywords) { @@ -41,31 +34,9 @@ } ScalarCData(PyType pyType, Type.Builtin type) { - super(pyType); - this.type = type; - this.memory = null; - } + super(pyType, type, type.getMemoryOp()); + } - @ExposedGet(name = "value") - public PyObject getValue() { - // If native memory has been allocated, read the value from there - if (memory != null) { - return type.getMemoryOp().get(memory, 0); - } - - return value; - } - - - @ExposedSet(name = "value") - public void setValue(PyObject value) { - this.value = value; - // If native memory has been allocated, sync the value to memory - if (memory != null) { - type.getMemoryOp().put(memory, 0, value); - } - } - @Override public int asInt() { return getValue().asInt(); Modified: branches/ctypes-jffi/src/org/python/modules/jffi/Type.java =================================================================== --- branches/ctypes-jffi/src/org/python/modules/jffi/Type.java 2009-08-26 04:19:39 UTC (rev 6719) +++ branches/ctypes-jffi/src/org/python/modules/jffi/Type.java 2009-08-26 05:25:19 UTC (rev 6720) @@ -1,20 +1,24 @@ package org.python.modules.jffi; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.python.core.Py; import org.python.core.PyNewWrapper; import org.python.core.PyObject; +import org.python.core.PyObjectDerived; import org.python.core.PyType; import org.python.expose.ExposeAsSuperclass; import org.python.expose.ExposedGet; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; -@ExposedType(name = "jffi.Type", base = PyObject.class) +@ExposedType(name = "jffi.Type", base = PyObjectDerived.class) public class Type extends PyObject { public static final PyType TYPE = PyType.fromClass(Type.class); static { TYPE.fastGetDict().__setitem__("Array", Array.TYPE); + TYPE.fastGetDict().__setitem__("Pointer", Pointer.TYPE); } public static final Type VOID = primitive(NativeType.VOID); public static final Type SINT8 = primitive(NativeType.BYTE); @@ -55,7 +59,6 @@ this.memoryOp = memoryOp; } - public NativeType getNativeType() { return nativeType; } @@ -123,6 +126,104 @@ return length; } + @Override + public final String toString() { + return String.format("<jffi.Type.Array length=%d>", length); + } + } + @ExposedType(name = "jffi.Type.Pointer", base = Type.class) + final static class Pointer extends Type { + public static final PyType TYPE = PyType.fromClass(Pointer.class); + private static final ConcurrentMap<PyObject, Pointer> typeCache + = new ConcurrentHashMap<PyObject, Pointer>(); + + final Type componentType; + final PyType pyComponentType; + final MemoryOp componentMemoryOp; + + Pointer(PyType subtype, Type componentType, PyType pyComponentType) { + super(NativeType.POINTER, com.kenai.jffi.Type.POINTER, MemoryOp.POINTER); + this.componentType = componentType; + this.pyComponentType = pyComponentType; + if (pyComponentType.isSubType(ScalarCData.TYPE)) { + this.componentMemoryOp = new ScalarOp(MemoryOp.getMemoryOp(componentType.getNativeType()), pyComponentType); + } else { + throw Py.TypeError("pointer only supported for scalar types"); + } + + } + + @ExposedNew + public static PyObject Pointer_new(PyNewWrapper new_, boolean init, PyType subtype, + PyObject[] args, String[] keywords) { + + Pointer p = typeCache.get(args[0]); + if (p != null) { + return p; + } + + if (args.length < 1) { + throw Py.TypeError(String.format("__init__() takes exactly 1 argument (%d given)", args.length)); + } + + if (!(args[0] instanceof Type)) { + throw Py.TypeError("expected jffi.Type"); + } + + if (args.length > 1 && !(args[1] instanceof PyType)) { + throw Py.TypeError("expected type"); + } + p = new Pointer(subtype, (Type) args[0], args.length > 1 ? (PyType) args[1] : Py.None.getType()); + typeCache.put(args[0], p); + + return p; + } + + @Override + public final String toString() { + return String.format("<jffi.Type.Pointer component_type=%s>", componentType.toString()); + } + + @Override + public PyObject __call__(PyObject value) { + if (value == Py.None) { + + return new org.python.modules.jffi.Pointer(new NullMemory(), componentMemoryOp); + + } else if (value.getType().isSubType(pyComponentType) && value instanceof CData) { + + return new org.python.modules.jffi.Pointer((DirectMemory) ((CData) value).getContentMemory(), componentMemoryOp); + + } else { + throw Py.TypeError("expected " + pyComponentType.getName() + " instead of " + value.getType().getName()); + } + } + + private static final class ScalarOp extends MemoryOp { + private final MemoryOp op; + private final PyType type; + + public ScalarOp(MemoryOp op, PyType type) { + this.op = op; + this.type = type; + } + + public final void put(Memory mem, long offset, PyObject value) { + op.put(mem, offset, value); + } + + public final PyObject get(Memory mem, long offset) { + PyObject result = type.__call__(op.get(mem, offset)); + // + // Point the CData to the backing memory so all value gets/sets + // update the same memory this pointer points to + // + if (result instanceof CData) { + ((CData) result).setContentMemory(mem); + } + return result; + } + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |