Pointer.java
- package org.jruby.ext.ffi;
- import java.nio.ByteOrder;
- import org.jruby.*;
- import org.jruby.anno.JRubyClass;
- import org.jruby.anno.JRubyMethod;
- import org.jruby.internal.runtime.methods.CallConfiguration;
- import org.jruby.internal.runtime.methods.DynamicMethod;
- import org.jruby.runtime.*;
- import org.jruby.runtime.builtin.IRubyObject;
- import static org.jruby.runtime.Visibility.*;
- /**
- * C memory pointer operations.
- * <p>
- * This is an abstract class that defines Pointer operations
- * </p>
- */
- @JRubyClass(name="FFI::Pointer", parent=AbstractMemory.ABSTRACT_MEMORY_RUBY_CLASS)
- public class Pointer extends AbstractMemory {
- public static RubyClass createPointerClass(Ruby runtime, RubyModule module) {
- RubyClass pointerClass = module.defineClassUnder("Pointer",
- module.getClass(AbstractMemory.ABSTRACT_MEMORY_RUBY_CLASS),
- RubyInstanceConfig.REIFY_RUBY_CLASSES ? new ReifyingAllocator(Pointer.class) : PointerAllocator.INSTANCE);
- pointerClass.defineAnnotatedMethods(Pointer.class);
- pointerClass.defineAnnotatedConstants(Pointer.class);
- pointerClass.setReifiedClass(Pointer.class);
- pointerClass.kindOf = new RubyModule.KindOf() {
- @Override
- public boolean isKindOf(IRubyObject obj, RubyModule type) {
- return obj instanceof Pointer && super.isKindOf(obj, type);
- }
- };
- module.defineClassUnder("NullPointerError", runtime.getRuntimeError(),
- runtime.getRuntimeError().getAllocator());
- // Add Pointer::NULL as a constant
- Pointer nullPointer = new Pointer(runtime, pointerClass, new NullMemoryIO(runtime));
- pointerClass.setConstant("NULL", nullPointer);
-
- runtime.getNilClass().addMethod("to_ptr", new NilToPointerMethod(runtime.getNilClass(), nullPointer));
- return pointerClass;
- }
- private static final class PointerAllocator implements ObjectAllocator {
- static final ObjectAllocator INSTANCE = new PointerAllocator();
- public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
- return new Pointer(runtime, klazz);
- }
- }
- public static final Pointer getNull(Ruby runtime) {
- return runtime.getFFI().nullPointer;
- }
- public Pointer(Ruby runtime, RubyClass klazz) {
- super(runtime, klazz, runtime.getFFI().getNullMemoryIO(), 0);
- }
- public Pointer(Ruby runtime, MemoryIO io) {
- this(runtime, getPointerClass(runtime), io);
- }
- public Pointer(Ruby runtime, MemoryIO io, long size, int typeSize) {
- this(runtime, getPointerClass(runtime), io, size, typeSize);
- }
- protected Pointer(Ruby runtime, RubyClass klass, MemoryIO io) {
- super(runtime, klass, io, Long.MAX_VALUE);
- }
- protected Pointer(Ruby runtime, RubyClass klass, MemoryIO io, long size) {
- super(runtime, klass, io, size);
- }
- protected Pointer(Ruby runtime, RubyClass klass, MemoryIO io, long size, int typeSize) {
- super(runtime, klass, io, size, typeSize);
- }
- public static final RubyClass getPointerClass(Ruby runtime) {
- return runtime.getFFI().pointerClass;
- }
- public final AbstractMemory order(Ruby runtime, ByteOrder order) {
- return new Pointer(runtime,
- order.equals(getMemoryIO().order()) ? getMemoryIO() : new SwappedMemoryIO(runtime, getMemoryIO()),
- size, typeSize);
- }
-
- @JRubyMethod(name = "size", meta = true, visibility = PUBLIC)
- public static IRubyObject size(ThreadContext context, IRubyObject recv) {
- return RubyFixnum.newFixnum(context.getRuntime(), Factory.getInstance().sizeOf(NativeType.POINTER));
- }
- @JRubyMethod(name = { "initialize" }, visibility = PRIVATE)
- public IRubyObject initialize(ThreadContext context, IRubyObject address) {
- setMemoryIO(address instanceof Pointer
- ? ((Pointer) address).getMemoryIO()
- : Factory.getInstance().wrapDirectMemory(context.runtime, RubyFixnum.num2long(address)));
- size = Long.MAX_VALUE;
- typeSize = 1;
- return this;
- }
- @JRubyMethod(name = { "initialize" }, visibility = PRIVATE)
- public IRubyObject initialize(ThreadContext context, IRubyObject type, IRubyObject address) {
- setMemoryIO(address instanceof Pointer
- ? ((Pointer) address).getMemoryIO()
- : Factory.getInstance().wrapDirectMemory(context.runtime, RubyFixnum.num2long(address)));
- size = Long.MAX_VALUE;
- typeSize = calculateTypeSize(context, type);
- return this;
- }
-
- /**
- *
- */
- @JRubyMethod(required = 1, visibility=PRIVATE)
- public IRubyObject initialize_copy(ThreadContext context, IRubyObject other) {
- if (this == other) {
- return this;
- }
- Pointer orig = (Pointer) other;
- this.typeSize = orig.typeSize;
- this.size = orig.size;
- setMemoryIO(orig.getMemoryIO().dup());
- return this;
- }
- /**
- * Tests if this <tt>Pointer</tt> represents the C <tt>NULL</tt> value.
- *
- * @return true if the address is NULL.
- */
- @JRubyMethod(name = "null?")
- public IRubyObject null_p(ThreadContext context) {
- return context.runtime.newBoolean(getMemoryIO().isNull());
- }
- @Override
- @JRubyMethod(name = { "to_s", "inspect" }, optional = 1)
- public IRubyObject to_s(ThreadContext context, IRubyObject[] args) {
- String s = size != Long.MAX_VALUE
- ? String.format("#<%s address=0x%x size=%s>", getMetaClass().getName(), getAddress(), size)
- : String.format("#<%s address=0x%x>", getMetaClass().getName(), getAddress());
- return RubyString.newString(context.runtime, s);
- }
- @JRubyMethod(name = { "address", "to_i" })
- public IRubyObject address(ThreadContext context) {
- return context.runtime.newFixnum(getAddress());
- }
- /**
- * Gets the native memory address of this pointer.
- *
- * @return A long containing the native memory address.
- */
- public final long getAddress() {
- return getMemoryIO().address();
- }
- @JRubyMethod(name = "==", required = 1)
- public IRubyObject op_equal(ThreadContext context, IRubyObject obj) {
- return context.runtime.newBoolean(this == obj
- || getAddress() == 0L && obj.isNil()
- || (obj instanceof Pointer && ((Pointer) obj).getAddress() == getAddress()));
- }
-
- @Override
- protected AbstractMemory slice(Ruby runtime, long offset) {
- return new Pointer(runtime, getPointerClass(runtime),
- getMemoryIO().slice(offset),
- size == Long.MAX_VALUE ? Long.MAX_VALUE : size - offset, typeSize);
- }
- @Override
- protected AbstractMemory slice(Ruby runtime, long offset, long size) {
- return new Pointer(runtime, getPointerClass(runtime),
- getMemoryIO().slice(offset, size), size, typeSize);
- }
- protected Pointer getPointer(Ruby runtime, long offset) {
- return new Pointer(runtime, getPointerClass(runtime), getMemoryIO().getMemoryIO(offset), Long.MAX_VALUE);
- }
- private static final class NilToPointerMethod extends DynamicMethod {
- private static final Arity ARITY = Arity.NO_ARGUMENTS;
- private final Pointer nullPointer;
- private NilToPointerMethod(RubyModule implementationClass, Pointer nullPointer) {
- super(implementationClass, Visibility.PUBLIC, CallConfiguration.FrameNoneScopeNone);
- this.nullPointer = nullPointer;
- }
- @Override
- public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name, IRubyObject[] args, Block block) {
- ARITY.checkArity(context.runtime, args);
- return nullPointer;
- }
- @Override
- public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule klazz, String name) {
- return nullPointer;
- }
- @Override
- public DynamicMethod dup() {
- return this;
- }
- }
- }