Permalink
Browse files

Merge branch 'master' into fast

  • Loading branch information...
2 parents 7226515 + e207d1a commit ad3d2f0f9c14052cea87c8ba33a34c61f0ce99b3 @headius headius committed Aug 17, 2010
View
24 bench/ffi/bench_struct_field.rb
@@ -0,0 +1,24 @@
+require 'benchmark'
+require 'ffi'
+
+class S < FFI::Struct
+ layout :a, :int, :b, :int
+end
+
+iter = 1000_000
+puts "Benchmark FFI struct field get performance, #{iter}x"
+
+10.times {
+ puts Benchmark.measure {
+ s = S.new(FFI::Buffer.new(S))
+ iter.times { s[:a] }
+ }
+}
+
+10.times {
+ puts Benchmark.measure {
+ s = S.new(FFI::Buffer.new(S))
+ iter.times { s['a'] }
+ }
+}
+
View
10 build.xml
@@ -304,7 +304,7 @@
<zipfileset src="${build.lib.dir}/jffi-i386-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-x86_64-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-s390x-Linux.jar"/>
- <zipfileset src="${build.lib.dir}/joda-time-1.6.jar"/>
+ <zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<zipfileset src="${build.lib.dir}/yydebug.jar"/>
<zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
<metainf dir="${base.dir}/spi">
@@ -347,7 +347,7 @@
<zipfileset src="${build.lib.dir}/joni.jar"/>
<zipfileset src="${build.lib.dir}/jnr-netdb.jar"/>
<zipfileset src="${build.lib.dir}/jnr-posix.jar"/>
- <zipfileset src="${build.lib.dir}/joda-time-1.6.jar"/>
+ <zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<manifest>
<attribute name="Built-By" value="${user.name}"/>
<attribute name="Main-Class" value="org.jruby.Main"/>
@@ -392,7 +392,7 @@
<zipfileset src="${build.lib.dir}/jffi-i386-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-x86_64-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-s390x-Linux.jar"/>
- <zipfileset src="${build.lib.dir}/joda-time-1.6.jar"/>
+ <zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<zipfileset src="${build.lib.dir}/yydebug.jar"/>
<zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
<metainf dir="${base.dir}/spi">
@@ -490,7 +490,7 @@
<zipfileset src="${build.lib.dir}/jffi-i386-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-x86_64-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-s390x-Linux.jar"/>
- <zipfileset src="${build.lib.dir}/joda-time-1.6.jar"/>
+ <zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<zipfileset src="${build.lib.dir}/yydebug.jar"/>
<zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
<zipfileset src="${shared.lib.dir}/yecht.jar"/>
@@ -580,7 +580,7 @@
<zipfileset src="${build.lib.dir}/jffi-i386-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-x86_64-Windows.jar"/>
<zipfileset src="${build.lib.dir}/jffi-s390x-Linux.jar"/>
- <zipfileset src="${build.lib.dir}/joda-time-1.6.jar"/>
+ <zipfileset src="${build.lib.dir}/joda-time-1.6.1.jar"/>
<zipfileset src="${build.lib.dir}/yydebug.jar"/>
<zipfileset src="${build.lib.dir}/nailgun-0.7.1.jar"/>
<zipfileset src="${shared.lib.dir}/yecht.jar"/>
View
BIN build_lib/joda-time-1.6.jar → build_lib/joda-time-1.6.1.jar
Binary file not shown.
View
2 lib/ruby/1.8/webrick/httpresponse.rb
@@ -209,7 +209,7 @@ def set_error(ex, backtrace=false)
@keep_alive = false
self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
end
- @header['content-type'] = "text/html; charset=utf-8"
+ @header['content-type'] = "text/html; charset=ISO-8859-1"
if respond_to?(:create_error_page)
create_error_page()
View
2 lib/ruby/1.9/webrick/httpresponse.rb
@@ -208,7 +208,7 @@ def set_error(ex, backtrace=false)
@keep_alive = false
self.status = HTTPStatus::RC_INTERNAL_SERVER_ERROR
end
- @header['content-type'] = "text/html; charset=utf-8"
+ @header['content-type'] = "text/html; charset=ISO-8859-1"
if respond_to?(:create_error_page)
create_error_page()
View
17 lib/ruby/site_ruby/shared/ffi/struct.rb
@@ -43,17 +43,7 @@ def offset_of(field_name)
self[field_name].offset
end
- class Enum < Field
-
- def get(ptr)
- type.find(ptr.get_int(offset))
- end
-
- def put(ptr, value)
- ptr.put_int(offset, type.find(value))
- end
-
- end
+ # Enum is implemented in java
# InnerStruct is implemented in java
@@ -178,6 +168,7 @@ def layout(*spec)
builder.union = self < Union
builder.packed = @packed if defined?(@packed)
builder.alignment = @min_alignment if defined?(@min_alignment)
+ builder.byte_order = @byte_order
if spec[0].kind_of?(Hash)
hash_layout(builder, spec)
@@ -209,6 +200,10 @@ def aligned(alignment = 1)
end
alias :align :aligned
+ def byte_order(order = :native)
+ @byte_order = order
+ end
+
def enclosing_module
begin
mod = self.name.split("::")[0..-2].inject(Object) { |obj, c| obj.const_get(c) }
View
3 lib/ruby/site_ruby/shared/ffi/struct_layout_builder.rb
@@ -21,6 +21,7 @@
module FFI
class StructLayoutBuilder
attr_reader :size, :alignment
+ attr_accessor :byte_order
def initialize
@size = 0
@@ -151,7 +152,7 @@ def field_for_type(name, offset, type)
raise TypeError, "invalid struct field type #{type.inspect}"
end
- field_class.new(name, offset, type)
+ field_class.new(name, offset, type, :byte_order => @byte_order)
end
end
View
2 nbproject/project.xml
@@ -225,7 +225,7 @@
<java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
<compilation-unit>
<package-root>${src.dir}</package-root>
- <classpath mode="compile">build_lib/junit.jar:build_lib/jline-0.9.93.jar:build_lib/jna.jar:build_lib/nailgun-0.7.1.jar:build_lib/joni.jar:build_lib/dynalang-0.3.jar:build_lib/invokedynamic.jar:build_lib/jcodings.jar:build_lib/constantine.jar:build_lib/bytelist.jar:build_lib/jffi.jar:build_lib/yydebug.jar:build_lib/bsf.jar:build_lib/jaffl.jar:build_lib/asm-3.2.jar:build_lib/asm-analysis-3.2.jar:build_lib/asm-commons-3.2.jar:build_lib/asm-tree-3.2.jar:build_lib/asm-util-3.2.jar:build_lib/jsr292-mock.jar:build_lib/jgrapht-jdk1.5.jar:build_lib/jnr-netdb.jar:build_lib/jnr-posix.jar:build_lib/joda-time-1.6.jar:build_lib/livetribe-jsr223-2.0.6.jar</classpath>
+ <classpath mode="compile">build_lib/junit.jar:build_lib/jline-0.9.93.jar:build_lib/jna.jar:build_lib/nailgun-0.7.1.jar:build_lib/joni.jar:build_lib/dynalang-0.3.jar:build_lib/invokedynamic.jar:build_lib/jcodings.jar:build_lib/constantine.jar:build_lib/bytelist.jar:build_lib/jffi.jar:build_lib/yydebug.jar:build_lib/bsf.jar:build_lib/jaffl.jar:build_lib/asm-3.2.jar:build_lib/asm-analysis-3.2.jar:build_lib/asm-commons-3.2.jar:build_lib/asm-tree-3.2.jar:build_lib/asm-util-3.2.jar:build_lib/jsr292-mock.jar:build_lib/jgrapht-jdk1.5.jar:build_lib/jnr-netdb.jar:build_lib/jnr-posix.jar:build_lib/joda-time-1.6.1.jar:build_lib/livetribe-jsr223-2.0.6.jar</classpath>
<built-to>${jruby.classes.dir}</built-to>
<built-to>${lib.dir}/jruby.jar</built-to>
<javadoc-built-to>docs/api</javadoc-built-to>
View
11 src/org/jruby/RubyEnumerator.java
@@ -166,6 +166,17 @@ private IRubyObject initialize(IRubyObject object, IRubyObject method, IRubyObje
return this;
}
+ @JRubyMethod(name = "dup")
+ @Override
+ public IRubyObject dup() {
+ // JRUBY-5013: Enumerator needs to copy private fields in order to have a valid structure
+ RubyEnumerator copy = (RubyEnumerator) super.dup();
+ copy.object = this.object;
+ copy.method = this.method;
+ copy.methodArgs = this.methodArgs;
+ return copy;
+ }
+
/**
* Send current block and supplied args to method on target. According to MRI
* Block may not be given and "each" should just ignore it and call on through to
View
14 src/org/jruby/ext/ffi/AbstractMemory.java
@@ -28,6 +28,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
@@ -1600,7 +1601,20 @@ public IRubyObject put_callback(ThreadContext context, IRubyObject offset, IRuby
public IRubyObject op_plus(ThreadContext context, IRubyObject value) {
return slice(context.getRuntime(), RubyNumeric.fix2long(value));
}
+
+ @JRubyMethod(name = "order", required = 0)
+ public final IRubyObject order(ThreadContext context) {
+ return context.getRuntime().newSymbol(getMemoryIO().order().equals(ByteOrder.LITTLE_ENDIAN) ? "little" : "big");
+ }
+
+ @JRubyMethod(name = "order", required = 1)
+ public final IRubyObject order(ThreadContext context, IRubyObject byte_order) {
+ return order(context.getRuntime(), Util.parseByteOrder(context.getRuntime(), byte_order));
+ }
+
+ abstract public AbstractMemory order(Ruby runtime, ByteOrder order);
abstract protected AbstractMemory slice(Ruby runtime, long offset);
abstract protected AbstractMemory slice(Ruby runtime, long offset, long size);
abstract protected Pointer getPointer(Ruby runtime, long offset);
+
}
View
4 src/org/jruby/ext/ffi/ArrayMemoryIO.java
@@ -70,6 +70,10 @@ public final boolean isDirect() {
return false;
}
+ public final ByteOrder order() {
+ return ByteOrder.nativeOrder();
+ }
+
public ArrayMemoryIO slice(long offset) {
checkBounds(offset, 1);
return offset == 0 ? this : new ArrayMemoryIO(runtime, array(), arrayOffset() + (int) offset, arrayLength() - (int) offset);
View
8 src/org/jruby/ext/ffi/Buffer.java
@@ -2,6 +2,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
@@ -158,6 +159,13 @@ public IRubyObject inspect(ThreadContext context) {
return RubyString.newString(context.getRuntime(),
String.format("#<Buffer size=%d>", size));
}
+
+
+ public final AbstractMemory order(Ruby runtime, ByteOrder order) {
+ return new Buffer(runtime, getMetaClass(),
+ order.equals(getMemoryIO().order()) ? getMemoryIO() : new SwappedMemoryIO(runtime, getMemoryIO()),
+ size, typeSize, inout);
+ }
ArrayMemoryIO getArrayMemoryIO() {
return (ArrayMemoryIO) getMemoryIO();
View
5 src/org/jruby/ext/ffi/InvalidMemoryIO.java
@@ -2,6 +2,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.exceptions.RaiseException;
@@ -29,6 +30,10 @@ protected RubyClass getErrorClass(Ruby runtime) {
protected RaiseException ex() {
return new RaiseException(runtime, getErrorClass(runtime), message, true);
}
+
+ public ByteOrder order() {
+ return ByteOrder.nativeOrder();
+ }
public MemoryIO slice(long offset) {
return this;
View
10 src/org/jruby/ext/ffi/MemoryIO.java
@@ -28,6 +28,8 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
+
/**
* Abstracted memory operations.
* <p>
@@ -51,6 +53,14 @@
public boolean isDirect();
/**
+ * Gets the {@link ByteOrder} this {@code MemoryIO} instance will read/write
+ * values to memory in.
+ *
+ * @return The current ByteOrder
+ */
+ public ByteOrder order();
+
+ /**
* Creates a new MemoryIO pointing to a subset of the memory area of this
* <tt>MemoryIO</tt>.
* @param offset The offset within the existing memory area to start the
View
107 src/org/jruby/ext/ffi/MemoryOp.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.runtime.Block;
@@ -21,8 +22,18 @@
public static final MemoryOp UINT64 = new Unsigned64();
public static final MemoryOp FLOAT32 = new Float32();
public static final MemoryOp FLOAT64 = new Float64();
+ public static final MemoryOp INT16SWAP = new Signed16Swapped();
+ public static final MemoryOp UINT16SWAP = new Unsigned16Swapped();
+ public static final MemoryOp INT32SWAP = new Signed32Swapped();
+ public static final MemoryOp UINT32SWAP = new Unsigned32Swapped();
+ public static final MemoryOp INT64SWAP = new Signed64Swapped();
+ public static final MemoryOp UINT64SWAP = new Unsigned64Swapped();
- public static final MemoryOp getMemoryOp(NativeType type) {
+ public static MemoryOp getMemoryOp(NativeType type) {
+ return getMemoryOp(type, ByteOrder.nativeOrder());
+ }
+
+ public static MemoryOp getMemoryOp(NativeType type, ByteOrder order) {
switch (type) {
case BOOL:
return BOOL;
@@ -31,42 +42,46 @@ public static final MemoryOp getMemoryOp(NativeType type) {
case UCHAR:
return UINT8;
case SHORT:
- return INT16;
+ return order.equals(ByteOrder.nativeOrder()) ? INT16 : INT16SWAP;
case USHORT:
- return UINT16;
+ return order.equals(ByteOrder.nativeOrder()) ? UINT16 : UINT16SWAP;
case INT:
- return INT32;
+ return order.equals(ByteOrder.nativeOrder()) ? INT32 : INT32SWAP;
case UINT:
- return UINT32;
+ return order.equals(ByteOrder.nativeOrder()) ? UINT32 : UINT32SWAP;
case LONG_LONG:
- return INT64;
+ return order.equals(ByteOrder.nativeOrder()) ? INT64 : INT64SWAP;
case ULONG_LONG:
- return UINT64;
+ return order.equals(ByteOrder.nativeOrder()) ? UINT64 : UINT64SWAP;
case FLOAT:
return FLOAT32;
case DOUBLE:
return FLOAT64;
case LONG:
return Platform.getPlatform().longSize() == 32
- ? INT32 : INT64;
+ ? getMemoryOp(NativeType.INT, order) : getMemoryOp(NativeType.LONG_LONG, order);
case ULONG:
return Platform.getPlatform().longSize() == 32
- ? UINT32 : UINT64;
+ ? getMemoryOp(NativeType.UINT, order) : getMemoryOp(NativeType.ULONG_LONG, order);
default:
return null;
}
}
- public static final MemoryOp getMemoryOp(Type type) {
+ public static MemoryOp getMemoryOp(Type type) {
+ return getMemoryOp(type, ByteOrder.nativeOrder());
+ }
+
+ public static MemoryOp getMemoryOp(Type type, ByteOrder order) {
if (type instanceof Type.Builtin) {
- return getMemoryOp(type.getNativeType());
+ return getMemoryOp(type.getNativeType(), order);
} else if (type instanceof StructByValue) {
StructByValue sbv = (StructByValue) type;
return new StructOp(sbv.getStructClass());
} else if (type instanceof MappedType) {
- return getMemoryOp(((MappedType) type).getRealType());
+ return getMemoryOp(((MappedType) type).getRealType(), order);
}
return null;
@@ -112,6 +127,7 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned8(runtime, io.getByte(offset));
}
}
+
static final class Signed16 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, Util.int16Value(value));
@@ -121,6 +137,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned16(runtime, io.getShort(offset));
}
}
+
+ static final class Signed16Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putShort(offset, Short.reverseBytes(Util.int16Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newSigned16(runtime, Short.reverseBytes(io.getShort(offset)));
+ }
+ }
+
static final class Unsigned16 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, (short) Util.uint16Value(value));
@@ -130,6 +157,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned16(runtime, io.getShort(offset));
}
}
+
+ static final class Unsigned16Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putShort(offset, Short.reverseBytes((short) Util.uint16Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newUnsigned16(runtime, Short.reverseBytes(io.getShort(offset)));
+ }
+ }
+
static final class Signed32 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, Util.int32Value(value));
@@ -139,6 +177,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned32(runtime, io.getInt(offset));
}
}
+
+ static final class Signed32Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putInt(offset, Integer.reverseBytes(Util.int32Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newSigned32(runtime, Integer.reverseBytes(io.getInt(offset)));
+ }
+ }
+
static final class Unsigned32 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, (int) Util.uint32Value(value));
@@ -148,6 +197,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned32(runtime, io.getInt(offset));
}
}
+
+ static final class Unsigned32Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putInt(offset, Integer.reverseBytes((int) Util.uint32Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newUnsigned32(runtime, Integer.reverseBytes(io.getInt(offset)));
+ }
+ }
+
static final class Signed64 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Util.int64Value(value));
@@ -157,6 +217,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned64(runtime, io.getLong(offset));
}
}
+
+ static final class Signed64Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putLong(offset, Long.reverseBytes(Util.int64Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newSigned64(runtime, Long.reverseBytes(io.getLong(offset)));
+ }
+ }
+
static final class Unsigned64 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Util.uint64Value(value));
@@ -166,6 +237,17 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned64(runtime, io.getLong(offset));
}
}
+
+ static final class Unsigned64Swapped extends MemoryOp {
+ public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
+ io.putLong(offset, Long.reverseBytes(Util.uint64Value(value)));
+ }
+
+ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
+ return Util.newUnsigned64(runtime, Long.reverseBytes(io.getLong(offset)));
+ }
+ }
+
static final class Float32 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putFloat(offset, Util.floatValue(value));
@@ -175,6 +257,7 @@ public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return runtime.newFloat(io.getFloat(offset));
}
}
+
static final class Float64 extends MemoryOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putDouble(offset, Util.doubleValue(value));
View
7 src/org/jruby/ext/ffi/Pointer.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
@@ -74,6 +75,12 @@ public static final RubyClass getPointerClass(Ruby runtime) {
return runtime.fastGetModule("FFI").fastGetClass("Pointer");
}
+ public final AbstractMemory order(Ruby runtime, ByteOrder order) {
+ return new Pointer(runtime,
+ order.equals(getMemoryIO().order()) ? (DirectMemoryIO) getMemoryIO() : new SwappedMemoryIO(runtime, getMemoryIO()),
+ size, typeSize);
+ }
+
@JRubyMethod(name = { "initialize" })
public IRubyObject initialize(ThreadContext context, IRubyObject address) {
io = Factory.getInstance().wrapDirectMemory(context.getRuntime(), RubyFixnum.num2long(address));
View
13 src/org/jruby/ext/ffi/Struct.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.RubyModule;
@@ -202,6 +203,18 @@ public IRubyObject null_p(ThreadContext context) {
return context.getRuntime().newBoolean(getMemory().getMemoryIO().isNull());
}
+ @JRubyMethod(name = "order", required = 0)
+ public final IRubyObject order(ThreadContext context) {
+ return context.getRuntime().newSymbol(getMemoryIO().order().equals(ByteOrder.LITTLE_ENDIAN) ? "little" : "big");
+ }
+
+ @JRubyMethod(name = "order", required = 1)
+ public final IRubyObject order(ThreadContext context, IRubyObject byte_order) {
+ ByteOrder order = Util.parseByteOrder(context.getRuntime(), byte_order);
+ return new Struct(context.getRuntime(), getMetaClass(), layout,
+ getMemory().order(context.getRuntime(), Util.parseByteOrder(context.getRuntime(), byte_order)));
+ }
+
public final AbstractMemory getMemory() {
return memory != null ? memory : (memory = MemoryPointer.allocate(getRuntime(), layout.getSize(), 1, true));
}
View
130 src/org/jruby/ext/ffi/StructLayout.java
@@ -28,16 +28,19 @@
package org.jruby.ext.ffi;
+import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedHashMap;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.RubyClass;
+import org.jruby.RubyHash;
import org.jruby.RubyInteger;
import org.jruby.RubyModule;
import org.jruby.RubyNumeric;
@@ -63,7 +66,10 @@
static final String CLASS_NAME = "StructLayout";
/** The name:offset map for this struct */
- private final Map<IRubyObject, Member> fieldMap;
+ private final Map<IRubyObject, Member> fieldSymbolMap;
+
+ /** The name:offset map for this struct */
+ private final Map<IRubyObject, Member> fieldStringMap;
/** The ordered list of field names (as symbols) */
private final List<IRubyObject> fieldNames;
@@ -156,8 +162,9 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> fiel
List<Field> fieldList = new ArrayList<Field>(fields.size());
List<IRubyObject> names = new ArrayList<IRubyObject>(fields.size());
List<Member> memberList = new ArrayList<Member>(fields.size());
- Map<IRubyObject, Member> memberMap = new LinkedHashMap<IRubyObject, Member>(fields.size());
-
+ Map<IRubyObject, Member> memberStringMap = new HashMap<IRubyObject, Member>(fields.size());
+ Map<IRubyObject, Member> memberSymbolMap = new IdentityHashMap<IRubyObject, Member>(fields.size() * 2);
+
int index = 0;
for (IRubyObject obj : fields) {
@@ -174,10 +181,11 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> fiel
fieldList.add(f);
Member m = new Member(f, index, f.isCacheable() ? cfCount++ : -1, f.isValueReferenceNeeded() ? refCount++ : -1);
- memberMap.put(f.name, m);
+ memberSymbolMap.put(f.name, m);
// Allow fields to be accessed as ['name'] as well as [:name] for legacy code
- memberMap.put(f.name.asString(), m);
+ memberStringMap.put(f.name, m);
+ memberStringMap.put(f.name.asString(), m);
memberList.add(m);
}
@@ -188,13 +196,16 @@ private StructLayout(Ruby runtime, RubyClass klass, Collection<IRubyObject> fiel
// Create the ordered list of field names from the map
this.fieldNames = Collections.unmodifiableList(new ArrayList<IRubyObject>(names));
this.fields = Collections.unmodifiableList(fieldList);
- this.fieldMap = Collections.unmodifiableMap(memberMap);
+ this.fieldStringMap = Collections.unmodifiableMap(memberStringMap);
+ this.fieldSymbolMap = Collections.unmodifiableMap(memberSymbolMap);
this.members = Collections.unmodifiableList(memberList);
}
- @JRubyMethod(name = "new", meta = true, required = 3)
+ @JRubyMethod(name = "new", meta = true, required = 3, optional = 1)
public static final IRubyObject newStructLayout(ThreadContext context, IRubyObject klass,
- IRubyObject rbFields, IRubyObject size, IRubyObject alignment) {
+ IRubyObject[] args) {
+
+ IRubyObject rbFields = args[0], size = args[1], alignment = args[2];
if (!(rbFields instanceof RubyArray)) {
throw context.getRuntime().newTypeError(rbFields, context.getRuntime().getArray());
@@ -260,7 +271,7 @@ public IRubyObject offsets(ThreadContext context) {
RubyArray offset = RubyArray.newArray(runtime);
// Assemble a [ :name, offset ] array
offset.append(name);
- offset.append(runtime.newFixnum(fieldMap.get(name).offset));
+ offset.append(runtime.newFixnum(getMember(runtime, name).offset));
offsets.append(offset);
}
@@ -292,10 +303,16 @@ final void putValue(ThreadContext context, IRubyObject name, Storage cache, IRub
* @return A <tt>Member</tt> descriptor.
*/
final Member getMember(Ruby runtime, IRubyObject name) {
- Member f = fieldMap.get(name);
+ Member f = fieldSymbolMap.get(name);
if (f != null) {
return f;
}
+
+ f = fieldStringMap.get(name);
+ if (f != null) {
+ return f;
+ }
+
throw runtime.newArgumentError("Unknown field: " + name);
}
@@ -543,9 +560,14 @@ void init(IRubyObject name, IRubyObject type, IRubyObject offset, FieldIO io) {
this.io = io;
}
- @JRubyMethod
- public IRubyObject initialize(ThreadContext context, IRubyObject name, IRubyObject offset, IRubyObject type) {
- init(name, type, offset);
+ void init(IRubyObject[] args, FieldIO io) {
+ init(args[0], args[2], args[1], io);
+ }
+
+ @JRubyMethod(name="initialize", required = 3, optional = 1)
+ public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+
+ init(args[0], args[2], args[1]);
return this;
}
@@ -597,6 +619,27 @@ final FieldIO getFieldIO() {
return io;
}
+ static ByteOrder getByteOrderOption(ThreadContext context, IRubyObject[] args) {
+
+ ByteOrder order = ByteOrder.nativeOrder();
+
+ if (args.length > 3 && args[3] instanceof RubyHash) {
+ RubyHash options = (RubyHash) args[3];
+ IRubyObject byte_order = options.fastARef(RubySymbol.newSymbol(context.getRuntime(), "byte_order"));
+ if (byte_order instanceof RubySymbol || byte_order instanceof RubyString) {
+ String orderName = byte_order.asJavaString();
+ if ("network".equals(orderName) || "big".equals(orderName)) {
+ order = ByteOrder.BIG_ENDIAN;
+
+ } else if ("little".equals(orderName)) {
+ order = ByteOrder.LITTLE_ENDIAN;
+ }
+ }
+ }
+
+ return order;
+ }
+
@JRubyMethod
public final IRubyObject size(ThreadContext context) {
return context.getRuntime().newFixnum(type.getNativeSize());
@@ -638,10 +681,9 @@ public NumberField(Ruby runtime, RubyClass klass) {
}
@Override
- @JRubyMethod
- public IRubyObject initialize(ThreadContext context, IRubyObject name, IRubyObject offset, IRubyObject type) {
+ public final IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
- init(name, type, offset, new NumberFieldIO(checkType(type)));
+ init(args, new NumberFieldIO(checkType(args[2]), getByteOrderOption(context, args)));
return this;
}
@@ -657,7 +699,15 @@ public final IRubyObject allocate(Ruby runtime, RubyClass klass) {
@JRubyClass(name="FFI::StructLayout::Enum", parent="FFI::StructLayout::Field")
public static final class EnumField extends Field {
public EnumField(Ruby runtime, RubyClass klass) {
- super(runtime, klass, EnumFieldIO.INSTANCE);
+ super(runtime, klass);
+ }
+
+ @Override
+ public final IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+
+ init(args, new EnumFieldIO(getByteOrderOption(context, args)));
+
+ return this;
}
}
@@ -704,12 +754,15 @@ public FunctionField(Ruby runtime, RubyClass klass) {
}
@Override
- @JRubyMethod
- public IRubyObject initialize(ThreadContext context, IRubyObject name, IRubyObject offset, IRubyObject type) {
+ @JRubyMethod(name="initialize", required = 3, optional = 1)
+ public final IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+
+ IRubyObject type = args[2];
+
if (!(type instanceof CallbackInfo)) {
throw context.getRuntime().newTypeError(type, context.getRuntime().fastGetModule("FFI").fastGetClass("Type").fastGetClass("Function"));
}
- init(name, type, offset, FunctionFieldIO.INSTANCE);
+ init(args, FunctionFieldIO.INSTANCE);
return this;
}
@@ -730,13 +783,16 @@ public InnerStructField(Ruby runtime, RubyClass klass) {
}
@Override
- @JRubyMethod
- public IRubyObject initialize(ThreadContext context, IRubyObject name, IRubyObject offset, IRubyObject type) {
+ @JRubyMethod(name="initialize", required = 3, optional = 1)
+ public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+
+ IRubyObject type = args[2];
+
if (!(type instanceof StructByValue)) {
throw context.getRuntime().newTypeError(type,
context.getRuntime().fastGetModule("FFI").fastGetClass("Type").fastGetClass("Struct"));
}
- init(name, type, offset, new InnerStructFieldIO((StructByValue) type));
+ init(args, new InnerStructFieldIO((StructByValue) type));
return this;
}
@@ -757,13 +813,15 @@ public ArrayField(Ruby runtime, RubyClass klass) {
}
@Override
- @JRubyMethod
- public IRubyObject initialize(ThreadContext context, IRubyObject name, IRubyObject offset, IRubyObject type) {
+ @JRubyMethod(name="initialize", required = 3, optional = 1)
+ public final IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
+
+ IRubyObject type = args[2];
if (!(type instanceof Type.Array)) {
throw context.getRuntime().newTypeError(type,
context.getRuntime().fastGetModule("FFI").fastGetClass("Type").fastGetClass("Array"));
}
- init(name, type, offset, new ArrayFieldIO((Type.Array) type));
+ init(args, new ArrayFieldIO((Type.Array) type));
return this;
}
@@ -917,8 +975,8 @@ public IRubyObject to_s(ThreadContext context) {
static final class NumberFieldIO implements FieldIO {
private final MemoryOp op;
- NumberFieldIO(Type type) {
- this.op = MemoryOp.getMemoryOp(type);
+ NumberFieldIO(Type type, ByteOrder order) {
+ this.op = MemoryOp.getMemoryOp(type, order);
}
NumberFieldIO(MemoryOp op) {
@@ -946,19 +1004,23 @@ public final boolean isValueReferenceNeeded() {
* Enum (maps :foo => 1, :bar => 2, etc)
*/
static final class EnumFieldIO implements FieldIO {
- public static final FieldIO INSTANCE = new EnumFieldIO();
+ private final MemoryOp op;
+
+ public EnumFieldIO(ByteOrder order) {
+ this.op = MemoryOp.getMemoryOp(NativeType.INT, order);
+ }
+
public void put(ThreadContext context, StructLayout.Storage cache, Member m, IRubyObject ptr, IRubyObject value) {
// Upcall to ruby to convert :foo to an int, then write it out
- m.getMemoryIO(ptr).putInt(m.offset,
- RubyNumeric.num2int(m.type.callMethod(context, "find", value)));
+ op.put(context.getRuntime(), m.getMemoryIO(ptr), m.offset,
+ m.type.callMethod(context, "find", value));
}
public IRubyObject get(ThreadContext context, StructLayout.Storage cache, Member m, IRubyObject ptr) {
// Read an int from the native memory, then upcall to the ruby value
// lookup code to convert it to the appropriate symbol
- return m.type.callMethod(context, "find",
- context.getRuntime().newFixnum(m.getMemoryIO(ptr).getInt(m.offset)));
+ return m.type.callMethod(context, "find", op.get(context.getRuntime(), m.getMemoryIO(ptr), m.offset));
}
public final boolean isCacheable() {
View
251 src/org/jruby/ext/ffi/SwappedMemoryIO.java
@@ -0,0 +1,251 @@
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.jruby.ext.ffi;
+
+import java.nio.ByteOrder;
+import org.jruby.Ruby;
+
+/**
+ *
+ */
+public final class SwappedMemoryIO implements MemoryIO, DirectMemoryIO {
+ protected static final int LONG_SIZE = Platform.getPlatform().longSize();
+ protected static final int ADDRESS_SIZE = Platform.getPlatform().addressSize();
+
+ private final Ruby runtime;
+ private final MemoryIO io;
+
+ SwappedMemoryIO(Ruby runtime, MemoryIO io) {
+ this.runtime = runtime;
+ this.io = io;
+ }
+
+ public final ByteOrder order() {
+ return ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)
+ ? ByteOrder.LITTLE_ENDIAN : ByteOrder.BIG_ENDIAN;
+ }
+
+ public final long getAddress() {
+ return io instanceof DirectMemoryIO ? ((DirectMemoryIO) io).getAddress() : 0L;
+ }
+
+ public SwappedMemoryIO slice(long offset) {
+ return offset == 0 ? this : new SwappedMemoryIO(runtime, io.slice(offset));
+ }
+
+ public SwappedMemoryIO slice(long offset, long size) {
+ return new SwappedMemoryIO(runtime, io.slice(offset, size));
+ }
+
+ public final java.nio.ByteBuffer asByteBuffer() {
+ return io.asByteBuffer().order(order());
+ }
+
+ Ruby getRuntime() {
+ return this.runtime;
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ return obj == this || (obj instanceof SwappedMemoryIO) && ((SwappedMemoryIO) obj).io.equals(io);
+ }
+
+ @Override
+ public final int hashCode() {
+ return io.hashCode();
+ }
+
+ public final boolean isNull() {
+ return io.isNull();
+ }
+
+ public final boolean isDirect() {
+ return io.isDirect();
+ }
+
+ public final byte getByte(long offset) {
+ return io.getByte(offset);
+ }
+
+ public final short getShort(long offset) {
+ return Short.reverseBytes(io.getShort(offset));
+ }
+
+ public final int getInt(long offset) {
+ return Integer.reverseBytes(io.getInt(offset));
+ }
+
+ public final long getLong(long offset) {
+ return Long.reverseBytes(io.getLong(offset));
+ }
+
+ public final long getNativeLong(long offset) {
+ return LONG_SIZE == 32 ? getInt(offset) : getLong(offset);
+ }
+
+ public final float getFloat(long offset) {
+ return Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(io.getFloat(offset))));
+ }
+
+ public final double getDouble(long offset) {
+ return Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(io.getDouble(offset))));
+ }
+
+ public final long getAddress(long offset) {
+ throw runtime.newRuntimeError("cannot get native address values in non-native byte order memory");
+ }
+
+ public final DirectMemoryIO getMemoryIO(long offset) {
+ throw runtime.newRuntimeError("cannot get native address values in non-native byte order memory");
+ }
+
+ public final void putByte(long offset, byte value) {
+ io.putByte(offset, value);
+ }
+
+ public final void putShort(long offset, short value) {
+ io.putShort(offset, Short.reverseBytes(value));
+ }
+
+ public final void putInt(long offset, int value) {
+ io.putInt(offset, Integer.reverseBytes(value));
+ }
+
+ public final void putLong(long offset, long value) {
+ io.putLong(offset, Long.reverseBytes(value));
+ }
+
+ public final void putNativeLong(long offset, long value) {
+ if (LONG_SIZE == 32) {
+ putInt(offset, (int) value);
+ } else {
+ putLong(offset, value);
+ }
+ }
+ public final void putAddress(long offset, long value) {
+ throw runtime.newRuntimeError("cannot write native address values to non-native byte order memory");
+ }
+
+ public final void putFloat(long offset, float value) {
+ io.putFloat(offset, Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(value))));
+ }
+
+ public final void putDouble(long offset, double value) {
+ io.putDouble(offset, Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(value))));
+ }
+
+ public final void putMemoryIO(long offset, MemoryIO value) {
+ throw runtime.newRuntimeError("cannot write native address values to non-native byte order memory");
+ }
+
+ public final void get(long offset, byte[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ }
+
+ public final void put(long offset, byte[] src, int off, int len) {
+ io.put(offset, src, off, len);
+ }
+
+ public final void get(long offset, short[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ for (int i = 0; i < len; ++i) {
+ dst[off + i] = Short.reverseBytes(dst[off + i]);
+ }
+ }
+
+ public final void put(long offset, short[] src, int off, int len) {
+ short[] values = new short[len];
+ for (int i = 0; i < len; ++i) {
+ values[i] = Short.reverseBytes(src[off + i]);
+ }
+ io.put(offset, values, 0, len);
+ }
+
+ public final void get(long offset, int[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ for (int i = 0; i < len; ++i) {
+ dst[off + i] = Integer.reverseBytes(dst[off + i]);
+ }
+ }
+
+ public final void put(long offset, int[] src, int off, int len) {
+ int[] values = new int[len];
+ for (int i = 0; i < len; ++i) {
+ values[i] = Integer.reverseBytes(src[off + i]);
+ }
+ io.put(offset, values, 0, len);
+ }
+
+ public final void get(long offset, long[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ for (int i = 0; i < len; ++i) {
+ dst[off + i] = Long.reverseBytes(dst[off + i]);
+ }
+ }
+
+ public final void put(long offset, long[] src, int off, int len) {
+ long[] values = new long[len];
+ for (int i = 0; i < len; ++i) {
+ values[i] = Long.reverseBytes(src[off + i]);
+ }
+ io.put(offset, values, 0, len);
+ }
+
+ public final void get(long offset, float[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ for (int i = 0; i < len; ++i) {
+ dst[off + i] = Float.intBitsToFloat(Integer.reverseBytes(Float.floatToRawIntBits(dst[off + i])));
+ }
+ }
+
+ public final void put(long offset, float[] src, int off, int len) {
+ int[] values = new int[len];
+ for (int i = 0; i < len; ++i) {
+ values[i] = Integer.reverseBytes(Float.floatToRawIntBits(src[off + i]));
+ }
+ io.put(offset, values, 0, len);
+ }
+
+ public final void get(long offset, double[] dst, int off, int len) {
+ io.get(offset, dst, off, len);
+ for (int i = 0; i < len; ++i) {
+ dst[off + i] = Double.longBitsToDouble(Long.reverseBytes(Double.doubleToRawLongBits(dst[off + i])));
+ }
+ }
+
+ public final void put(long offset, double[] src, int off, int len) {
+ long[] values = new long[len];
+ for (int i = 0; i < len; ++i) {
+ values[i] = Long.reverseBytes(Double.doubleToRawLongBits(src[off + i]));
+ }
+ io.put(offset, values, 0, len);
+ }
+
+ public final int indexOf(long offset, byte value) {
+ return io.indexOf(offset, value);
+ }
+
+ public final int indexOf(long offset, byte value, int maxlen) {
+ return io.indexOf(offset, value, maxlen);
+ }
+
+ public final void setMemory(long offset, long size, byte value) {
+ io.setMemory(offset, size, value);
+ }
+
+ public final byte[] getZeroTerminatedByteArray(long offset) {
+ return io.getZeroTerminatedByteArray(offset);
+ }
+
+ public final byte[] getZeroTerminatedByteArray(long offset, int maxlen) {
+ return io.getZeroTerminatedByteArray(offset, maxlen);
+ }
+
+ public void putZeroTerminatedByteArray(long offset, byte[] bytes, int off, int len) {
+ io.putZeroTerminatedByteArray(offset, bytes, off, len);
+ }
+
+}
View
20 src/org/jruby/ext/ffi/Util.java
@@ -30,12 +30,14 @@
import java.math.BigInteger;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyBignum;
import org.jruby.RubyHash;
import org.jruby.RubyModule;
import org.jruby.RubyNumeric;
import org.jruby.RubyString;
+import org.jruby.RubySymbol;
import org.jruby.javasupport.JavaObject;
import org.jruby.javasupport.JavaUtil;
import org.jruby.runtime.ThreadContext;
@@ -206,4 +208,22 @@ public static final Type findType(ThreadContext context, IRubyObject name) {
final IRubyObject type = ((RubyHash) typeDefs).fastARef(name);
return type instanceof Type ? (Type) type : (Type) ffi.callMethod(context, "find_type", name);
}
+
+ public static ByteOrder parseByteOrder(Ruby runtime, IRubyObject byte_order) {
+ if (byte_order instanceof RubySymbol || byte_order instanceof RubyString) {
+ String orderName = byte_order.asJavaString();
+ if ("network".equals(orderName) || "big".equals(orderName)) {
+ return ByteOrder.BIG_ENDIAN;
+
+ } else if ("little".equals(orderName)) {
+ return ByteOrder.LITTLE_ENDIAN;
+
+ } else {
+ return ByteOrder.nativeOrder();
+ }
+
+ } else {
+ throw runtime.newTypeError(byte_order, runtime.getSymbol());
+ }
+ }
}
View
5 src/org/jruby/ext/ffi/jffi/BoundedNativeMemoryIO.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi.jffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.ext.ffi.DirectMemoryIO;
import org.jruby.ext.ffi.MemoryIO;
@@ -84,6 +85,10 @@ public final boolean isDirect() {
return true;
}
+ public final ByteOrder order() {
+ return ByteOrder.nativeOrder();
+ }
+
public final byte getByte(long offset) {
checkBounds(offset, 1);
return IO.getByte(address + offset);
View
5 src/org/jruby/ext/ffi/jffi/NativeMemoryIO.java
@@ -1,6 +1,7 @@
package org.jruby.ext.ffi.jffi;
+import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.ext.ffi.DirectMemoryIO;
import org.jruby.ext.ffi.MemoryIO;
@@ -66,6 +67,10 @@ public final boolean isDirect() {
return true;
}
+ public final ByteOrder order() {
+ return ByteOrder.nativeOrder();
+ }
+
public final byte getByte(long offset) {
return IO.getByte(address + offset);
}
View
5 test/testEnumerator.rb
@@ -174,4 +174,7 @@ def initialize(x, y, *z)
test_no_exception {
JRuby3492.new("foo", :each_byte)
-}
+}
+
+# JRUBY-5013: dup'ed Enumerator should be able to enumerate correctly
+test_no_exception { [].each.dup.to_a }

0 comments on commit ad3d2f0

Please sign in to comment.