Skip to content

Commit

Permalink
Showing 3 changed files with 43 additions and 27 deletions.
56 changes: 32 additions & 24 deletions core/src/main/java/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
@@ -54,6 +54,7 @@
import org.jruby.runtime.Signature;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.callsite.CachingCallSite;
import org.jruby.runtime.encoding.EncodingCapable;
import org.jruby.runtime.invokedynamic.MethodNames;
import org.jruby.runtime.marshal.MarshalStream;
@@ -4404,11 +4405,16 @@ final IRubyObject dig(ThreadContext context, IRubyObject[] args, int idx) {

private IRubyObject maxWithBlock(ThreadContext context, Block block) {
IRubyObject result = UNDEF;

Ruby runtime = context.runtime;
ArraySites sites = sites(context);
CallSite op_gt = sites.op_gt_minmax;
CallSite op_lt = sites.op_lt_minmax;

for (int i = 0; i < realLength; i++) {
IRubyObject v = eltOk(i);

if (result == UNDEF || RubyComparable.cmpint(context, block.yieldArray(context, runtime.newArray(v, result), null), v, result) > 0) {
if (result == UNDEF || RubyComparable.cmpint(context, op_gt, op_lt, block.yieldArray(context, runtime.newArray(v, result), null), v, result) > 0) {
result = v;
}
}
@@ -4421,13 +4427,15 @@ public IRubyObject max(ThreadContext context, Block block) {
if (block.isGiven()) return maxWithBlock(context, block);

IRubyObject result = UNDEF;
Invalidator invalidator = getTypeIdForCMP();
Object typeId = invalidator != null ? invalidator.getData() : null;
ArraySites sites = sites(context);
CachingCallSite op_cmp = sites.op_cmp_minmax;
CallSite op_gt = sites.op_gt_minmax;
CallSite op_lt = sites.op_lt_minmax;

for (int i = 0; i < realLength; i++) {
IRubyObject v = eltOk(i);

if (result == UNDEF || optimizedCmp(context, v, result, typeId, invalidator) > 0) {
if (result == UNDEF || optimizedCmp(context, v, result, op_cmp, op_gt, op_lt) > 0) {
result = v;
}
}
@@ -4448,10 +4456,14 @@ private IRubyObject minWithBlock(ThreadContext context, Block block) {
IRubyObject result = UNDEF;

Ruby runtime = context.runtime;
ArraySites sites = sites(context);
CallSite op_gt = sites.op_gt_minmax;
CallSite op_lt = sites.op_lt_minmax;

for (int i = 0; i < realLength; i++) {
IRubyObject v = eltOk(i);

if (result == UNDEF || RubyComparable.cmpint(context, block.yieldArray(context, runtime.newArray(v, result), null), v, result) < 0) {
if (result == UNDEF || RubyComparable.cmpint(context, op_gt, op_lt, block.yieldArray(context, runtime.newArray(v, result), null), v, result) < 0) {
result = v;
}
}
@@ -4464,28 +4476,22 @@ public IRubyObject min(ThreadContext context, Block block) {
if (block.isGiven()) return minWithBlock(context, block);

IRubyObject result = UNDEF;
Invalidator invalidator = getTypeIdForCMP();
Object typeId = invalidator != null ? invalidator.getData() : null;
ArraySites sites = sites(context);
CachingCallSite op_cmp = sites.op_cmp_minmax;
CallSite op_gt = sites.op_gt_minmax;
CallSite op_lt = sites.op_lt_minmax;

for (int i = 0; i < realLength; i++) {
IRubyObject v = eltOk(i);

if (result == UNDEF || optimizedCmp(context, v, result, typeId, invalidator) < 0) {
if (result == UNDEF || optimizedCmp(context, v, result, op_cmp, op_gt, op_lt) < 0) {
result = v;
}
}

return result == UNDEF ? context.nil : result;
}

private Invalidator getTypeIdForCMP() {
if (realLength <= 0) return null;

RubyModule meta = eltOk(0).getMetaClass();

return meta.isBuiltin(OP_CMP.realName()) ? meta.getInvalidator() : null;
}

@JRubyMethod(name = "min")
public IRubyObject min(ThreadContext context, IRubyObject num, Block block) {
if (!num.isNil()) {
@@ -4495,16 +4501,18 @@ public IRubyObject min(ThreadContext context, IRubyObject num, Block block) {
return min(context, block);
}

private static final int optimizedCmp(ThreadContext context, IRubyObject a, IRubyObject b, Object typeId, Invalidator invalidator) {
if (a instanceof RubyFixnum && b instanceof RubyFixnum && typeId == invalidator.getData()) {
long aLong = ((RubyFixnum)a).getLongValue();
long bLong = ((RubyFixnum)b).getLongValue();
return aLong > bLong ? 1 : aLong < bLong ? -1 : 0;
} else if (a instanceof RubyString && b instanceof RubyString && typeId == invalidator.getData()) {
return ((RubyString)a).op_cmp((RubyString)b);
private static final int optimizedCmp(ThreadContext context, IRubyObject a, IRubyObject b, CachingCallSite op_cmp, CallSite op_gt, CallSite op_lt) {
if (op_cmp.retrieveCache(a.getMetaClass()).method.isBuiltin()) {
if (a instanceof RubyFixnum && b instanceof RubyFixnum) {
long aLong = ((RubyFixnum) a).getLongValue();
long bLong = ((RubyFixnum) b).getLongValue();
return Long.compare(aLong, bLong);
} else if (a instanceof RubyString && b instanceof RubyString) {
return ((RubyString) a).op_cmp((RubyString) b);
}
}

return RubyComparable.cmpint(context, invokedynamic(context, a, OP_CMP, b), a, b);
return RubyComparable.cmpint(context, op_gt, op_lt, op_cmp.call(context, a, a, b), a, b);
}

@Override
11 changes: 8 additions & 3 deletions core/src/main/java/org/jruby/RubyComparable.java
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ public static RubyModule createComparable(Ruby runtime) {
/** rb_cmpint
*
*/
public static int cmpint(ThreadContext context, IRubyObject val, IRubyObject a, IRubyObject b) {
public static int cmpint(ThreadContext context, CallSite op_gt, CallSite op_lt, IRubyObject val, IRubyObject a, IRubyObject b) {
if (val == context.nil) cmperr(a, b);
if (val instanceof RubyFixnum) {
final int asInt = RubyNumeric.fix2int((RubyFixnum) val);
@@ -87,12 +87,17 @@ public static int cmpint(ThreadContext context, IRubyObject val, IRubyObject a,
RubyFixnum zero = RubyFixnum.zero(context.runtime);

ComparableSites sites = sites(context);
if (sites.op_gt.call(context, val, val, zero).isTrue()) return 1;
if (sites.op_lt.call(context, val, val, zero).isTrue()) return -1;
if (op_gt.call(context, val, val, zero).isTrue()) return 1;
if (op_lt.call(context, val, val, zero).isTrue()) return -1;

return 0;
}

public static int cmpint(ThreadContext context, IRubyObject val, IRubyObject a, IRubyObject b) {
ComparableSites sites = sites(context);
return cmpint(context, sites.op_gt, sites.op_lt, val, a, b);
}

/** rb_cmperr
*
*/
3 changes: 3 additions & 0 deletions core/src/main/java/org/jruby/runtime/JavaSites.java
Original file line number Diff line number Diff line change
@@ -83,6 +83,9 @@ public static class ArraySites {
public final RespondToCallSite respond_to_to_ary = new RespondToCallSite("to_ary");
public final CallSite to_ary = new FunctionalCachingCallSite("to_ary");
public final CallSite cmp = new FunctionalCachingCallSite("<=>");
public final CachingCallSite op_cmp_minmax = new FunctionalCachingCallSite("<=>");
public final CallSite op_gt_minmax = new FunctionalCachingCallSite(">");
public final CallSite op_lt_minmax = new FunctionalCachingCallSite("<");
}

public static class StringSites {

0 comments on commit 49bbe5e

Please sign in to comment.