Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: jruby/jruby
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 4f2ec9420742
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 12736d3ba29d
Choose a head ref
  • 11 commits
  • 11 files changed
  • 1 contributor

Commits on Jul 27, 2016

  1. Copy the full SHA
    8faec85 View commit details
  2. [test] that Java::void now returns correct Void.TYPE

    (due previous commit)
    kares committed Jul 27, 2016
    Copy the full SHA
    4cafd7b View commit details
  3. Copy the full SHA
    e77ae6e View commit details
  4. avoid reflected array-copy since its (still) slow + DRY out error map…

    …ping
    
    before:
    ```
                                         user     system      total        real
    control                          0.030000   0.000000   0.030000 (  0.030799)
    ary.to_java                      0.590000   0.010000   0.600000 (  0.596296)
    ary.to_java :object              0.580000   0.000000   0.580000 (  0.579356)
    ary.to_java java.lang.Integer    0.780000   0.000000   0.780000 (  0.752359)
    ary.to_java :int                 0.610000   0.000000   0.610000 (  0.602031)
    ary.to_java Java::int            0.670000   0.000000   0.670000 (  0.673567)
    ary.to_java :short               0.740000   0.000000   0.740000 (  0.641244)
    long_ary.to_java                 2.030000   0.000000   2.030000 (  1.605155)
    long_ary.to_java :int            1.530000   0.000000   1.530000 (  1.523951)
    long_ary.to_java Java::int       1.550000   0.000000   1.550000 (  1.547217)
    long_ary.to_java :short          1.610000   0.000000   1.610000 (  1.600562)
    
    ```
    
    after:
    ```
                                         user     system      total        real
    control                          0.030000   0.000000   0.030000 (  0.028998)
    ary.to_java                      0.150000   0.000000   0.150000 (  0.149893)
    ary.to_java :object              0.200000   0.000000   0.200000 (  0.199358)
    ary.to_java java.lang.Integer    0.390000   0.010000   0.400000 (  0.359931)
    ary.to_java :int                 0.200000   0.000000   0.200000 (  0.192432)
    ary.to_java Java::int            0.250000   0.000000   0.250000 (  0.247384)
    ary.to_java :short               0.940000   0.000000   0.940000 (  0.612951)
    long_ary.to_java                 0.440000   0.010000   0.450000 (  0.286344)
    long_ary.to_java :int            0.340000   0.000000   0.340000 (  0.329349)
    long_ary.to_java Java::int       0.330000   0.000000   0.330000 (  0.330533)
    long_ary.to_java :short          1.460000   0.000000   1.460000 (  1.454139)
    ```
    kares committed Jul 27, 2016
    Copy the full SHA
    ec7e985 View commit details
  5. one liner return piece

    kares committed Jul 27, 2016
    Copy the full SHA
    c30d1b1 View commit details
  6. Copy the full SHA
    975bda2 View commit details
  7. Copy the full SHA
    8fc7da6 View commit details
  8. Copy the full SHA
    f368201 View commit details
  9. Copy the full SHA
    cb1b2a3 View commit details
  10. Copy the full SHA
    7fc92ed View commit details
  11. Copy the full SHA
    12736d3 View commit details
28 changes: 24 additions & 4 deletions bench/java/bench_array_to_java.rb
Original file line number Diff line number Diff line change
@@ -5,9 +5,29 @@

TIMES.times do
Benchmark.bm(30) do |bm|
bm.report("control") {a = [1,2,3,4]; 100_000.times {a}}
bm.report("ary.to_java") {a = [1,2,3,4]; 100_000.times {a.to_java}}
bm.report("ary.to_java :object") {a = [1,2,3,4]; 100_000.times {a.to_java :object}}
bm.report("ary.to_java :string") {a = [1,2,3,4]; 100_000.times {a.to_s.to_java :string}}
bm.report("control") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary } }
bm.report("ary.to_java") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java } }
bm.report("ary.to_java :object") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java :object } }
bm.report("ary.to_java java.lang.Integer") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java java.lang.Integer } }
bm.report("ary.to_java :int") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java :int } }
bm.report("ary.to_java Java::int") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java Java::int } }
bm.report("ary.to_java :short") { ary = [1,2,3,4,5,6,7,8]; 1_000_000.times { ary.to_java :short } }

bm.report("long_ary.to_java") do
long_ary = (0..255).to_a
100_000.times { long_ary.to_java }
end
bm.report("long_ary.to_java :int") do
long_ary = (0..255).to_a
100_000.times { long_ary.to_java :int }
end
bm.report("long_ary.to_java Java::int") do
long_ary = (0..255).to_a
100_000.times { long_ary.to_java Java::int }
end
bm.report("long_ary.to_java :short") do
long_ary = (0..255).to_a
100_000.times { long_ary.to_java :short }
end
end
end
28 changes: 16 additions & 12 deletions core/src/main/java/org/jruby/java/addons/KernelJavaAddons.java
Original file line number Diff line number Diff line change
@@ -2,21 +2,19 @@

import org.jruby.Ruby;
import org.jruby.RubyArray;
import org.jruby.javasupport.*;
import org.jruby.RubyKernel;
import org.jruby.RubyModule;
import org.jruby.RubyString;
import org.jruby.RubySymbol;
import org.jruby.anno.JRubyMethod;
import org.jruby.java.proxies.ConcreteJavaProxy;
import org.jruby.java.proxies.JavaProxy;
import org.jruby.javasupport.Java;
import org.jruby.javasupport.JavaClass;
import org.jruby.runtime.Helpers;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.Visibility;
import org.jruby.runtime.builtin.IRubyObject;

public class KernelJavaAddons {

@JRubyMethod
public static IRubyObject to_java(ThreadContext context, final IRubyObject fromObject) {
if ( fromObject instanceof RubyArray ) {
@@ -31,8 +29,8 @@ public static IRubyObject to_java(ThreadContext context, final IRubyObject fromO
if ( type.isNil() ) return to_java(context, fromObject);

final Ruby runtime = context.runtime;
final JavaClass targetType = getTargetType(context, runtime, type);

final JavaClass targetType = getTargetType(context, runtime, type);
if ( fromObject instanceof RubyArray ) {
return targetType.javaArrayFromRubyArray(context, (RubyArray) fromObject);
}
@@ -85,11 +83,9 @@ private static JavaClass getTargetType(ThreadContext context, Ruby runtime, IRub
JavaClass targetType;

if (type instanceof RubyString || type instanceof RubySymbol) {
targetType = runtime.getJavaSupport().getNameClassMap().get(type.asJavaString());
if (targetType == null) targetType = JavaClass.forNameVerbose(runtime, type.asJavaString());
}
else if (type instanceof RubyModule && type.respondsTo("java_class")) {
targetType = (JavaClass) Helpers.invoke(context, type, "java_class");
final String className = type.toString();
targetType = runtime.getJavaSupport().getNameClassMap().get(className);
if ( targetType == null ) targetType = JavaClass.forNameVerbose(runtime, className);
}
else if (type instanceof JavaProxy) {
final Object wrapped = ((JavaProxy) type).getObject();
@@ -98,10 +94,18 @@ else if (type instanceof JavaProxy) {
} else {
throw runtime.newTypeError("not a valid target type: " + type);
}
} else {
}
else if (type instanceof JavaClass) {
return (JavaClass) type;
}
else if (type instanceof RubyModule && type.respondsTo("java_class")) {
targetType = (JavaClass) Helpers.invoke(context, type, "java_class");
}
else {
throw runtime.newTypeError("unable to convert to type: " + type);
}

return targetType;
}

}
7 changes: 5 additions & 2 deletions core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java
Original file line number Diff line number Diff line change
@@ -99,6 +99,10 @@ public void set(final int index, final Object value) {
Array.set(getObject(), index, value);
}

public IRubyObject setValue(final Ruby runtime, final int index, final IRubyObject value) {
return ArrayUtils.asetDirect(runtime, getObject(), converter, index, value);
}

@JRubyMethod(name = "[]", required = 1, rest = true)
public final IRubyObject op_aref(ThreadContext context, IRubyObject[] args) {
if ( args.length == 1 ) return op_aref(context, args[0]);
@@ -107,8 +111,7 @@ public final IRubyObject op_aref(ThreadContext context, IRubyObject[] args) {

@JRubyMethod(name = "[]=")
public final IRubyObject op_aset(ThreadContext context, IRubyObject index, IRubyObject value) {
final int i = convertArrayIndex(index);
return ArrayUtils.asetDirect(context.runtime, getObject(), converter, i, value);
return setValue(context.runtime, convertArrayIndex(index), value);
}

@JRubyMethod(name = "dig", required = 1, rest = true)
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@
public class ArrayJavaProxyCreator extends RubyObject {
private static final int[] EMPTY = new int[0];

/* final */ Class<?> elementType;
final Class<?> elementType;
int[] dimensions = EMPTY;

public static RubyClass createArrayJavaProxyCreator(ThreadContext context) {
@@ -37,18 +37,17 @@ public static RubyClass createArrayJavaProxyCreator(ThreadContext context) {
return arrayJavaProxyCreator;
}

@Deprecated
public ArrayJavaProxyCreator(final Ruby runtime) {
super(runtime, runtime.getJavaSupport().getArrayJavaProxyCreatorClass());
}

ArrayJavaProxyCreator(final ThreadContext context, JavaClass elementType, final IRubyObject[] sizes) {
this(context.runtime);
this.elementType = elementType.javaClass();
this(context.runtime, elementType.javaClass());
assert sizes.length > 0;
aggregateDimensions(sizes);
}

private ArrayJavaProxyCreator(final Ruby runtime, Class<?> elementType) {
super(runtime, runtime.getJavaSupport().getArrayJavaProxyCreatorClass());
this.elementType = elementType;
}

@JRubyMethod(name = "[]", required = 1, rest = true)
public final IRubyObject op_aref(ThreadContext context, IRubyObject[] sizes) {
Arity.checkArgumentCount(context.runtime, sizes, 1, -1);
183 changes: 121 additions & 62 deletions core/src/main/java/org/jruby/java/util/ArrayUtils.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
import org.jruby.RubyArray;
import org.jruby.RubyClass;
import org.jruby.RubyFixnum;
import org.jruby.exceptions.RaiseException;
import org.jruby.java.proxies.ArrayJavaProxy;
import org.jruby.javasupport.JavaArray;
import org.jruby.javasupport.JavaClass;
@@ -20,14 +21,11 @@ public class ArrayUtils {

private ArrayUtils() { /* no instances */ }

public static IRubyObject arefDirect(Ruby runtime, Object array, JavaUtil.JavaConverter javaConverter, int intIndex) {
public static IRubyObject arefDirect(Ruby runtime, Object array, JavaUtil.JavaConverter javaConverter, int index) {
try {
return JavaUtil.convertJavaArrayElementToRuby(runtime, javaConverter, array, intIndex);
} catch (IndexOutOfBoundsException e) {
throw runtime.newArgumentError(
"index out of bounds for java array (" + intIndex +
" for length " + Array.getLength(array) + ')');
return JavaUtil.convertJavaArrayElementToRuby(runtime, javaConverter, array, index);
}
catch (IndexOutOfBoundsException e) { throw mapIndexOutOfBoundsException(runtime, array, index); }
}

public static IRubyObject concatArraysDirect(ThreadContext context, Object original, Object additional) {
@@ -54,92 +52,153 @@ public static ArrayJavaProxy newProxiedArray(Ruby runtime, Class<?> componentTyp
}

public static IRubyObject emptyJavaArrayDirect(ThreadContext context, Class componentType) {
Ruby runtime = context.runtime;
return newProxiedArray(runtime, componentType, 0);
return newProxiedArray(context.runtime, componentType, 0);
}

public static IRubyObject javaArraySubarrayDirect(ThreadContext context, Object fromArray, int index, int size) {
int actualLength = Array.getLength(fromArray);
if (index >= actualLength) {
return context.runtime.getNil();
} else {
if (index + size > actualLength) {
size = actualLength - index;
}

ArrayJavaProxy proxy = ArrayUtils.newProxiedArray(context.runtime, fromArray.getClass().getComponentType(), size);
Object newArray = proxy.getObject();
System.arraycopy(fromArray, index, newArray, 0, size);

return proxy;
if (index >= actualLength) return context.nil;

if (index + size > actualLength) {
size = actualLength - index;
}

ArrayJavaProxy proxy = ArrayUtils.newProxiedArray(context.runtime, fromArray.getClass().getComponentType(), size);
Object newArray = proxy.getObject();
System.arraycopy(fromArray, index, newArray, 0, size);

return proxy;
}

public static IRubyObject concatArraysDirect(ThreadContext context, Object original, IRubyObject additional) {
Ruby runtime = context.runtime;
int oldLength = Array.getLength(original);
int addLength = (int)((RubyFixnum) Helpers.invoke(context, additional, "length")).getLongValue();
final Ruby runtime = context.runtime;
final int oldLength = Array.getLength(original);
final int addLength = RubyFixnum.fix2int(Helpers.invoke(context, additional, "length"));

ArrayJavaProxy proxy = ArrayUtils.newProxiedArray(runtime, original.getClass().getComponentType(), oldLength + addLength);
Object newArray = proxy.getObject();

System.arraycopy(original, 0, newArray, 0, oldLength);
System.arraycopy(original, 0, proxy.getObject(), 0, oldLength);

for (int i = 0; i < addLength; i++) {
Helpers.invoke(context, proxy, "[]=", runtime.newFixnum(oldLength + i),
Helpers.invoke(context, additional, "[]", runtime.newFixnum(i)));
IRubyObject val = Helpers.invoke(context, additional, "[]", runtime.newFixnum(i));
proxy.setValue(runtime, oldLength + i, val); // [ oldLen + i ] = val
}

return proxy;
}

public static IRubyObject asetDirect(Ruby runtime, Object array, JavaUtil.JavaConverter javaConverter, int intIndex, IRubyObject value) {
public static IRubyObject asetDirect(Ruby runtime, Object array, JavaUtil.JavaConverter javaConverter, int index, IRubyObject value) {
try {
javaConverter.set(runtime, array, intIndex, value);
} catch (IndexOutOfBoundsException e) {
throw runtime.newArgumentError(
"index out of bounds for java array (" + intIndex +
" for length " + Array.getLength(array) + ')');
} catch (ArrayStoreException e) {
throw runtime.newTypeError(
"wrong element type " + value.getClass() + "(array contains " +
array.getClass().getComponentType().getName() + ')');
} catch (IllegalArgumentException iae) {
throw runtime.newArgumentError(
"wrong element type " + value.getClass() + "(array contains " +
array.getClass().getComponentType().getName() + ')');
javaConverter.set(runtime, array, index, value);
}
catch (IndexOutOfBoundsException e) { throw mapIndexOutOfBoundsException(runtime, array, index); }
catch (ArrayStoreException e) { throw mapArrayStoreException(runtime, array, value.getClass()); }
catch (IllegalArgumentException e) { throw mapIllegalArgumentException(runtime, array, value.getClass()); }
return value;
}

public static void setWithExceptionHandlingDirect(Ruby runtime, Object ary, int intIndex, Object javaObject) {
public static void setWithExceptionHandlingDirect(Ruby runtime, Object array, int index, Object javaValue) {
try {
Array.set(ary, intIndex, javaObject);
} catch (IndexOutOfBoundsException e) {
throw runtime.newArgumentError(
"index out of bounds for java array (" + intIndex +
" for length " + Array.getLength(ary) + ')');
} catch (ArrayStoreException e) {
throw runtime.newTypeError(
"wrong element type " + javaObject.getClass() + "(array contains " +
ary.getClass().getComponentType().getName() + ')');
} catch (IllegalArgumentException iae) {
throw runtime.newArgumentError(
"wrong element type " + javaObject.getClass() + "(array contains " +
ary.getClass().getComponentType().getName() + ')');
Array.set(array, index, javaValue);
}
catch (IndexOutOfBoundsException e) { throw mapIndexOutOfBoundsException(runtime, array, index); }
catch (ArrayStoreException e) { throw mapArrayStoreException(runtime, array, javaValue.getClass()); }
catch (IllegalArgumentException e) { throw mapIllegalArgumentException(runtime, array, javaValue.getClass()); }
}

public static void copyDataToJavaArrayDirect(
ThreadContext context, RubyArray rubyArray, Object javaArray) {
int javaLength = Array.getLength(javaArray);
private static RaiseException mapIndexOutOfBoundsException(final Ruby runtime, final Object array, int index) {
return runtime.newArgumentError("index out of bounds for java array (" +
index + " for length " + Array.getLength(array) + ')');
}

private static RaiseException mapArrayStoreException(final Ruby runtime, final Object array, final Class<?> type) {
return runtime.newTypeError("wrong element type " + type.getName() + " (array contains " +
array.getClass().getComponentType().getName() + ')');
}

private static RaiseException mapIllegalArgumentException(final Ruby runtime, final Object array, final Class<?> type) {
return runtime.newArgumentError("wrong element type " + type.getName() + " (array contains " +
array.getClass().getComponentType().getName() + ')');
}

public static void copyDataToJavaArrayDirect(ThreadContext context,
final RubyArray rubyArray, final Object javaArray) {
Class targetType = javaArray.getClass().getComponentType();

int rubyLength = rubyArray.getLength();
// 'premature' optimizations as reflected Array.set is (still) noticeably slower
if ( ! targetType.isPrimitive() ) {
copyDataToJavaArrayDirect(targetType, rubyArray, (Object[]) javaArray); return;
}
else if ( Integer.TYPE == targetType ) {
copyDataToJavaArrayDirect(targetType, rubyArray, (int[]) javaArray); return;
}
else if ( Long.TYPE == targetType ) {
copyDataToJavaArrayDirect(targetType, rubyArray, (long[]) javaArray); return;
}
else if ( Byte.TYPE == targetType ) {
copyDataToJavaArrayDirect(targetType, rubyArray, (byte[]) javaArray); return;
}

int length = rubyArray.getLength();

final int javaLength = Array.getLength(javaArray);
if ( javaLength < length ) length = javaLength;

for ( int i = 0; i < length; i++ ) {
Array.set(javaArray, i, rubyArray.eltInternal(i).toJava(targetType));
}
}

//public static void copyDataToJavaArrayDirect(ThreadContext context,
// final RubyArray rubyArray, final Object[] javaArray) {
// copyDataToJavaArrayDirect(javaArray.getClass().getComponentType(), rubyArray, javaArray)
//}

private static void copyDataToJavaArrayDirect(final Class<?> targetType,
final RubyArray rubyArray, final Object[] javaArray) {
int length = rubyArray.getLength();

final int javaLength = javaArray.length;
if ( javaLength < length ) length = javaLength;

for ( int i = 0; i < length; i++ ) {
javaArray[i] = rubyArray.eltInternal(i).toJava(targetType);
}
}

private static void copyDataToJavaArrayDirect(final Class<?> targetType,
final RubyArray rubyArray, final int[] javaArray) {
int length = rubyArray.getLength();

final int javaLength = javaArray.length;
if ( javaLength < length ) length = javaLength;

for ( int i = 0; i < length; i++ ) {
javaArray[i] = (Integer) rubyArray.eltInternal(i).toJava(targetType);
}
}

private static void copyDataToJavaArrayDirect(final Class<?> targetType,
final RubyArray rubyArray, final long[] javaArray) {
int length = rubyArray.getLength();

final int javaLength = javaArray.length;
if ( javaLength < length ) length = javaLength;

for ( int i = 0; i < length; i++ ) {
javaArray[i] = (Long) rubyArray.eltInternal(i).toJava(targetType);
}
}

private static void copyDataToJavaArrayDirect(final Class<?> targetType,
final RubyArray rubyArray, final byte[] javaArray) {
int length = rubyArray.getLength();

final int javaLength = javaArray.length;
if ( javaLength < length ) length = javaLength;

int i = 0;
for (; i < rubyLength && i < javaLength; i++) {
Array.set(javaArray, i, rubyArray.entry(i).toJava(targetType));
for ( int i = 0; i < length; i++ ) {
javaArray[i] = (Byte) rubyArray.eltInternal(i).toJava(targetType);
}
}

Loading