Skip to content

Commit

Permalink
Showing 42 changed files with 1,180 additions and 280 deletions.
14 changes: 14 additions & 0 deletions ci.hocon
Original file line number Diff line number Diff line change
@@ -229,6 +229,12 @@ psd-benchmarks: {
] ${post-process-and-upload-results}
}

image-demo-benchmarks: {
run: ${setup-benchmarks} [
[mx, benchmark, image-demo]
] ${post-process-and-upload-results}
}

asciidoctor-benchmarks: {
run: ${setup-benchmarks} [
[mx, benchmark, asciidoctor]
@@ -420,6 +426,14 @@ builds: [
{name: ruby-benchmarks-psd-graal-enterprise-no-om} ${common} ${graal-enterprise-no-om} ${bench-caps} ${jruby-truffle} ${psd-benchmarks},
{name: ruby-benchmarks-psd-graal-vm} ${common} ${graal-vm} ${daily-bench-caps} ${jruby-truffle} ${psd-benchmarks},

//{name: ruby-benchmarks-image-demo-noindy} ${common} ${no-graal} ${daily-bench-caps} ${jruby-noindy-benchmark} ${image-demo-benchmarks},
//{name: ruby-benchmarks-image-demo-indy} ${common} ${no-graal} ${daily-bench-caps} ${jruby-indy-benchmark} ${image-demo-benchmarks},
{name: ruby-benchmarks-image-demo-no-graal} ${common} ${no-graal} ${weekly-bench-caps} ${jruby-truffle} ${image-demo-benchmarks},
{name: ruby-benchmarks-image-demo-graal-core} ${common} ${graal-core} ${bench-caps} ${jruby-truffle} ${image-demo-benchmarks},
{name: ruby-benchmarks-image-demo-graal-enterprise} ${common} ${graal-enterprise} ${bench-caps} ${jruby-truffle} ${image-demo-benchmarks},
{name: ruby-benchmarks-image-demo-graal-enterprise-no-om} ${common} ${graal-enterprise-no-om} ${bench-caps} ${jruby-truffle} ${image-demo-benchmarks},
{name: ruby-benchmarks-image-demo-graal-vm} ${common} ${graal-vm} ${daily-bench-caps} ${jruby-truffle} ${image-demo-benchmarks},

//{name: ruby-benchmarks-asciidoctor-noindy} ${common} ${no-graal} ${daily-bench-caps} ${jruby-noindy-benchmark} ${asciidoctor-benchmarks},
//{name: ruby-benchmarks-asciidoctor-indy} ${common} ${no-graal} ${daily-bench-caps} ${jruby-indy-benchmark} ${asciidoctor-benchmarks},
{name: ruby-benchmarks-asciidoctor-no-graal} ${common} ${no-graal} ${weekly-bench-caps} ${jruby-truffle} ${asciidoctor-benchmarks},
12 changes: 4 additions & 8 deletions core/src/main/java/org/jruby/RubyArray.java
Original file line number Diff line number Diff line change
@@ -265,10 +265,7 @@ public static RubyArray newArrayMayCopy(Ruby runtime, IRubyObject... args) {
case 2:
return new RubyArrayTwoObject(runtime, args[0], args[1]);
}
RubyArray arr = new RubyArray(runtime, new IRubyObject[args.length]);
System.arraycopy(args, 0, arr.values, 0, args.length);
arr.realLength = args.length;
return arr;
return newArrayNoCopy(runtime, args, 0, args.length);
}

/**
@@ -4032,7 +4029,7 @@ public IRubyObject shuffle(ThreadContext context, IRubyObject[] args) {
return ary;
}

private static int SORTED_THRESHOLD = 10;
private static final int SORTED_THRESHOLD = 10;

@JRubyMethod(name = "sample", optional = 2)
public IRubyObject sample(ThreadContext context, IRubyObject[] args) {
@@ -4107,8 +4104,7 @@ public IRubyObject sample(ThreadContext context, IRubyObject[] args) {
}
if (k >= l && (++k >= g))
++k;
return newArray(runtime, eltOk(i),
eltOk(j), eltOk(k));
return newArray(runtime, eltOk(i), eltOk(j), eltOk(k));
}

int len = realLength;
@@ -4141,7 +4137,7 @@ public IRubyObject sample(ThreadContext context, IRubyObject[] args) {
result[j] = result[i];
result[i] = tmp;
}
RubyArray ary = newArrayMayCopy(runtime, result);
RubyArray ary = newArrayNoCopy(runtime, result);
ary.realLength = n;
return ary;
}
133 changes: 96 additions & 37 deletions core/src/main/java/org/jruby/RubyEnumerable.java
Original file line number Diff line number Diff line change
@@ -143,6 +143,7 @@ private static void checkContext(ThreadContext firstContext, ThreadContext secon
}
}

@Deprecated
public static IRubyObject count18(ThreadContext context, IRubyObject self, final Block block) {
return count(context, self, block);
}
@@ -309,8 +310,13 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args) {
return result;
}

@JRubyMethod(name = "take_while")
@Deprecated
public static IRubyObject take_while19(ThreadContext context, IRubyObject self, final Block block) {
return take_while(context, self, block);
}

@JRubyMethod(name = "take_while")
public static IRubyObject take_while(ThreadContext context, IRubyObject self, final Block block) {
if (!block.isGiven()) {
return enumeratorize(context.runtime, self, "take_while");
}
@@ -434,25 +440,27 @@ public IRubyObject yield(ThreadContext context, IRubyObject[] args) {
return result;
}

@JRubyMethod(name = {"to_a", "entries"})
public static IRubyObject to_a(ThreadContext context, IRubyObject self) {
return to_a19(context, self);
@Deprecated
public static IRubyObject to_a19(ThreadContext context, IRubyObject self) {
return to_a(context, self);
}

@JRubyMethod(name = {"to_a", "entries"}, rest = true)
public static IRubyObject to_a(ThreadContext context, IRubyObject self, IRubyObject[] args) {
return to_a19(context, self, args);
@Deprecated
public static IRubyObject to_a19(ThreadContext context, IRubyObject self, IRubyObject[] args) {
return to_a(context, self, args);
}

public static IRubyObject to_a19(ThreadContext context, IRubyObject self) {
@JRubyMethod(name = {"to_a", "entries"})
public static IRubyObject to_a(ThreadContext context, IRubyObject self) {
Ruby runtime = context.runtime;
RubyArray result = runtime.newArray();
callEach(runtime, context, self, Signature.OPTIONAL, new AppendBlockCallback(result));
result.infectBy(self);
return result;
}

public static IRubyObject to_a19(ThreadContext context, IRubyObject self, IRubyObject[] args) {
@JRubyMethod(name = {"to_a", "entries"}, rest = true)
public static IRubyObject to_a(ThreadContext context, IRubyObject self, IRubyObject[] args) {
final Ruby runtime = context.runtime;
final RubyArray result = runtime.newArray();
Helpers.invoke(context, self, "each", args, CallBlock.newCallClosure(self, runtime.getEnumerable(),
@@ -647,11 +655,12 @@ public static IRubyObject find(ThreadContext context, IRubyObject self, IRubyObj
enumeratorize(context.runtime, self, "find", ifnone);
}

@JRubyMethod(name = "find_index")
@Deprecated
public static IRubyObject find_index19(ThreadContext context, IRubyObject self, final Block block) {
return find_index(context, self, block);
}

@JRubyMethod(name = "find_index")
public static IRubyObject find_index(ThreadContext context, IRubyObject self, final Block block) {
boolean blockGiven = block.isGiven();

@@ -661,7 +670,7 @@ public static IRubyObject find_index(ThreadContext context, IRubyObject self, fi
enumeratorize(context.runtime, self, "find_index");
}

@Deprecated
@Deprecated @SuppressWarnings("deprecation")
public static IRubyObject find_index(ThreadContext context, IRubyObject self, final Block block, Arity callbackArity) {
boolean blockGiven = block.isGiven();

@@ -671,11 +680,12 @@ public static IRubyObject find_index(ThreadContext context, IRubyObject self, fi
enumeratorize(context.runtime, self, "find_index");
}

@JRubyMethod(name = "find_index")
@Deprecated
public static IRubyObject find_index19(ThreadContext context, IRubyObject self, final IRubyObject cond, final Block block) {
return find_index(context, self, cond, block);
}

@JRubyMethod(name = "find_index")
public static IRubyObject find_index(ThreadContext context, IRubyObject self, final IRubyObject cond, final Block block) {
final Ruby runtime = context.runtime;

@@ -800,17 +810,27 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
return result;
}

@JRubyMethod(name = {"collect"})
@Deprecated
public static IRubyObject collect19(ThreadContext context, IRubyObject self, final Block block) {
return collectCommon19(context, self, block, "collect");
return collect(context, self, block);
}

@JRubyMethod(name = {"map"})
@Deprecated
public static IRubyObject map19(ThreadContext context, IRubyObject self, final Block block) {
return collectCommon19(context, self, block, "map");
return map(context, self, block);
}

@JRubyMethod(name = "collect")
public static IRubyObject collect(ThreadContext context, IRubyObject self, final Block block) {
return collectCommon(context, self, block, "collect");
}

@JRubyMethod(name = "map")
public static IRubyObject map(ThreadContext context, IRubyObject self, final Block block) {
return collectCommon(context, self, block, "map");
}

private static IRubyObject collectCommon19(ThreadContext context, IRubyObject self, final Block block, String methodName) {
private static IRubyObject collectCommon(ThreadContext context, IRubyObject self, final Block block, String methodName) {
final Ruby runtime = context.runtime;
if (block.isGiven()) {
final RubyArray result = runtime.newArray();
@@ -835,23 +855,34 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
}
}

@Deprecated
public static IRubyObject collectCommon(ThreadContext context, Ruby runtime, IRubyObject self,
RubyArray result, final Block block, BlockCallback blockCallback) {
callEach(runtime, context, self, Signature.ONE_ARGUMENT, blockCallback);
return result;
}

@JRubyMethod(name = {"flat_map"})
@Deprecated
public static IRubyObject flat_map19(ThreadContext context, IRubyObject self, final Block block) {
return flatMapCommon19(context, self, block, "flat_map");
return flat_map(context, self, block);
}

@JRubyMethod(name = {"collect_concat"})
@Deprecated
public static IRubyObject collect_concat19(ThreadContext context, IRubyObject self, final Block block) {
return flatMapCommon19(context, self, block, "collect_concat");
return collect_concat(context, self, block);
}

@JRubyMethod(name = "flat_map")
public static IRubyObject flat_map(ThreadContext context, IRubyObject self, final Block block) {
return flatMapCommon(context, self, block, "flat_map");
}

@JRubyMethod(name = "collect_concat")
public static IRubyObject collect_concat(ThreadContext context, IRubyObject self, final Block block) {
return flatMapCommon(context, self, block, "collect_concat");
}

private static IRubyObject flatMapCommon19(ThreadContext context, IRubyObject self, final Block block, String methodName) {
private static IRubyObject flatMapCommon(ThreadContext context, IRubyObject self, final Block block, String methodName) {
final Ruby runtime = context.runtime;
if (block.isGiven()) {
final RubyArray ary = runtime.newArray();
@@ -1002,12 +1033,22 @@ public static IRubyObject each_with_indexCommon(ThreadContext context, IRubyObje
return self;
}

public static IRubyObject each_with_indexCommon19(ThreadContext context, IRubyObject self, Block block, IRubyObject[] args) {
public static IRubyObject each_with_indexCommon(ThreadContext context, IRubyObject self, Block block, IRubyObject[] args) {
callEach(context.runtime, context, self, args, Signature.OPTIONAL, new EachWithIndex(block));
return self;
}

@Deprecated
public static IRubyObject each_with_indexCommon19(ThreadContext context, IRubyObject self, Block block, IRubyObject[] args) {
return each_with_indexCommon(context, self, block, args);
}

@Deprecated
public static IRubyObject each_with_objectCommon19(ThreadContext context, IRubyObject self, final Block block, final IRubyObject arg) {
return each_with_objectCommon(context, self, block, arg);
}

public static IRubyObject each_with_objectCommon(ThreadContext context, IRubyObject self, final Block block, final IRubyObject arg) {
final Ruby runtime = context.runtime;
RubyEnumerable.callEach(runtime, context, self, Signature.OPTIONAL, new BlockCallback() {
public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
@@ -1018,17 +1059,22 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
}

public static IRubyObject each_with_index(ThreadContext context, IRubyObject self, Block block) {
return each_with_index19(context, self, IRubyObject.NULL_ARRAY, block);
return each_with_index(context, self, IRubyObject.NULL_ARRAY, block);
}

@JRubyMethod(name = "each_with_index", rest = true)
public static IRubyObject each_with_index(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
return block.isGiven() ? each_with_indexCommon(context, self, block, args) : enumeratorizeWithSize(context, self, "each_with_index", args, enumSizeFn(context, self));
}

@Deprecated @SuppressWarnings("deprecation")
public static IRubyObject each_with_index19(ThreadContext context, IRubyObject self, IRubyObject[] args, Block block) {
return block.isGiven() ? each_with_indexCommon19(context, self, block, args) : enumeratorizeWithSize(context, self, "each_with_index", args, enumSizeFn(context, self));
return each_with_index19(context, self, args, block);
}

@JRubyMethod(required = 1)
public static IRubyObject each_with_object(ThreadContext context, IRubyObject self, IRubyObject arg, Block block) {
return block.isGiven() ? each_with_objectCommon19(context, self, block, arg) : enumeratorizeWithSize(context, self, "each_with_object", new IRubyObject[] { arg }, enumSizeFn(context, self));
return block.isGiven() ? each_with_objectCommon(context, self, block, arg) : enumeratorizeWithSize(context, self, "each_with_object", new IRubyObject[] { arg }, enumSizeFn(context, self));
}

@JRubyMethod(rest = true)
@@ -1045,7 +1091,18 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
return self;
}

@Deprecated
public static IRubyObject each_slice19(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
return each_slice(context, self, arg, block);
}

@JRubyMethod(name = "each_slice")
public static IRubyObject each_slice(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
return block.isGiven() ? each_sliceCommon(context, self, arg, block) :
enumeratorizeWithSize(context, self, "each_slice", new IRubyObject[]{arg}, eachSliceSizeFn(context, self));
}

static IRubyObject each_sliceCommon(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
final int size = RubyNumeric.num2int(arg);
final Ruby runtime = context.runtime;
if (size <= 0) throw runtime.newArgumentError("invalid slice size");
@@ -1067,11 +1124,6 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
return context.nil;
}

@JRubyMethod(name = "each_slice")
public static IRubyObject each_slice19(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
return block.isGiven() ? each_slice(context, self, arg, block) : enumeratorizeWithSize(context, self, "each_slice", new IRubyObject[]{arg}, eachSliceSizeFn(context, self));
}

private static SizeFn eachSliceSizeFn(final ThreadContext context, final IRubyObject self) {
return new SizeFn() {
@Override
@@ -1094,8 +1146,18 @@ public IRubyObject size(IRubyObject[] args) {
};
}

@Deprecated
public static IRubyObject each_cons19(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
return each_cons(context, self, arg, block);
}

@JRubyMethod(name = "each_cons")
public static IRubyObject each_cons(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
final int size = (int)RubyNumeric.num2long(arg);
return block.isGiven() ? each_consCommon(context, self, arg, block) : enumeratorizeWithSize(context, self, "each_cons", new IRubyObject[] { arg }, eachConsSizeFn(context, self));
}

static IRubyObject each_consCommon(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
final int size = (int) RubyNumeric.num2long(arg);
final Ruby runtime = context.runtime;
if (size <= 0) throw runtime.newArgumentError("invalid size");

@@ -1113,11 +1175,6 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
return context.nil;
}

@JRubyMethod(name = "each_cons")
public static IRubyObject each_cons19(ThreadContext context, IRubyObject self, IRubyObject arg, final Block block) {
return block.isGiven() ? each_cons(context, self, arg, block) : enumeratorizeWithSize(context, self, "each_cons", new IRubyObject[] { arg }, eachConsSizeFn(context, self));
}

private static SizeFn eachConsSizeFn(final ThreadContext context, final IRubyObject self) {
return new SizeFn() {
@Override
@@ -1477,6 +1534,7 @@ public IRubyObject call(ThreadContext ctx, IRubyObject[] largs, Block blk) {
return result[0] ? runtime.getTrue() : runtime.getFalse();
}

@Deprecated
public static IRubyObject one_p19(ThreadContext context, IRubyObject self, final Block block) {
return one_p(context, self, block);
}
@@ -1530,6 +1588,7 @@ public static IRubyObject all_p(ThreadContext context, IRubyObject self, final B
return all_pCommon(context, self, block);
}

@Deprecated
public static IRubyObject all_p19(ThreadContext context, IRubyObject self, final Block block) {
return all_p(context, self, block);
}
113 changes: 76 additions & 37 deletions core/src/main/java/org/jruby/RubyEnumerator.java
Original file line number Diff line number Diff line change
@@ -72,14 +72,14 @@ public class RubyEnumerator extends RubyObject {
private IRubyObject feedValue;

public static void defineEnumerator(Ruby runtime) {
RubyModule enm = runtime.getClassFromPath("Enumerable");
final RubyModule Enumerable = runtime.getModule("Enumerable");

final RubyClass enmr;
enmr = runtime.defineClass("Enumerator", runtime.getObject(), ENUMERATOR_ALLOCATOR);
final RubyClass Enumerator;
Enumerator = runtime.defineClass("Enumerator", runtime.getObject(), ENUMERATOR_ALLOCATOR);

enmr.includeModule(enm);
enmr.defineAnnotatedMethods(RubyEnumerator.class);
runtime.setEnumerator(enmr);
Enumerator.includeModule(Enumerable);
Enumerator.defineAnnotatedMethods(RubyEnumerator.class);
runtime.setEnumerator(Enumerator);

RubyGenerator.createGeneratorClass(runtime);
RubyYielder.createYielderClass(runtime);
@@ -100,12 +100,12 @@ private RubyEnumerator(Ruby runtime, RubyClass type) {

private RubyEnumerator(Ruby runtime, RubyClass type, IRubyObject object, IRubyObject method, IRubyObject[] args, IRubyObject size) {
super(runtime, type);
initialize20(runtime, object, method, args, size, null);
initialize(runtime, object, method, args, size, null);
}

private RubyEnumerator(Ruby runtime, RubyClass type, IRubyObject object, IRubyObject method, IRubyObject[] args, SizeFn sizeFn) {
super(runtime, type);
initialize20(runtime, object, method, args, null, sizeFn);
initialize(runtime, object, method, args, null, sizeFn);
}

private RubyEnumerator(Ruby runtime, RubyClass type, IRubyObject object, IRubyObject method, IRubyObject[] args) {
@@ -156,25 +156,36 @@ public static IRubyObject enumeratorize(Ruby runtime, RubyClass type, IRubyObjec

@Override
public IRubyObject initialize(ThreadContext context) {
return initialize20(context, Block.NULL_BLOCK);
return initialize(context, Block.NULL_BLOCK);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, Block block) {
return initialize(context, NULL_ARRAY, block);
}

@Deprecated
public IRubyObject initialize19(ThreadContext context, Block block) {
return initialize20(context, block);
return initialize(context, block);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE)
@Deprecated
public IRubyObject initialize20(ThreadContext context, Block block) {
return initialize20(context, NULL_ARRAY, block);
return initialize(context, block);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE)
public IRubyObject initialize(ThreadContext context, IRubyObject object, Block block) {
return initialize(context, new IRubyObject[]{ object }, block);
}

@Deprecated
public IRubyObject initialize20(ThreadContext context, IRubyObject object, Block block) {
return initialize20(context, new IRubyObject[]{ object }, block);
return initialize(context, object, block);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE, rest = true)
public IRubyObject initialize20(ThreadContext context, IRubyObject[] args, Block block) {
public IRubyObject initialize(ThreadContext context, IRubyObject[] args, Block block) {
Ruby runtime = context.runtime;
IRubyObject object;
IRubyObject method = runtime.newSymbol("each");
@@ -205,54 +216,72 @@ public IRubyObject initialize20(ThreadContext context, IRubyObject[] args, Block
}
}

return initialize20(runtime, object, method, args, size, null);
}

public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method) {
return initialize20(context, object, method, Block.NULL_BLOCK);
return initialize(runtime, object, method, args, size, null);
}

public IRubyObject initialize19(ThreadContext context, IRubyObject object, IRubyObject method, Block block) {
return initialize20(context, object, method, block);
@Deprecated
public IRubyObject initialize20(ThreadContext context, IRubyObject[] args, Block block) {
return initialize(context, args, block);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE)
public IRubyObject initialize20(ThreadContext context, IRubyObject object, IRubyObject method, Block block) {
public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method, Block block) {
if (block.isGiven()) {
throw context.runtime.newArgumentError(2, 1);
}
return initialize(context.runtime, object, method, NULL_ARRAY);
}

public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg) {
return initialize20(context, object, method, methodArg, Block.NULL_BLOCK);
public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method) {
return initialize(context, object, method, Block.NULL_BLOCK);
}

public IRubyObject initialize19(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg, Block block) {
return initialize20(context, object, method, methodArg, Block.NULL_BLOCK);
@Deprecated
public IRubyObject initialize19(ThreadContext context, IRubyObject object, IRubyObject method, Block block) {
return initialize(context, object, method, block);
}

@Deprecated
public IRubyObject initialize20(ThreadContext context, IRubyObject object, IRubyObject method, Block block) {
return initialize(context, object, method, block);
}

@JRubyMethod(name = "initialize", visibility = PRIVATE)
public IRubyObject initialize20(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg, Block block) {
public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg, Block block) {
if (block.isGiven()) {
throw context.runtime.newArgumentError(3, 1);
}
return initialize(context.runtime, object, method, new IRubyObject[] { methodArg });
}

public IRubyObject initialize(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg) {
return initialize(context, object, method, methodArg, Block.NULL_BLOCK);
}

@Deprecated
public IRubyObject initialize19(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg, Block block) {
return initialize(context, object, method, methodArg, Block.NULL_BLOCK);
}

@Deprecated
public IRubyObject initialize20(ThreadContext context, IRubyObject object, IRubyObject method, IRubyObject methodArg, Block block) {
return initialize(context, object, method, methodArg, block);
}

public IRubyObject initialize(ThreadContext context, IRubyObject[] args) {
return initialize20(context, args, Block.NULL_BLOCK);
return initialize(context, args, Block.NULL_BLOCK);
}

@Deprecated
public IRubyObject initialize19(ThreadContext context, IRubyObject[] args, Block block) {
return initialize20(context, args, block);
return initialize(context, args, block);
}

private IRubyObject initialize(Ruby runtime, IRubyObject object, IRubyObject method, IRubyObject[] methodArgs) {
return initialize20(runtime, object, method, methodArgs, null, null);
return initialize(runtime, object, method, methodArgs, null, null);
}

private IRubyObject initialize20(Ruby runtime, IRubyObject object, IRubyObject method, IRubyObject[] methodArgs, IRubyObject size, SizeFn sizeFn) {
private IRubyObject initialize(Ruby runtime, IRubyObject object, IRubyObject method, IRubyObject[] methodArgs, IRubyObject size, SizeFn sizeFn) {
this.object = object;
this.method = method.asJavaString();
this.methodArgs = methodArgs;
@@ -370,28 +399,38 @@ protected static IRubyObject newEnumerator(ThreadContext context, IRubyObject ar

@JRubyMethod(required = 1)
public IRubyObject each_with_object(final ThreadContext context, IRubyObject arg, Block block) {
return block.isGiven() ? RubyEnumerable.each_with_objectCommon19(context, this, block, arg) :
return block.isGiven() ? RubyEnumerable.each_with_objectCommon(context, this, block, arg) :
enumeratorizeWithSize(context, this, "each_with_object", new IRubyObject[]{arg}, enumSizeFn(context));
}

@JRubyMethod
public IRubyObject with_object(ThreadContext context, final IRubyObject arg, final Block block) {
return block.isGiven() ? RubyEnumerable.each_with_objectCommon19(context, this, block, arg) : enumeratorizeWithSize(context, this, "with_object", new IRubyObject[]{arg}, enumSizeFn(context));
return block.isGiven() ? RubyEnumerable.each_with_objectCommon(context, this, block, arg) : enumeratorizeWithSize(context, this, "with_object", new IRubyObject[]{arg}, enumSizeFn(context));
}

@JRubyMethod(rest = true)
public IRubyObject each_entry(ThreadContext context, final IRubyObject[] args, final Block block) {
return block.isGiven() ? RubyEnumerable.each_entryCommon(context, this, args, block) : enumeratorize(context.runtime, getType(), this, "each_entry", args);
}

@JRubyMethod(name = "each_slice")
@Deprecated
public IRubyObject each_slice19(ThreadContext context, IRubyObject arg, final Block block) {
return block.isGiven() ? RubyEnumerable.each_slice(context, this, arg, block) : enumeratorize(context.runtime, getType(), this, "each_slice", arg);
return each_slice(context, arg, block);
}

@JRubyMethod(name = "each_cons")
@JRubyMethod(name = "each_slice")
public IRubyObject each_slice(ThreadContext context, IRubyObject arg, final Block block) {
return block.isGiven() ? RubyEnumerable.each_sliceCommon(context, this, arg, block) : enumeratorize(context.runtime, getType(), this, "each_slice", arg);
}

@Deprecated
public IRubyObject each_cons19(ThreadContext context, IRubyObject arg, final Block block) {
return block.isGiven() ? RubyEnumerable.each_cons(context, this, arg, block) : enumeratorize(context.runtime, getType(), this, "each_cons", arg);
return each_cons(context, arg, block);
}

@JRubyMethod(name = "each_cons")
public IRubyObject each_cons(ThreadContext context, IRubyObject arg, final Block block) {
return block.isGiven() ? RubyEnumerable.each_consCommon(context, this, arg, block) : enumeratorize(context.runtime, getType(), this, "each_cons", arg);
}

@JRubyMethod
2 changes: 1 addition & 1 deletion core/src/main/java/org/jruby/RubyObject.java
Original file line number Diff line number Diff line change
@@ -466,7 +466,7 @@ public IRubyObject op_eqq(ThreadContext context, IRubyObject other) {
* Helper method for checking equality, first using Java identity
* equality, and then calling the "==" method.
*/
protected static boolean equalInternal(final ThreadContext context, final IRubyObject a, final IRubyObject b){
public static boolean equalInternal(final ThreadContext context, final IRubyObject a, final IRubyObject b){
if (a == b) {
return true;
} else if (a instanceof RubySymbol) {
34 changes: 0 additions & 34 deletions core/src/main/java/org/jruby/demo/ext/MethodMissing.java

This file was deleted.

355 changes: 328 additions & 27 deletions core/src/main/java/org/jruby/java/proxies/ArrayJavaProxy.java

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions core/src/main/java/org/jruby/javasupport/JavaClass.java
Original file line number Diff line number Diff line change
@@ -140,16 +140,16 @@ static RubyClass createJavaClassClass(final Ruby runtime, final RubyModule Java,
// JavaClass? Do we want them to do that? Can you Class.new(JavaClass)? Should you be able to?
// NOTE: NOT_ALLOCATABLE_ALLOCATOR is probably OK here, since we don't intend for people to monkey with
// this type and it can't be marshalled. Confirm. JRUBY-415
RubyClass JavaCLass = Java.defineClassUnder("JavaClass", JavaObject, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
RubyClass JavaClass = Java.defineClassUnder("JavaClass", JavaObject, ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);

JavaCLass.includeModule(runtime.getModule("Comparable"));
JavaClass.includeModule(runtime.getModule("Comparable"));

JavaCLass.defineAnnotatedMethods(JavaClass.class);
JavaClass.defineAnnotatedMethods(JavaClass.class);

JavaCLass.getMetaClass().undefineMethod("new");
JavaCLass.getMetaClass().undefineMethod("allocate");
JavaClass.getMetaClass().undefineMethod("new");
JavaClass.getMetaClass().undefineMethod("allocate");

return JavaCLass;
return JavaClass;
}

public final Class javaClass() {
@@ -182,7 +182,7 @@ public static JavaClass forNameVerbose(Ruby runtime, String className) {
Class<?> klass = null; // "boolean".length() == 7
if (className.length() < 8 && Character.isLowerCase(className.charAt(0))) {
// one word type name that starts lower-case...it may be a primitive type
klass = JavaUtil.PRIMITIVE_CLASSES.get(className);
klass = JavaUtil.getPrimitiveClass(className);
}
synchronized (JavaClass.class) {
if (klass == null) {
42 changes: 39 additions & 3 deletions core/src/main/java/org/jruby/javasupport/ext/JavaLang.java
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ public static IRubyObject each(final ThreadContext context, final IRubyObject se
final Object value = iterator.next();
block.yield(context, convertJavaToUsableRubyObject(runtime, value));
}
return context.nil;
return self;
}

@JRubyMethod
@@ -114,10 +114,10 @@ public static IRubyObject each_with_index(final ThreadContext context, final IRu
block.yield(context, RubyArray.newArray(runtime, rValue, index));
}
}
return context.nil;
return self;
}

@JRubyMethod(name = { "to_a", "entries" })
@JRubyMethod(name = { "to_a", "entries" }) // @override Enumerable#to_a
public static IRubyObject to_a(final ThreadContext context, final IRubyObject self, final Block block) {
final Ruby runtime = context.runtime;
final RubyArray ary = runtime.newArray();
@@ -130,6 +130,42 @@ public static IRubyObject to_a(final ThreadContext context, final IRubyObject se
return ary;
}

@JRubyMethod(name = "count") // @override Enumerable#count
public static IRubyObject count(final ThreadContext context, final IRubyObject self, final Block block) {
final Ruby runtime = context.runtime;
java.lang.Iterable iterable = unwrapJavaObject(self);
if ( block.isGiven() ) {
return countBlock(context, iterable.iterator(), block);
}
if ( iterable instanceof java.util.Collection ) {
return RubyFixnum.newFixnum(runtime, ((java.util.Collection) iterable).size());
}
int count = 0;
for( java.util.Iterator it = iterable.iterator(); it.hasNext(); ) { it.next(); count++; }
return RubyFixnum.newFixnum(runtime, count);
}

static RubyFixnum countBlock(final ThreadContext context, final java.util.Iterator it, final Block block) {
final Ruby runtime = context.runtime;
int count = 0; while ( it.hasNext() ) {
IRubyObject next = convertJavaToUsableRubyObject( runtime, it.next() );
if ( block.yield( context, next ).isTrue() ) count++;
}
return RubyFixnum.newFixnum(runtime, count);
}

@JRubyMethod(name = "count") // @override Enumerable#count
public static IRubyObject count(final ThreadContext context, final IRubyObject self, final IRubyObject obj, final Block unused) {
// unused block due DescriptorInfo not (yet) supporting if a method receives block and an override doesn't
final Ruby runtime = context.runtime;
java.lang.Iterable iterable = unwrapJavaObject(self);
int count = 0; for ( java.util.Iterator it = iterable.iterator(); it.hasNext(); ) {
IRubyObject next = convertJavaToUsableRubyObject( runtime, it.next() );
if ( RubyObject.equalInternal(context, next, obj) ) count++;
}
return RubyFixnum.newFixnum(runtime, count);
}

}

@JRubyClass(name = "Java::JavaLang::Comparable", include = "Comparable")
16 changes: 16 additions & 0 deletions core/src/main/java/org/jruby/javasupport/ext/JavaUtil.java
Original file line number Diff line number Diff line change
@@ -180,6 +180,22 @@ public static RubyArray to_a(final ThreadContext context, final IRubyObject self
return RubyArray.newArrayNoCopy(context.runtime, convertJavaArrayToRuby(context.runtime, array));
}

/*
@JRubyMethod(name = "count") // @override Enumerable#count
public IRubyObject count(final ThreadContext context, final IRubyObject self, final Block block) {
final Ruby runtime = context.runtime;
final java.util.Collection coll = unwrapJavaObject(self);
if ( block.isGiven() ) {
return JavaLang.Iterable.countBlock(context, coll.iterator(), block);
}
return RubyFixnum.newFixnum(runtime, coll.size());
}
@JRubyMethod(name = "count") // @override Enumerable#count
public static IRubyObject count(final ThreadContext context, final IRubyObject self, final IRubyObject obj, final Block unused) {
return JavaLang.Iterable.count(context, self, obj, Block.NULL_BLOCK);
} */

@JRubyMethod(name = "+", required = 1)
public static IRubyObject op_plus(final ThreadContext context, final IRubyObject self, final IRubyObject coll) {
final IRubyObject dup = self.callMethod(context, "dup");
17 changes: 17 additions & 0 deletions core/src/main/ruby/jruby/java/java_ext/java.lang.rb
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ module Java::java::lang::Iterable
include ::Enumerable

# Ruby style `Enumerable#each` iteration for Java iterable types.
# @return [Java::java::util::Iterable] self (since 9.1.3)
# @return [Enumerator] if called without a block to yield to
def each(&block)
# stub implemented in org.jruby.javasupport.ext.JavaLang.java
@@ -53,6 +54,7 @@ def each(&block)
end

# Ruby style `Enumerable#each_with_index` for Java iterable types.
# @return [Java::java::util::Iterable] self (since 9.1.3)
# @return [Enumerator] if called without a block to yield to
def each_with_index(&block)
# stub implemented in org.jruby.javasupport.ext.JavaLang.java
@@ -63,6 +65,21 @@ def each_with_index(&block)
# index += 1
# end
end

# Re-defined `Enumerable#to_a`.
# @return [Array]
# @since 9.1.3
def to_a
# stub implemented in org.jruby.javasupport.ext.JavaLang.java
end
alias entries to_a

# Re-defined `Enumerable#count`.
# @return [Integer] matched elements count
# @since 9.1.3
def count(obj = nil, &block)
# stub implemented in org.jruby.javasupport.ext.JavaLang.java
end
end if false

# *java.lang.Comparable* mixes in Ruby's `Comparable` support.
4 changes: 3 additions & 1 deletion core/src/main/ruby/jruby/java/java_ext/java.util.rb
Original file line number Diff line number Diff line change
@@ -20,7 +20,7 @@ def each_with_index(&block)
end

# Re-implemented for efficiency, so that we do not (`#each`) loop over the collection
# for types where its not necessary (e.g. *java.util.Set* instances), using (native) `contains`.
# for types where its not necessary (e.g. *java.util.Set* instances), uses (native) `java.util.Collection#contains`.
# @see Java::java::lang::Iterable#include?
# @return [true, false]
# @since 9.1.3
@@ -92,6 +92,8 @@ def join(*args)
def to_a
# stub implemented in org.jruby.javasupport.ext.JavaUtil.java
end
# @since 9.1.3
alias entries to_a

# Return a dup-ed collection (if possible).
# @example
21 changes: 21 additions & 0 deletions mx.jruby/mx_jruby.py
Original file line number Diff line number Diff line change
@@ -589,6 +589,26 @@ def benchmarks(self):
def time(self):
return psd_benchmark_time

image_demo_benchmarks = [
'image-demo-conv',
'image-demo-sobel',
]

image_demo_benchmark_time = 120

class ImageDemoBenchmarkSuite(AllBenchmarksBenchmarkSuite):
def name(self):
return 'image-demo'

def directory(self):
return 'image-demo'

def benchmarks(self):
return image_demo_benchmarks

def time(self):
return image_demo_benchmark_time

asciidoctor_benchmarks = [
'asciidoctor:file-lines',
'asciidoctor:string-lines',
@@ -715,6 +735,7 @@ def runBenchmark(self, benchmark, bmSuiteArgs):
mx_benchmark.add_bm_suite(ClassicBenchmarkSuite())
mx_benchmark.add_bm_suite(ChunkyBenchmarkSuite())
mx_benchmark.add_bm_suite(PSDBenchmarkSuite())
mx_benchmark.add_bm_suite(ImageDemoBenchmarkSuite())
mx_benchmark.add_bm_suite(AsciidoctorBenchmarkSuite())
mx_benchmark.add_bm_suite(SyntheticBenchmarkSuite())
mx_benchmark.add_bm_suite(MicroBenchmarkSuite())
18 changes: 16 additions & 2 deletions spec/java_integration/extensions/collection_spec.rb
Original file line number Diff line number Diff line change
@@ -13,8 +13,9 @@
expect(data).to eq @data

data = []
java.util.concurrent.LinkedBlockingQueue.new(@data).each { |elem| data << elem }
ret = java.util.concurrent.LinkedBlockingQueue.new(@data).each { |elem| data << elem }
expect(data).to eq @data
expect(ret).to be_a java.util.concurrent.LinkedBlockingQueue
end

it 'iterates with an Enumerator on #each' do
@@ -30,9 +31,10 @@
set = java.util.LinkedHashSet.new
@data.each { |elem| set.add elem }
data = []; idx = []
set.each_with_index { |elem, i| data << elem; idx << i }
ret = set.each_with_index { |elem, i| data << elem; idx << i }
expect(data).to eq @data
expect(idx).to eq [0, 1, 2, 3]
expect(ret).to be set

data = []
java.util.concurrent.LinkedBlockingQueue.new.each_with_index { |elem| data << elem }
@@ -192,6 +194,18 @@
expect( set.contains 3.to_java(:short) ).to be true
end

it 'counts' do
vec = java.util.Vector.new [1, 2, 2, 3, 2, 4, 2, 5, 2]
expect( vec.count ).to eql 9
expect( java.util.Collections::EMPTY_SET.count ).to eql 0

expect( vec.count { |i| i > 2 } ).to eq 3
expect( vec.count(2) ).to eq 5

expect( java.util.HashSet.new(vec).count(2) ).to eq 1
expect( java.util.LinkedHashSet.new(vec).count(0) ).to eq 0
end

it "should respect to_ary objects defined on iteration" do
class Pair
def initialize(a, b)
35 changes: 32 additions & 3 deletions spec/java_integration/extensions/iterable_spec.rb
Original file line number Diff line number Diff line change
@@ -8,9 +8,10 @@
file_system = java.nio.file.FileSystems.getDefault
path = file_system.getPath(__FILE__)
paths = []
path.each { |p| paths << p.to_s }
ret = path.each { |p| paths << p.to_s }
expect( paths ).to_not be_empty
expect( paths.last ).to eq 'iterable_spec.rb'
expect( ret ).to eq path
end

it 'iterates with an Enumerator on #each' do
@@ -23,11 +24,19 @@
it 'iterates using #each_with_index' do
file_system = java.nio.file.FileSystems.getDefault
path = file_system.getPath(__FILE__)
paths = []; idxs = []
path.each_with_index { |p| paths << p }
paths = []
ret = path.each_with_index { |p| paths << p }
expect( paths ).to_not be_empty
expect( paths[-1][0].to_s ).to eq 'iterable_spec.rb'
expect( paths[-1][1] ).to eq paths.size - 1
expect( ret ).to eq path

paths = []; idxs = []
ret = path.each_with_index { |p, i| paths << p; idxs << i }
expect( paths ).to_not be_empty
expect( paths[-1].to_s ).to eq 'iterable_spec.rb'
expect( idxs[0] ).to eq 0
expect( idxs[-1] ).to eq paths.size - 1
end

it 'iterates with an Enumerator on #each_with_index' do
@@ -54,6 +63,26 @@
expect( path.to_a ).to eql iterate_path(path)
end

it 'counts' do
file_system = java.nio.file.FileSystems.getDefault
path = file_system.getPath(__FILE__)
expect( path.count ).to eq iterate_path(path).size

expect( path.count { |p| p.to_s == 'iterable_spec.rb' } ).to eq 1
a_path = iterate_path(path).last

path = file_system.getPath(__FILE__)
expect( path.count(nil) ).to eq 0
expect( path.count(a_path) ).to eq 1
end

it 'converts #to_a' do
file_system = java.nio.file.FileSystems.getDefault
path = file_system.getPath(__FILE__)
expect( path.to_a ).to_not be_empty
expect( path.to_a ).to eql iterate_path(path)
end

private

def iterate_path(path)
191 changes: 186 additions & 5 deletions spec/java_integration/types/array_spec.rb
Original file line number Diff line number Diff line change
@@ -52,14 +52,14 @@
expect(arr[0]).to be_falsey
expect(arr[1]).to be_falsey
expect(arr[2]).to be_falsey
expect(arr[3]).to be_truthy
expect(arr[4]).to be_falsey
expect(arr[3]).to be true
expect(arr[4]).to be false
end

it "should be possible to get values from primitive array" do
arr = [false, true, false].to_java :boolean
expect(arr[0]).to be_falsey
expect(arr[1]).to be_truthy
expect(arr[0]).to be false
expect(arr[1]).to be true
expect(arr[2]).to be_falsey
end

@@ -180,6 +180,24 @@
expect([86, 87].to_java(:byte).to_s).to eq("VW")
end

it "detects element using include?" do
arr = Java::byte[3].new
arr[0] = 1
arr[1] = 127
arr[2] = -128

expect(arr.include?(1)).to be true
expect(arr.include?(0)).to be false
expect(arr.include?(10000)).to be false
expect(arr.include?(127)).to be true
expect(arr.include?(-128)).to be true
expect(arr.include?(-127)).to be false
expect(arr.include?(-1)).to be false
expect(arr.include?(-200)).to be false
expect(arr.include?(nil)).to be false
expect(arr.include?('x')).to be false
end

it "clones" do
arr = Java::byte[10].new
arr[1] = 1
@@ -283,6 +301,21 @@
arr = [100, 101, 102].to_java :char
expect(arr.to_s).to match(/\[C@[0-9a-f]+$/)
end

it "detects element using include?" do
arr = Java::char[3].new
arr[0] = 1
arr[1] = 0
arr[2] = 64

expect(arr.include?(1)).to be true
expect(arr.include?(0)).to be true
expect(arr.include?(10)).to be false
expect(arr.include?(64)).to be true
expect(arr.include?(-128)).to be false
expect(arr.include?(-1)).to be false
expect(arr.include?('z')).to be false
end
end

describe "double" do
@@ -371,6 +404,22 @@
arr = [1.0, 1.1, 1.2].to_java :double
expect(arr.inspect).to match(/^double\[1\.0, 1\.1, 1\.2\]@[0-9a-f]+$/)
end

it "detects element using include?" do
arr = Java::double[3].new
arr[0] = 111
arr[1] = 0.001
arr[2] = -1234560000.789

expect(arr.include?(111)).to be true
expect(arr.include?(111.1)).to be false
expect(arr.include?(0.0011)).to be false
expect(arr.include?(0.001)).to be true
expect(arr.include?(-1234560000.789)).to be true
expect(arr.include?(-1234560000.79)).to be false
expect(arr.include?(nil)).to be false
expect(arr.include?('x')).to be false
end
end

describe "float" do
@@ -468,6 +517,23 @@
arr = [1.0, 1.1, 1.2].to_java :float
expect(arr.inspect).to match(/^float\[1\.0, 1\.1, 1\.2\]@[0-9a-f]+$/)
end

it "detects element using include?" do
arr = Java::float[3].new
arr[0] = 111
arr[1] = 0.001
arr[2] = -123456.789

expect(arr.include?(111)).to be true
expect(arr.include?(111.1)).to be false
expect(arr.include?(0.0011)).to be false
expect(arr.include?(0.001)).to be true
expect(arr.include?(-123456.789)).to be true
# expect(arr.include?(-123456.79)).to be false
expect(arr.include?(-123456.8)).to be false
expect(arr.include?(nil)).to be false
expect(arr.include?('x')).to be false
end
end

describe "int" do
@@ -560,6 +626,25 @@
arr = [13, 42, 120].to_java :int
expect(arr.inspect).to match(/^int\[13, 42, 120\]@[0-9a-f]+$/)
end

it "detects element using include?" do
arr = Java::int[8].new
arr[0] = -1
arr[1] = 22
arr[3] = 2147483647
arr[6] = -111111111

expect(arr.include?(0)).to be true
expect(arr.include?(1)).to be false
expect(arr.include?(22)).to be true
expect(arr.include?(-111111111)).to be true
expect(arr.include?(-1111111111111)).to be false
expect(arr.include?(2147483648)).to be false
expect(arr.include?(2147483646)).to be false
expect(arr.include?(2147483647)).to be true
expect(arr.include?(nil)).to be false
expect(arr.include?('x')).to be false
end
end

describe "long" do
@@ -656,6 +741,24 @@
dup[1] = 11
expect(arr[1]).to eq(1)
end

it "detects element using include?" do
arr = Java::long[8].new
arr[0] = -1
arr[1] = 22
arr[3] = 2147483647000
arr[6] = -111111111000

expect(arr.include?(0)).to be true
expect(arr.include?(1)).to be false
expect(arr.include?(22)).to be true
expect(arr.include?(-111111111)).to be false
expect(arr.include?(-111111111000)).to be true
expect(arr.include?(2147483647001)).to be false
expect(arr.include?(2147483647000)).to be true
expect(arr.include?(nil)).to be false
expect(arr.include?('x')).to be false
end
end

describe "short" do
@@ -1084,7 +1187,7 @@ def blah()

it "to_a coerces nested Java arrays to Ruby arrays" do
arr = [[1],[2]].to_java(Java::byte[]).to_a
expect(arr.first).to eq([1])
expect(arr.first).to eql [1]
expect(arr.first.first).to be_kind_of(Fixnum)
end

@@ -1093,6 +1196,11 @@ def blah()
r_arr = j_arr.to_a
j_arr[0] = 3
expect( r_arr[0] ).to eql 1

j_arr = [1, 2].to_java(:int)
r_arr = j_arr.entries
j_arr[0] = 3
expect( r_arr[0] ).to eql 1
end

it "returns a new array from to_ary" do
@@ -1102,6 +1210,79 @@ def blah()
expect( r_arr[0] ).to eql 1
end

it 'supports #first (Enumerable)' do
arr = [ '1', '2', '3' ].to_java('java.lang.String')
expect( arr.first ).to eql '1'
expect( arr.first(2) ).to eql [ '1', '2' ]

arr = [ 1, 2, 3 ].to_java(:int)
expect( arr.first ).to eql 1
expect( arr.first(1) ).to eql [ 1 ]
expect( arr.first(5) ).to eql [ 1, 2, 3 ]

arr = Java::byte[0].new
expect( arr.first ).to be nil
expect( arr.first(1) ).to eql []
end

it 'supports #last (like Ruby Array)' do
arr = [ '1', '2', '3' ].to_java('java.lang.String')
expect( arr.last ).to eql '3'
expect( arr.last(2) ).to eql [ '2', '3' ]

arr = [ 1, 2, 3 ].to_java(:int)
expect( arr.last ).to eql 3
expect( arr.last(1) ).to eql [ 3 ]
expect( arr.last(8) ).to eql [ 1, 2, 3 ]

arr = Java::byte[0].new
expect( arr.last ).to be nil
expect( arr.last(1) ).to eql []
end

it 'counts' do
arr = [ '1', '2', '3' ].to_java('java.lang.String')
expect( arr.count ).to eql 3
expect( arr.count('2') ).to eql 1
expect( arr.count(1) ).to eql 0

arr = [ 1, 2, 2 ].to_java(:int)
expect( arr.count { |e| e > 0 } ).to eql 3
expect( arr.count(2) ).to eql 2

arr = Java::byte[0].new
expect( arr.count ).to eql 0
end

it 'each return self' do
arr = Java::int[5].new
expect( arr.each { |i| i } ).to be arr
arr = [].to_java
expect( arr.each { |i| i } ).to be arr
end

it 'each without block' do
arr = Java::float[5].new; arr[1] = 1.0
expect( enum = arr.each ).to be_a Enumerator
expect( enum.next ).to eql 0.0
expect( enum.next ).to eql 1.0
end

it 'each with index' do
arr = Java::byte[5].new
counter = 0
ret = arr.each_with_index { |el, i| expect(el).to eql 0; expect(i).to eql(counter); counter += 1 }
expect( counter ).to eql 5
expect( ret ).to eql arr

arr = Java::long[4].new; arr[1] = 1; arr[2] = 1; arr[3] = 3
expect( enum = arr.each_with_index ).to be_a Enumerator
expect( enum.next ).to eql [0, 0]
expect( enum.next ).to eql [1, 1]
expect( enum.next ).to eql [1, 2]
expect( enum.next ).to eql [3, 3]
end

describe "#dig" do

it 'returns #at with one arg' do
3 changes: 2 additions & 1 deletion truffle/src/main/java/org/jruby/truffle/core/MathNodes.java
Original file line number Diff line number Diff line change
@@ -56,6 +56,7 @@
import org.jruby.truffle.language.dispatch.MissingBehavior;
import org.jruby.truffle.language.objects.IsANode;
import org.jruby.truffle.language.objects.IsANodeGen;
import org.jruby.truffle.util.DoubleUtils;

@CoreClass("Math")
public abstract class MathNodes {
@@ -475,7 +476,7 @@ public double function(double a, long b) {
public double function(double a, double b) {
if (Double.isNaN(b)) {
exceptionProfile.enter();
throw new RaiseException(coreExceptions().rangeError("float", Double.toString(b), "integer", this));
throw new RaiseException(coreExceptions().rangeError("float", DoubleUtils.toString(b), "integer", this));
}

return a * Math.pow(2, b);
Original file line number Diff line number Diff line change
@@ -943,7 +943,7 @@ public abstract static class HashNode extends ArrayCoreMethodNode {
public long hashNull(DynamicObject array) {
final int size = 0;
long h = Helpers.hashStart(getContext().getJRubyRuntime(), size);
h = Helpers.murmurCombine(h, System.identityHashCode(ArrayNodes.class));
h = Helpers.murmurCombine(h, identityHashCode(ArrayNodes.class));
return Helpers.hashEnd(h);
}

@@ -954,7 +954,7 @@ public long hash(VirtualFrame frame, DynamicObject array,
final int size = getSize(array);
// TODO BJF Jul 4, 2016 Seed could be chosen in advance to avoid branching
long h = Helpers.hashStart(getContext().getJRubyRuntime(), size);
h = Helpers.murmurCombine(h, System.identityHashCode(ArrayNodes.class));
h = Helpers.murmurCombine(h, identityHashCode(ArrayNodes.class));
final ArrayMirror store = strategy.newMirror(array);

for (int n = 0; n < size; n++) {
@@ -979,6 +979,11 @@ private long toLong(VirtualFrame frame, Object indexObject) {
}
}

@TruffleBoundary
private int identityHashCode(Object o) {
return System.identityHashCode(o);
}

}

@CoreMethod(names = "include?", required = 1)
Original file line number Diff line number Diff line change
@@ -177,7 +177,7 @@ public Object instanceEval(VirtualFrame frame, Object receiver, DynamicObject st

// TODO (pitr 15-Oct-2015): fix this ugly hack, required for AS, copy-paste
final String space = getSpace(line);
final Source source = getContext().getSourceLoader().loadFragment(space + code.toString(), StringOperations.rope(fileName).toString());
final Source source = loadFragment(space + code.toString(), StringOperations.rope(fileName).toString());

final RubyRootNode rootNode = getContext().getCodeLoader().parse(source, code.getEncoding(), ParserContext.EVAL, null, true, this);
final CodeLoader.DeferredCall deferredCall = getContext().getCodeLoader().prepareExecute(ParserContext.EVAL, DeclarationContext.INSTANCE_EVAL, rootNode, null, receiver);
@@ -206,6 +206,11 @@ private String getSpace(int line) {
return StringUtils.replace(s, "\0", "\n");
}

@TruffleBoundary
private Source loadFragment(String fragment, String name) {
return getContext().getSourceLoader().loadFragment(fragment, name);
}

}

@CoreMethod(names = "instance_exec", needsBlock = true, rest = true)
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@
import org.jruby.truffle.language.dispatch.MissingBehavior;
import org.jruby.truffle.language.objects.IsTaintedNode;
import org.jruby.truffle.language.objects.IsTaintedNodeGen;
import org.jruby.truffle.util.DoubleUtils;

import java.nio.charset.StandardCharsets;

@@ -82,7 +83,7 @@ public byte[] toString(long value) {
@TruffleBoundary
@Specialization(guards = "convertNumbersToStrings")
public byte[] toString(double value) {
return Double.toString(value).getBytes(StandardCharsets.US_ASCII);
return DoubleUtils.toString(value).getBytes(StandardCharsets.US_ASCII);
}

@Specialization(guards = "isRubyString(string)")
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ protected String getCharString(VirtualFrame frame, Object value) {
// TODO BJF check char length is > 0
charString = Character.toString((char) charValue);
} else {
final String resultString = new String((byte[]) toStrResult);
final String resultString = StringUtils.create((byte[]) toStrResult);
final int size = resultString.length();
if (size > 1) {
throw new RaiseException(getContext().getCoreExceptions().argumentErrorCharacterRequired(this));
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.format.FormatNode;
import org.jruby.truffle.core.format.printf.PrintfSimpleTreeBuilder;
import org.jruby.truffle.util.StringUtils;
import org.jruby.util.ConvertBytes;

import java.math.BigInteger;
@@ -77,7 +78,7 @@ public byte[] format(int width, int precision, int value) {
formatted = "0" + formatted;
}
if (value < 0) {
formatted = "..7" + new String(elide(ConvertBytes.intToOctalBytes(value), format, precision));
formatted = "..7" + StringUtils.create(elide(ConvertBytes.intToOctalBytes(value), format, precision));
;
}
break;
@@ -126,7 +127,7 @@ public byte[] format(int width, int precision, long value) {
formatted = "0" + formatted;
}
if (value < 0) {
formatted = "..7" + new String(elide(ConvertBytes.longToOctalBytes(value), format, precision));
formatted = "..7" + StringUtils.create(elide(ConvertBytes.longToOctalBytes(value), format, precision));
}
break;
case 'd':
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.util.DoubleUtils;
import org.jruby.truffle.util.StringUtils;

import java.util.Locale;
@@ -771,7 +772,7 @@ public abstract static class ToSNode extends CoreMethodArrayArgumentsNode {
@Specialization
public DynamicObject toS(double value) {
if (Double.isInfinite(value) || Double.isNaN(value)) {
return create7BitString(Double.toString(value), USASCIIEncoding.INSTANCE);
return create7BitString(DoubleUtils.toString(value), USASCIIEncoding.INSTANCE);
}

String str = StringUtils.format(Locale.ENGLISH, "%.15g", value);
Original file line number Diff line number Diff line change
@@ -343,6 +343,7 @@ public LeafRope makeValidLeafRopeFixedWidthEncoding(byte[] bytes, Encoding encod
return new ValidLeafRope(bytes, encoding, calculatedCharacterLength);
}

@TruffleBoundary
@Specialization(guards = { "isValid(codeRange)", "!isFixedWidth(encoding)", "wasNotProvided(characterLength)" })
public LeafRope makeValidLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength) {
// Exctracted from StringSupport.strLength.
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.language.RubyGuards;
import org.jruby.truffle.util.ByteListUtils;
import org.jruby.truffle.util.StringUtils;
import org.jruby.util.ByteList;

@@ -195,7 +196,7 @@ public static Rope ropeFromByteList(ByteList byteList, int codeRange) {

@TruffleBoundary
public static ByteList createByteList(CharSequence s) {
return ByteList.create(s);
return ByteListUtils.create(s);
}

public static Rope rope(DynamicObject string) {
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.JavaException;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.util.ByteListUtils;
import org.jruby.util.ByteList;
import java.io.IOException;

@@ -316,12 +317,13 @@ public boolean isBoxed(Object receiver) {
@CoreMethod(names = "unbox", isModuleFunction = true, required = 1)
public abstract static class UnboxNode extends CoreMethodArrayArgumentsNode {

@TruffleBoundary
@Specialization
public DynamicObject unbox(CharSequence receiver) {
// TODO CS-21-Dec-15 this shouldn't be needed - we need to convert j.l.String to Ruby's String automatically

return Layouts.STRING.createString(coreLibrary().getStringFactory(),
StringOperations.ropeFromByteList(ByteList.create(receiver)));
StringOperations.ropeFromByteList(ByteListUtils.create(receiver)));
}

@Specialization
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
*/
package org.jruby.truffle.interop;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.object.DynamicObject;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.RubyContext;
@@ -29,7 +29,7 @@ public JRubyInterop(RubyContext context) {
this.context = context;
}

@CompilerDirectives.TruffleBoundary
@TruffleBoundary
public DynamicObject toTruffle(org.jruby.RubyException jrubyException, RubyNode currentNode) {
switch (jrubyException.getMetaClass().getName()) {
case "ArgumentError":
@@ -41,6 +41,7 @@ public DynamicObject toTruffle(org.jruby.RubyException jrubyException, RubyNode
throw new UnsupportedOperationException();
}

@TruffleBoundary
public String getArg0() {
return context.getJRubyRuntime().getGlobalVariables().get("$0").toString();
}
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@
import org.jruby.truffle.Layouts;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.util.ByteList;
import org.jruby.truffle.util.ByteListUtils;

public class DataNode extends RubyNode {

@@ -38,7 +38,7 @@ public Object execute(VirtualFrame frame) {
final Object data = snippetNode.execute(frame,
"Truffle.get_data(file, offset)",
"file", StringOperations.createString(getContext(),
ByteList.create(getEncapsulatingSourceSection().getSource().getName())),
ByteListUtils.create(getEncapsulatingSourceSection().getSource().getName())),
"offset", endPosition);

Layouts.MODULE.getFields(coreLibrary().getObjectClass()).setConstant(getContext(), null, "DATA", data);
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
package org.jruby.truffle.language;

import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.interop.ForeignAccess;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.ObjectType;
@@ -22,6 +23,7 @@
public class RubyObjectType extends ObjectType {

@Override
@TruffleBoundary
public String toString(DynamicObject object) {
CompilerAsserts.neverPartOfCompilation();

Original file line number Diff line number Diff line change
@@ -34,6 +34,7 @@
import org.jruby.truffle.language.loader.SourceLoader;
import org.jruby.truffle.language.methods.DeclarationContext;
import org.jruby.truffle.language.parser.ParserContext;
import org.jruby.truffle.util.ByteListUtils;
import org.jruby.util.ByteList;
import org.jruby.util.Memo;

@@ -94,7 +95,7 @@ public Object runJRubyRootNode(VirtualFrame frame, @Cached("create()") IndirectC
coreLibrary().getGlobalVariables().put(
"$0",
StringOperations.createString(getContext(),
ByteList.create(getContext().getJRubyInterop().getArg0())));
ByteListUtils.create(getContext().getJRubyInterop().getArg0())));

String inputFile = getContext().getJRubyInterop().getOriginalInputFile();

Original file line number Diff line number Diff line change
@@ -26,6 +26,8 @@ public class ReadUserKeywordsHashNode extends RubyNode {

private final ConditionProfile notEnoughArgumentsProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile lastArgumentIsHashProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile respondsToToHashProfile = ConditionProfile.createBinaryProfile();
private final ConditionProfile convertedIsHashProfile = ConditionProfile.createBinaryProfile();

public ReadUserKeywordsHashNode(int minArgumentCount) {
this.minArgumentCount = minArgumentCount;
@@ -45,20 +47,14 @@ public Object execute(VirtualFrame frame) {
return lastArgument;
}

CompilerDirectives.bailout("Ruby keyword arguments aren't optimized yet");

if (respondToToHashNode == null) {
respondToToHashNode = insert(new DoesRespondDispatchHeadNode(getContext(), false));
}

if (respondToToHashNode.doesRespondTo(frame, "to_hash", lastArgument)) {
if (callToHashNode == null) {
callToHashNode = insert(CallDispatchHeadNode.createMethodCall());
}
return tryConvertToHash(frame, argumentCount, lastArgument);
}

final Object converted = callToHashNode.call(frame, lastArgument, "to_hash");
private Object tryConvertToHash(VirtualFrame frame, final int argumentCount, final Object lastArgument) {
if (respondsToToHashProfile.profile(respondToToHash(frame, lastArgument))) {
final Object converted = callToHash(frame, lastArgument);

if (RubyGuards.isRubyHash(converted)) {
if (convertedIsHashProfile.profile(RubyGuards.isRubyHash(converted))) {
RubyArguments.setArgument(frame, argumentCount - 1, converted);
return converted;
}
@@ -67,4 +63,20 @@ public Object execute(VirtualFrame frame) {
return null;
}

private boolean respondToToHash(VirtualFrame frame, final Object lastArgument) {
if (respondToToHashNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
respondToToHashNode = insert(new DoesRespondDispatchHeadNode(getContext(), false));
}
return respondToToHashNode.doesRespondTo(frame, "to_hash", lastArgument);
}

private Object callToHash(VirtualFrame frame, final Object lastArgument) {
if (callToHashNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
callToHashNode = insert(CallDispatchHeadNode.createMethodCall());
}
return callToHashNode.call(frame, lastArgument, "to_hash");
}

}
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@
import org.jruby.truffle.language.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.language.methods.DeclarationContext;
import org.jruby.truffle.language.parser.ParserContext;
import org.jruby.truffle.util.StringUtils;

@NodeChild("feature")
public abstract class RequireNode extends RubyNode {
@@ -104,7 +105,7 @@ protected boolean require(VirtualFrame frame, String feature,
return false;
}

final String mimeType = source.getMimeType();
final String mimeType = getSourceMimeType(source);

if (RubyLanguage.MIME_TYPE.equals(mimeType)) {
final RubyRootNode rootNode = getContext().getCodeLoader().parse(
@@ -145,7 +146,7 @@ protected boolean require(VirtualFrame frame, String feature,
} else {
errorProfile.enter();

if (expandedPath.toLowerCase().endsWith(".su")) {
if (StringUtils.toLowerCase(expandedPath).endsWith(".su")) {
throw new RaiseException(cextSupportNotAvailable(expandedPath));
} else {
throw new RaiseException(unknownLanguage(expandedPath, mimeType));
@@ -161,6 +162,11 @@ protected boolean require(VirtualFrame frame, String feature,
}
}

@TruffleBoundary
private String getSourceMimeType(Source source) {
return source.getMimeType();
}

@TruffleBoundary
private DynamicObject cextSupportNotAvailable(String expandedPath) {
return getContext().getCoreExceptions().internalError(
Original file line number Diff line number Diff line change
@@ -164,17 +164,24 @@ public DynamicObject translate(Throwable throwable) {
throwable.printStackTrace();
}

final StringBuilder message = new StringBuilder();
message.append(throwable.getClass().getSimpleName());
message.append(" ");
message.append(throwable.getMessage());

if (throwable.getStackTrace().length > 0) {
message.append(" ");
message.append(throwable.getStackTrace()[0].toString());
final String message;

if (throwable.getMessage() != null && throwable.getMessage().startsWith("LLVM error")) {
message = throwable.getMessage();
} else {
final StringBuilder messageBuilder = new StringBuilder();
messageBuilder.append(throwable.getClass().getSimpleName());
messageBuilder.append(" ");
messageBuilder.append(throwable.getMessage());

if (throwable.getStackTrace().length > 0) {
messageBuilder.append(" ");
messageBuilder.append(throwable.getStackTrace()[0].toString());
}
message = messageBuilder.toString();
}

return coreExceptions().internalError(message.toString(), this, throwable);
return coreExceptions().internalError(message, this, throwable);
}

}
Original file line number Diff line number Diff line change
@@ -80,18 +80,10 @@ public Object doOther(
final Object numerator = numeratorCallNode.call(frame, value, "numerator");
final Object denominator = denominatorCallNode.call(frame, value, "denominator");

final RubyRational rubyRationalValue = RubyRational.newRationalRaw(
getContext().getJRubyRuntime(),
toJRubyInteger(numerator),
toJRubyInteger(denominator));
final RubyRational rubyRationalValue = newRationalRaw(numerator, denominator);

try {
return RubyBigDecimal
.getVpRubyObjectWithPrec19Inner(
getContext().getJRubyRuntime().getCurrentContext(),
rubyRationalValue,
(RoundingMode) roundingMode)
.getBigDecimalValue();
return toBigDecimal(rubyRationalValue, (RoundingMode) roundingMode);
} catch (Exception e) {
throw e;
}
@@ -106,6 +98,23 @@ public Object doOther(
}
}

@TruffleBoundary
private RubyRational newRationalRaw(Object numerator, Object denominator) {
return RubyRational.newRationalRaw(
getContext().getJRubyRuntime(),
toJRubyInteger(numerator),
toJRubyInteger(denominator));
}

@TruffleBoundary
private BigDecimal toBigDecimal(RubyRational rubyRationalValue, RoundingMode roundingMode) {
return RubyBigDecimal
.getVpRubyObjectWithPrec19Inner(
getContext().getJRubyRuntime().getCurrentContext(),
rubyRationalValue, roundingMode)
.getBigDecimalValue();
}

@TruffleBoundary
private IRubyObject toJRubyInteger(Object value) {
if (value instanceof Integer) {
Original file line number Diff line number Diff line change
@@ -137,6 +137,7 @@ public DynamicObject initialize(
@CoreMethod(names = "start_stream", required = 1)
public abstract static class StartStreamNode extends CoreMethodArrayArgumentsNode {

@TruffleBoundary
@Specialization
public DynamicObject startStream(DynamicObject emitter, int encodingOrdinal) {
if (Layouts.PSYCH_EMITTER.getEmitter(emitter) != null) {
Original file line number Diff line number Diff line change
@@ -38,12 +38,13 @@
*/
package org.jruby.truffle.stdlib.psych;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.profiles.BranchProfile;
import com.oracle.truffle.api.source.SourceSection;
import org.jcodings.Encoding;
import org.jcodings.specific.UTF8Encoding;
@@ -68,6 +69,7 @@
import org.jruby.truffle.language.objects.ReadObjectFieldNodeGen;
import org.jruby.truffle.language.objects.TaintNode;
import org.jruby.truffle.language.objects.TaintNodeGen;
import org.jruby.truffle.util.BoundaryUtils.BoundaryIterable;
import org.jruby.util.ByteList;
import org.jruby.util.io.EncodingUtils;
import org.yaml.snakeyaml.DumperOptions;
@@ -76,6 +78,7 @@
import org.yaml.snakeyaml.events.DocumentEndEvent;
import org.yaml.snakeyaml.events.DocumentStartEvent;
import org.yaml.snakeyaml.events.Event;
import org.yaml.snakeyaml.events.Event.ID;
import org.yaml.snakeyaml.events.MappingStartEvent;
import org.yaml.snakeyaml.events.ScalarEvent;
import org.yaml.snakeyaml.events.SequenceStartEvent;
@@ -85,11 +88,9 @@
import org.yaml.snakeyaml.reader.ReaderException;
import org.yaml.snakeyaml.reader.StreamReader;
import org.yaml.snakeyaml.scanner.ScannerException;

import java.io.ByteArrayInputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;

@CoreClass("Psych::Parser")
@@ -135,36 +136,21 @@ public Object parse(
@Cached("createMethodCall()") CallDispatchHeadNode callEndStreamNode,
@Cached("new()") SnippetNode raiseSyntaxErrorSnippetNode,
@Cached("new()") SnippetNode tagPushNode,
@Cached("createTaintNode()") TaintNode taintNode) {
CompilerDirectives.bailout("Psych parsing cannot be compiled");
@Cached("createTaintNode()") TaintNode taintNode,
@Cached("create()") BranchProfile errorProfile) {

final boolean tainted = (boolean) taintedNode.execute(frame, "yaml.tainted? || yaml.is_a?(IO)", "yaml", yaml);

final StreamReader reader;

if (!RubyGuards.isRubyString(yaml) && respondToReadNode.doesRespondTo(frame, "read", yaml)) {
final Encoding enc = UTF8Encoding.INSTANCE;
final Charset charset = enc.getCharset();
reader = new StreamReader(new InputStreamReader(new InputStreamAdapter(getContext(), yaml), charset));
reader = newStreamReader(yaml);
} else {
ByteList byteList = StringOperations.getByteListReadOnly(toStrNode.executeToStr(frame, yaml));
Encoding encoding = byteList.getEncoding();

if (!(encoding instanceof UnicodeEncoding)) {
byteList = EncodingUtils.strConvEnc(getContext().getJRubyRuntime().getCurrentContext(),
byteList, encoding, UTF8Encoding.INSTANCE);

encoding = UTF8Encoding.INSTANCE;
}

reader = new StreamReader(
new InputStreamReader(
new ByteArrayInputStream(
byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize()),
encoding.getCharset()));
reader = newStringReader(byteList);
}

final Parser parser = new ParserImpl(reader);
final Parser parser = newParser(reader);

try {
if (isNil(path) && respondToPathNode.doesRespondTo(frame, "path", yaml)) {
@@ -174,11 +160,12 @@ public Object parse(
final Object handler = readHandlerNode.execute(parserObject);

while (true) {
Event event = parser.getEvent();
Event event = getParserEvent(parser);

if (event.is(Event.ID.StreamStart)) {
if (isEvent(event, Event.ID.StreamStart)) {
callStartStreamNode.call(frame, handler, "start_stream", YAMLEncoding.YAML_ANY_ENCODING.ordinal());
} else if (event.is(Event.ID.DocumentStart)) {

} else if (isEvent(event, Event.ID.DocumentStart)) {
final DocumentStartEvent startEvent = (DocumentStartEvent) event;

final DumperOptions.Version versionOptions = startEvent.getVersion();
@@ -189,7 +176,7 @@ public Object parse(
if (versionInts == null) {
versionArray = Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), null, 0);
} else {
versionArray = Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), new Object[]{
versionArray = Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), new Object[] {
versionInts[0], versionInts[1]
}, 2);
}
@@ -198,9 +185,9 @@ public Object parse(
DynamicObject tags = Layouts.ARRAY.createArray(coreLibrary().getArrayFactory(), null, 0);

if (tagsMap != null && tagsMap.size() > 0) {
for (Map.Entry<String, String> tag : tagsMap.entrySet()) {
Object key = stringFor(tag.getKey(), tainted, taintNode);
Object value = stringFor(tag.getValue(), tainted, taintNode);
for (Map.Entry<String, String> tag : BoundaryIterable.wrap(tagsMap.entrySet())) {
Object key = stringFor(getKey(tag), tainted, taintNode);
Object value = stringFor(getValue(tag), tainted, taintNode);
tagPushNode.execute(frame,
"tags.push [key, value]",
"tags", tags,
@@ -211,15 +198,18 @@ public Object parse(

Object notExplicit = !startEvent.getExplicit();
callStartDocumentNode.call(frame, handler, "start_document", versionArray, tags, notExplicit);
} else if (event.is(Event.ID.DocumentEnd)) {

} else if (isEvent(event, Event.ID.DocumentEnd)) {
final DocumentEndEvent endEvent = (DocumentEndEvent) event;
Object notExplicit = !endEvent.getExplicit();
callEndDocumentNode.call(frame, handler, "end_document", notExplicit);
} else if (event.is(Event.ID.Alias)) {

} else if (isEvent(event, Event.ID.Alias)) {
final AliasEvent aliasEvent = (AliasEvent) event;
Object alias = stringOrNilFor(aliasEvent.getAnchor(), tainted, taintNode);
callAliasNode.call(frame, handler, "alias", alias);
} else if (event.is(Event.ID.Scalar)) {

} else if (isEvent(event, Event.ID.Scalar)) {
final ScalarEvent scalarEvent = (ScalarEvent) event;

Object anchor = stringOrNilFor(scalarEvent.getAnchor(), tainted, taintNode);
@@ -229,9 +219,9 @@ public Object parse(
Object style = translateStyle(scalarEvent.getStyle());
Object val = stringFor(scalarEvent.getValue(), tainted, taintNode);

callScalarNode.call(frame, handler, "scalar", val, anchor, tag, plain_implicit, quoted_implicit,
style);
} else if (event.is(Event.ID.SequenceStart)) {
callScalarNode.call(frame, handler, "scalar", val, anchor, tag, plain_implicit, quoted_implicit, style);

} else if (isEvent(event, Event.ID.SequenceStart)) {
final SequenceStartEvent sequenceStartEvent = (SequenceStartEvent) event;

Object anchor = stringOrNilFor(sequenceStartEvent.getAnchor(), tainted, taintNode);
@@ -240,9 +230,11 @@ public Object parse(
Object style = translateFlowStyle(sequenceStartEvent.getFlowStyle());

callStartSequenceNode.call(frame, handler, "start_sequence", anchor, tag, implicit, style);
} else if (event.is(Event.ID.SequenceEnd)) {

} else if (isEvent(event, Event.ID.SequenceEnd)) {
callEndSequenceNode.call(frame, handler, "end_sequence");
} else if (event.is(Event.ID.MappingStart)) {

} else if (isEvent(event, Event.ID.MappingStart)) {
final MappingStartEvent mappingStartEvent = (MappingStartEvent) event;

Object anchor = stringOrNilFor(mappingStartEvent.getAnchor(), tainted, taintNode);
@@ -251,14 +243,17 @@ public Object parse(
Object style = translateFlowStyle(mappingStartEvent.getFlowStyle());

callStartMappingNode.call(frame, handler, "start_mapping", anchor, tag, implicit, style);
} else if (event.is(Event.ID.MappingEnd)) {

} else if (isEvent(event, Event.ID.MappingEnd)) {
callEndMappingNode.call(frame, handler, "end_mapping");
} else if (event.is(Event.ID.StreamEnd)) {

} else if (isEvent(event, Event.ID.StreamEnd)) {
callEndStreamNode.call(frame, handler, "end_stream");
break;
}
}
} catch (ParserException pe) {
} catch (ParserException | ScannerException pe) {
errorProfile.enter();
final Mark mark = pe.getProblemMark();

raiseSyntaxErrorSnippetNode.execute(frame,
@@ -267,36 +262,87 @@ public Object parse(
"line", mark.getLine(),
"col", mark.getColumn(),
"offset", mark.getIndex(),
"problem", pe.getProblem() == null ? nil() : createString(new ByteList(pe.getProblem().getBytes(StandardCharsets.UTF_8))),
"context", pe.getContext() == null ? nil() : createString(new ByteList(pe.getContext().getBytes(StandardCharsets.UTF_8))));
} catch (ScannerException se) {
final Mark mark = se.getProblemMark();

raiseSyntaxErrorSnippetNode.execute(frame,
"raise Psych::SyntaxError.new(file, line, col, offset, problem, context)",
"file", path,
"line", mark.getLine(),
"col", mark.getColumn(),
"offset", mark.getIndex(),
"problem", se.getProblem() == null ? nil() : createString(new ByteList(se.getProblem().getBytes(StandardCharsets.UTF_8))),
"context", se.getContext() == null ? nil() : createString(new ByteList(se.getContext().getBytes(StandardCharsets.UTF_8))));
"problem", pe.getProblem() == null ? nil() : createUTF8String(pe.getProblem()),
"context", pe.getContext() == null ? nil() : createUTF8String(pe.getContext()));
} catch (ReaderException re) {
errorProfile.enter();

raiseSyntaxErrorSnippetNode.execute(frame,
"raise Psych::SyntaxError.new(file, line, col, offset, problem, context)",
"file", path,
"line", 0,
"col", 0,
"offset", re.getPosition(),
"problem", re.getName() == null ? nil() : createString(new ByteList(re.getName().getBytes(StandardCharsets.UTF_8))),
"context", re.toString() == null ? nil() : createString(new ByteList(re.toString().getBytes(StandardCharsets.UTF_8))));
"problem", re.getName() == null ? nil() : createUTF8String(re.getName()),
"context", toString(re) == null ? nil() : createUTF8String(toString(re)));
} catch (Throwable t) {
errorProfile.enter();
Helpers.throwException(t);
return parserObject;
}

return parserObject;
}

@TruffleBoundary
private StreamReader newStreamReader(DynamicObject yaml) {
final Encoding enc = UTF8Encoding.INSTANCE;
final Charset charset = enc.getCharset();
return new StreamReader(new InputStreamReader(new InputStreamAdapter(getContext(), yaml), charset));
}

@TruffleBoundary
private StreamReader newStringReader(ByteList byteList) {
Encoding encoding = byteList.getEncoding();

if (!(encoding instanceof UnicodeEncoding)) {
byteList = EncodingUtils.strConvEnc(getContext().getJRubyRuntime().getCurrentContext(),
byteList, encoding, UTF8Encoding.INSTANCE);

encoding = UTF8Encoding.INSTANCE;
}

return new StreamReader(
new InputStreamReader(
new ByteArrayInputStream(
byteList.getUnsafeBytes(), byteList.getBegin(), byteList.getRealSize()),
encoding.getCharset()));
}

@TruffleBoundary
private ParserImpl newParser(StreamReader reader) {
return new ParserImpl(reader);
}

@TruffleBoundary
private Event getParserEvent(Parser parser) {
return parser.getEvent();
}

@TruffleBoundary
private boolean isEvent(Event event, ID id) {
return event.is(id);
}

private DynamicObject createUTF8String(String value) {
return createString(StringOperations.encodeRope(value, UTF8Encoding.INSTANCE));
}

@TruffleBoundary
private String getKey(Map.Entry<String, String> tag) {
return tag.getKey();
}

@TruffleBoundary
private String getValue(Map.Entry<String, String> tag) {
return tag.getValue();
}

@TruffleBoundary
private String toString(ReaderException re) {
return re.toString();
}

protected ReadObjectFieldNode createReadHandlerNode() {
return ReadObjectFieldNodeGen.create("@handler", nil());
}
@@ -341,6 +387,7 @@ private static int translateFlowStyle(Boolean flowStyle) {
}
}

@TruffleBoundary
private Object stringOrNilFor(String value, boolean tainted, TaintNode taintNode) {
if (value == null) {
return nil();
@@ -349,6 +396,7 @@ private Object stringOrNilFor(String value, boolean tainted, TaintNode taintNode
}
}

@TruffleBoundary
private Object stringFor(String value, boolean tainted, TaintNode taintNode) {
Encoding encoding = getContext().getJRubyRuntime().getDefaultInternalEncoding();

57 changes: 57 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/util/BoundaryUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.util;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import java.util.Iterator;

public class BoundaryUtils {

public static class BoundaryIterable<E> implements Iterable<E> {

public static <E> Iterable<E> wrap(Iterable<E> iterable) {
return new BoundaryIterable<>(iterable);
}

private final Iterable<E> iterable;

public BoundaryIterable(Iterable<E> iterable) {
this.iterable = iterable;
}

@Override
public Iterator<E> iterator() {
return new BoundaryIterator<E>(iterable.iterator());
}
}

public static class BoundaryIterator<E> implements Iterator<E> {

private final Iterator<E> iterator;

public BoundaryIterator(Iterator<E> iterator) {
this.iterator = iterator;
}

@TruffleBoundary
@Override
public boolean hasNext() {
return iterator.hasNext();
}

@TruffleBoundary
@Override
public E next() {
return iterator.next();
}

}

}
22 changes: 22 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/util/ByteListUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.util;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import org.jruby.util.ByteList;

public abstract class ByteListUtils {

@TruffleBoundary
public static ByteList create(CharSequence s) {
return ByteList.create(s);
}

}
21 changes: 21 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/util/DoubleUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved. This
* code is released under a tri EPL/GPL/LGPL license. You can use it,
* redistribute it and/or modify it under the terms of the:
*
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*/
package org.jruby.truffle.util;

import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;

public abstract class DoubleUtils {

@TruffleBoundary
public static String toString(double d) {
return Double.toString(d);
}

}
10 changes: 10 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/util/StringUtils.java
Original file line number Diff line number Diff line change
@@ -15,6 +15,11 @@

public abstract class StringUtils {

@TruffleBoundary
public static String create(byte[] bytes) {
return new String(bytes);
}

@TruffleBoundary
public static String format(Locale locale, String format, Object... args) {
return String.format(locale, format, args);
@@ -35,4 +40,9 @@ public static String replace(String string, CharSequence target, CharSequence re
return string.replace(target, replacement);
}

@TruffleBoundary
public static String toLowerCase(String string) {
return string.toLowerCase();
}

}
8 changes: 4 additions & 4 deletions truffle/src/main/ruby/core/comparable.rb
Original file line number Diff line number Diff line change
@@ -29,11 +29,11 @@ def ==(other)
return true if equal?(other)

return false if Thread.detect_recursion(self, other) do
unless comp = (self <=> other)
return false
end
unless comp = (self <=> other)
return false
end

return Comparable.compare_int(comp) == 0
return Comparable.compare_int(comp) == 0
end
end

6 changes: 0 additions & 6 deletions truffle/src/main/ruby/core/encoding.rb
Original file line number Diff line number Diff line change
@@ -230,12 +230,6 @@ def initialize(from, to, options=undefined)
end
initialize_jruby(*[@source_encoding, @destination_encoding, @options])
end

alias_method :initialize_rubinius, :initialize

def initialize(*args)
initialize_rubinius(*args)
end

def convert(str)
str = StringValue(str)

0 comments on commit 10c6b6e

Please sign in to comment.