Skip to content

Commit

Permalink
Showing 27 changed files with 593 additions and 97 deletions.
9 changes: 6 additions & 3 deletions core/src/main/java/org/jruby/RubyString.java
Original file line number Diff line number Diff line change
@@ -2088,6 +2088,7 @@ public static IRubyObject inspect19(Ruby runtime, ByteList byteList) {
result.associateEncoding(resultEnc);

boolean isUnicode = StringSupport.isUnicode(enc);
boolean asciiCompat = enc.isAsciiCompatible();

EncodingDB.Entry e = null;
CaseInsensitiveBytesHash<EncodingDB.Entry> encodings = runtime.getEncodingService().getEncodings();
@@ -2100,6 +2101,7 @@ public static IRubyObject inspect19(Ruby runtime, ByteList byteList) {
} else if (c0 == 0xFF && c1 == 0xFE) {
e = encodings.get("UTF-16LE".getBytes());
} else {
e = encodings.get("ASCII-8BIT".getBytes());
isUnicode = false;
}
} else if (enc == encodings.get("UTF-32".getBytes()).getEncoding() && end - p > 3) {
@@ -2113,6 +2115,7 @@ public static IRubyObject inspect19(Ruby runtime, ByteList byteList) {
} else if (c3 == 0 && c2 == 0 && c1 == 0xFE && c0 == 0xFF) {
e = encodings.get("UTF-32LE".getBytes());
} else {
e = encodings.get("ASCII-8BIT".getBytes());
isUnicode = false;
}
}
@@ -2137,13 +2140,13 @@ public static IRubyObject inspect19(Ruby runtime, ByteList byteList) {
}
int c = enc.mbcToCode(bytes, p, end);
p += n;
if ((enc.isAsciiCompatible() || isUnicode) &&
if ((asciiCompat || isUnicode) &&
(c == '"' || c == '\\' ||
(c == '#' && p < end && (StringSupport.preciseLength(enc, bytes, p, end) > 0) &&
(cc = codePoint(runtime, enc, bytes, p, end)) == '$' || cc == '@' || cc == '{'))) {
if (p - n > prev) result.cat(bytes, prev, p - n - prev);
result.cat('\\');
if (enc.isAsciiCompatible() || enc == resultEnc) {
if (asciiCompat || enc == resultEnc) {
prev = p - n;
continue;
}
@@ -2169,7 +2172,7 @@ public static IRubyObject inspect19(Ruby runtime, ByteList byteList) {
continue;
}

if ((enc == resultEnc && enc.isPrint(c)) || (enc.isAsciiCompatible() && Encoding.isAscii(c) && enc.isPrint(c))) {
if ((enc == resultEnc && enc.isPrint(c)) || (asciiCompat && Encoding.isAscii(c) && enc.isPrint(c))) {
continue;
} else {
if (p - n > prev) result.cat(bytes, prev, p - n - prev);
1 change: 1 addition & 0 deletions maven/jruby-dist/src/main/assembly/jruby.xml
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
<include>LICENSE*</include>
<include>COPYING*</include>
<include>lib/jruby.jar</include>
<include>lib/jruby-truffle.jar</include>
<include>lib/jni/**/*</include>
<include>samples/**/*</include>
<include>docs/**/*</include>
15 changes: 5 additions & 10 deletions spec/regression/GH-1675_casecmp_on_UTF16LE_encoded_string_spec.rb
Original file line number Diff line number Diff line change
@@ -3,16 +3,11 @@
describe 'String#casecmp' do
it 'returns correct value' do
Encoding.name_list.each do |enc_name|
if (enc_name != "UTF-7") && (enc_name != "CP65000")
# this condition statement escape the following error:
# Encoding::ConverterNotFoundError:
# code converter not found for UTF-7

# using "UTF-16LE", "UTF-8", "Shift_JIS", and other available encodings
a = 'ABC'.encode(enc_name)
b = 'ABC'.encode(enc_name)
b.casecmp(a).should be_true
end
enc = Encoding.find(enc_name)
next if !enc || enc.dummy?
a = 'ABC'.encode(enc)
b = 'ABC'.encode(enc)
b.casecmp(a).should == 0
end
end
end
1 change: 0 additions & 1 deletion spec/truffle/tags/core/array/concat_tags.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
fails:Array#concat tries to convert the passed argument to an Array using #to_ary
fails:Array#concat is not infected by the other
fails:Array#concat is not infected untrustedness by the other
fails:Array#concat returns the array itself
1 change: 0 additions & 1 deletion spec/truffle/tags/core/array/flatten_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/array/initialize_copy_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/array/replace_tags.txt

This file was deleted.

5 changes: 0 additions & 5 deletions spec/truffle/tags/core/random/equal_value_tags.txt

This file was deleted.

8 changes: 0 additions & 8 deletions spec/truffle/tags/core/random/new_tags.txt

This file was deleted.

16 changes: 1 addition & 15 deletions spec/truffle/tags/core/random/rand_tags.txt
Original file line number Diff line number Diff line change
@@ -7,29 +7,15 @@ fails:Random.rand returns an Integer >= 0 if an Integer argument is passed
fails:Random.rand returns an Integer < the max argument if an Integer argument is passed
fails:Random.rand returns the same sequence for a given seed if an Integer argument is passed
fails:Random.rand coerces arguments to Integers with #to_int
fails:Random#rand with Fixnum returns an Integer
fails:Random#rand with Fixnum returns a Fixnum greater than or equal to 0
fails:Random#rand with Fixnum returns a Fixnum less than the argument
fails:Random#rand with Fixnum returns the same sequence for a given seed
fails:Random#rand with Fixnum eventually returns all possible values
fails:Random#rand with Fixnum raises an ArgumentError when the argument is 0
fails:Random#rand with Fixnum raises an ArgumentError when the argument is negative
fails:Random#rand with Bignum typically returns a Bignum
fails:Random#rand with Bignum returns a Bignum greater than or equal to 0
fails:Random#rand with Bignum returns a Bignum less than the argument
fails:Random#rand with Bignum returns the same sequence for a given seed
fails:Random#rand with Bignum raises an ArgumentError when the argument is negative
fails:Random#rand with Float returns a Float
fails:Random#rand with Float returns a Float greater than or equal to 0.0
fails:Random#rand with Float returns a Float less than the argument
fails:Random#rand with Float returns the same sequence for a given seed
fails:Random#rand with Float raises an ArgumentError when the argument is negative
fails:Random#rand with Range returns an element from the Range
fails:Random#rand with Fixnum returns the same sequence for a given seed
fails:Random#rand with Range returns an object that is a member of the Range
fails:Random#rand with Range works with inclusive ranges
fails:Random#rand with Range works with exclusive ranges
fails:Random#rand with Range returns the same sequence for a given seed
fails:Random#rand with Range eventually returns all possible values
fails:Random#rand with Range considers Integers as Floats if one end point is a float
fails:Random#rand with Range raises an ArgumentError when the startpoint lacks #+ and #- methods
fails:Random#rand with Range raises an ArgumentError when the endpoint lacks #+ and #- methods
5 changes: 0 additions & 5 deletions spec/truffle/tags/core/random/seed_tags.txt

This file was deleted.

7 changes: 0 additions & 7 deletions spec/truffle/tags/core/thread/join_tags.txt

This file was deleted.

1 change: 0 additions & 1 deletion spec/truffle/tags/core/thread/main_tags.txt

This file was deleted.

16 changes: 16 additions & 0 deletions tool/truffle-findbugs-exclude.xml
Original file line number Diff line number Diff line change
@@ -74,4 +74,20 @@
<Class name="org.jruby.truffle.runtime.subsystems.SimpleShell" />
<Bug pattern="DM_EXIT" />
</Match>
<Match>
<Class name="org.jruby.truffle.nodes.debug.AssertConstantNode" />
<Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY" />
</Match>
<Match>
<Class name="org.jruby.truffle.nodes.debug.AssertNotCompiledNode" />
<Bug pattern="VO_VOLATILE_REFERENCE_TO_ARRAY" />
</Match>
<Match>
<Class name="org.jruby.truffle.nodes.debug.AssertConstantNode" />
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
</Match>
<Match>
<Class name="org.jruby.truffle.nodes.debug.AssertNotCompiledNode" />
<Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD" />
</Match>
</FindBugsFilter>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.jruby.truffle.nodes.coerce;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.frame.VirtualFrame;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.truffle.nodes.RubyNode;
import org.jruby.truffle.nodes.dispatch.CallDispatchHeadNode;
import org.jruby.truffle.nodes.dispatch.DispatchHeadNodeFactory;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.control.RaiseException;
import org.jruby.truffle.runtime.core.RubyArray;


@NodeChild(value = "child", type = RubyNode.class)
public abstract class ToAryNode extends RubyNode {

@Child private CallDispatchHeadNode toAryNode;

public ToAryNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public ToAryNode(ToAryNode prev) {
super(prev);
}

@Specialization
public RubyArray coerceRubyArray(RubyArray rubyArray) {
return rubyArray;
}

@Specialization(guards = "!isRubyArray(object)")
public RubyArray coerceObject(VirtualFrame frame, Object object) {
notDesignedForCompilation();

if (toAryNode == null) {
CompilerDirectives.transferToInterpreter();
toAryNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

final Object coerced;

try {
coerced = toAryNode.call(frame, object, "to_ary", null);
} catch (RaiseException e) {
if (e.getRubyException().getLogicalClass() == getContext().getCoreLibrary().getNoMethodErrorClass()) {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().typeErrorNoImplicitConversion(object, "Array", this));
} else {
throw e;
}
}
if (coerced instanceof RubyArray) {
return (RubyArray) coerced;
} else {
CompilerDirectives.transferToInterpreter();

throw new RaiseException(
getContext().getCoreLibrary().typeErrorBadCoercion(object, "Array", "to_ary", coerced, this));
}
}
}
34 changes: 31 additions & 3 deletions truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java
Original file line number Diff line number Diff line change
@@ -31,6 +31,7 @@
import org.jruby.truffle.nodes.RubyRootNode;
import org.jruby.truffle.nodes.array.*;
import org.jruby.truffle.nodes.coerce.ToIntNode;
import org.jruby.truffle.nodes.coerce.ToAryNodeFactory;
import org.jruby.truffle.nodes.coerce.ToIntNodeFactory;
import org.jruby.truffle.nodes.dispatch.*;
import org.jruby.truffle.nodes.methods.arguments.MissingArgumentBehaviour;
@@ -598,7 +599,12 @@ public Object compactObjects(RubyArray array) {
}

@CoreMethod(names = "concat", required = 1, raiseIfFrozenSelf = true)
public abstract static class ConcatNode extends ArrayCoreMethodNode {
@NodeChildren({
@NodeChild(value = "array"),
@NodeChild(value = "other")
})
@ImportStatic(ArrayGuards.class)
public abstract static class ConcatNode extends RubyNode {

public ConcatNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -608,6 +614,10 @@ public ConcatNode(ConcatNode prev) {
super(prev);
}

@CreateCast("other") public RubyNode coerceOtherToAry(RubyNode other) {
return ToAryNodeFactory.create(getContext(), getSourceSection(), other);
}

@Specialization(guards = "areBothNull(array, other)")
public RubyArray concatNull(RubyArray array, RubyArray other) {
return array;
@@ -1236,7 +1246,12 @@ public RubyArray initialize(RubyArray array, RubyArray copy, UndefinedPlaceholde
}

@CoreMethod(names = "initialize_copy", visibility = Visibility.PRIVATE, required = 1, raiseIfFrozenSelf = true)
public abstract static class InitializeCopyNode extends ArrayCoreMethodNode {
@NodeChildren({
@NodeChild(value = "self"),
@NodeChild(value = "from")
})
@ImportStatic(ArrayGuards.class)
public abstract static class InitializeCopyNode extends RubyNode {
// TODO(cs): what about allocationSite ?

public InitializeCopyNode(RubyContext context, SourceSection sourceSection) {
@@ -1247,6 +1262,10 @@ public InitializeCopyNode(InitializeCopyNode prev) {
super(prev);
}

@CreateCast("from") public RubyNode coerceOtherToAry(RubyNode other) {
return ToAryNodeFactory.create(getContext(), getSourceSection(), other);
}

@Specialization(guards = "isOtherNull(self, from)")
public RubyArray initializeCopyNull(RubyArray self, RubyArray from) {
if (self == from) {
@@ -2657,7 +2676,12 @@ public Object rejectInPlaceObject(VirtualFrame frame, RubyArray array, RubyProc
}

@CoreMethod(names = "replace", required = 1, raiseIfFrozenSelf = true)
public abstract static class ReplaceNode extends ArrayCoreMethodNode {
@NodeChildren({
@NodeChild(value = "array"),
@NodeChild(value = "other")
})
@ImportStatic(ArrayGuards.class)
public abstract static class ReplaceNode extends RubyNode {

public ReplaceNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -2667,6 +2691,10 @@ public ReplaceNode(ReplaceNode prev) {
super(prev);
}

@CreateCast("other") public RubyNode coerceOtherToAry(RubyNode index) {
return ToAryNodeFactory.create(getContext(), getSourceSection(), index);
}

@Specialization(guards = "isOtherNull(array, other)")
public RubyArray replace(RubyArray array, RubyArray other) {
notDesignedForCompilation();
Original file line number Diff line number Diff line change
@@ -6,6 +6,21 @@
* Eclipse Public License version 1.0
* GNU General Public License version 2
* GNU Lesser General Public License version 2.1
*
* Contains code modified from JRuby's RubyString.java
*
* Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
* Copyright (C) 2001-2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
* Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
* Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
* Copyright (C) 2002-2006 Thomas E Enebo <enebo@acm.org>
* Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
* Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
* Copyright (C) 2005 Tim Azzopardi <tim@tigerfive.com>
* Copyright (C) 2006 Miguel Covarrubias <mlcovarrubias@gmail.com>
* Copyright (C) 2006 Ola Bini <ola@ologix.com>
* Copyright (C) 2007 Nick Sieger <nicksieger@gmail.com>
*
*/
package org.jruby.truffle.nodes.core;

@@ -1707,23 +1722,77 @@ public RubyString succBang(RubyString string) {
}
}

@CoreMethod(names = "sum")
// String#sum is in Java because without OSR we can't warm up the Rubinius implementation

@CoreMethod(names = "sum", optional = 1)
public abstract static class SumNode extends CoreMethodNode {

@Child private CallDispatchHeadNode addNode;
@Child private CallDispatchHeadNode subNode;
@Child private CallDispatchHeadNode shiftNode;
@Child private CallDispatchHeadNode andNode;

public SumNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
addNode = DispatchHeadNodeFactory.createMethodCall(context);
subNode = DispatchHeadNodeFactory.createMethodCall(context);
shiftNode = DispatchHeadNodeFactory.createMethodCall(context);
andNode = DispatchHeadNodeFactory.createMethodCall(context);
}

public SumNode(SumNode prev) {
super(prev);
addNode = prev.addNode;
subNode = prev.subNode;
shiftNode = prev.shiftNode;
andNode = prev.andNode;
}

@Specialization
public int sum(RubyString string) {
notDesignedForCompilation();
public Object sum(VirtualFrame frame, RubyString string, int bits) {
return sum(frame, string, (long) bits);
}

@Specialization
public Object sum(VirtualFrame frame, RubyString string, long bits) {
// Copied from JRuby

return (int) getContext().toTruffle(getContext().toJRuby(string).sum(getContext().getRuntime().getCurrentContext()));
final byte[] bytes = string.getByteList().getUnsafeBytes();
int p = string.getByteList().getBegin();
final int len = string.getByteList().getRealSize();
final int end = p + len;

if (bits >= 8 * 8) { // long size * bits in byte
Object sum = 0;
while (p < end) {
//modifyCheck(bytes, len);
sum = addNode.call(frame, sum, "+", null, bytes[p++] & 0xff);
}
if (bits != 0) {
final Object mod = shiftNode.call(frame, 1, "<<", null, bits);
sum = andNode.call(frame, sum, "&", null, subNode.call(frame, mod, "-", null, 1));
}
return sum;
} else {
long sum = 0;
while (p < end) {
//modifyCheck(bytes, len);
sum += bytes[p++] & 0xff;
}
return bits == 0 ? sum : sum & (1L << bits) - 1L;
}
}

@Specialization
public Object sum(VirtualFrame frame, RubyString string, UndefinedPlaceholder bits) {
return sum(frame, string, 16);
}

@Specialization(guards = {"!isInteger(bits)", "!isLong(bits)", "!isUndefinedPlaceholder(bits)"})
public Object sum(VirtualFrame frame, RubyString string, Object bits) {
return ruby(frame, "sum Rubinius::Type.coerce_to(bits, Fixnum, :to_int)", "bits", bits);
}

}

@CoreMethod(names = "to_f")
Original file line number Diff line number Diff line change
@@ -148,19 +148,51 @@ public JoinNode(JoinNode prev) {
}

@Specialization
public RubyThread join(RubyThread self, UndefinedPlaceholder timeout) {
public RubyThread join(RubyThread thread, UndefinedPlaceholder timeout) {
notDesignedForCompilation();

self.join();
return self;
thread.join();
return thread;
}

@Specialization
public RubyThread join(RubyThread self, int timeout) {
public Object join(RubyThread thread, int timeout) {
notDesignedForCompilation();

self.join(timeout);
return self;
return joinMillis(thread, timeout * 1000);
}

@Specialization
public Object join(RubyThread thread, double timeout) {
notDesignedForCompilation();

return joinMillis(thread, (int) (timeout * 1000.0));
}

private Object joinMillis(RubyThread self, int timeoutInMillis) {
if (self.join(timeoutInMillis)) {
return self;
} else {
return getContext().getCoreLibrary().getNilObject();
}
}

}

@CoreMethod(names = "main", onSingleton = true)
public abstract static class MainNode extends CoreMethodNode {

public MainNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public MainNode(MainNode prev) {
super(prev);
}

@Specialization
public RubyThread main() {
return getContext().getThreadManager().getRootThread();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package org.jruby.truffle.nodes.rubinius;

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.dsl.Specialization;
import com.oracle.truffle.api.source.SourceSection;
import org.jruby.Ruby;
import org.jruby.RubyFixnum;
import org.jruby.RubyNumeric;
import org.jruby.RubyRandom;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.truffle.runtime.RubyContext;
import org.jruby.truffle.runtime.core.RubyBasicObject;
import org.jruby.truffle.runtime.core.RubyBignum;

import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;

/**
* Rubinius primitives associated with the Ruby {@code Random} class.
*/

public abstract class RandomPrimitiveNodes {

@RubiniusPrimitive(name = "randomizer_seed")
public static abstract class RandomizerSeedPrimitiveNode extends RubiniusPrimitiveNode {

public RandomizerSeedPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public RandomizerSeedPrimitiveNode(RandomizerSeedPrimitiveNode prev) {
super(prev);
}

@Specialization
public long randomizerSeed(RubyBasicObject random) {
notDesignedForCompilation();

return System.currentTimeMillis();
}

}

@RubiniusPrimitive(name = "randomizer_rand_float")
public static abstract class RandomizerRandFloatPrimitiveNode extends RubiniusPrimitiveNode {

public RandomizerRandFloatPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public RandomizerRandFloatPrimitiveNode(RandomizerRandFloatPrimitiveNode prev) {
super(prev);
}

@Specialization
public double randomizerRandFloat(RubyBasicObject random) {
notDesignedForCompilation();

return Math.random();
}

}

@RubiniusPrimitive(name = "randomizer_rand_int")
public static abstract class RandomizerRandIntPrimitiveNode extends RubiniusPrimitiveNode {

public RandomizerRandIntPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public RandomizerRandIntPrimitiveNode(RandomizerRandIntPrimitiveNode prev) {
super(prev);
}

@Specialization
public long randomizerRandInt(RubyBasicObject random, Integer limit) {
notDesignedForCompilation();

return RandomPrimitiveHelper.randomInt(getContext().getRuntime().getCurrentContext().getRuntime(), limit);
}

@Specialization
public long randomizerRandInt(RubyBasicObject random, Long limit) {
notDesignedForCompilation();

return RandomPrimitiveHelper.randomInt(getContext().getRuntime().getCurrentContext().getRuntime(), limit);
}
}

@RubiniusPrimitive(name = "randomizer_gen_seed")
public static abstract class RandomizerGenSeedPrimitiveNode extends RubiniusPrimitiveNode {

public RandomizerGenSeedPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}

public RandomizerGenSeedPrimitiveNode(RandomizerGenSeedPrimitiveNode prev) {
super(prev);
}

@Specialization
public RubyBignum randomizerGenSeed(RubyBasicObject random) {
notDesignedForCompilation();

BigInteger integer = RandomPrimitiveHelper.randomSeed(getContext().getRuntime().getCurrentContext().getRuntime());
return new RubyBignum(getContext().getCoreLibrary().getBignumClass(), integer);
}
}

static class RandomPrimitiveHelper {

@CompilerDirectives.TruffleBoundary
public static BigInteger randomSeed(Ruby context) {
return RubyRandom.randomSeed(context).getBigIntegerValue();
}

@CompilerDirectives.TruffleBoundary
public static long randomInt(Ruby context, long limit) {
RubyFixnum fixnum = context.newFixnum(limit);
return generateRandomInt(context, fixnum);
}

@CompilerDirectives.TruffleBoundary
public static long randomInt(Ruby context, int limit) {
RubyFixnum fixnum = context.newFixnum(limit);
return generateRandomInt(context, fixnum);
}

public static long generateRandomInt(Ruby context, RubyFixnum limit) {
IRubyObject params[] = new IRubyObject[1];
params[0] = limit;
RubyNumeric num = (RubyNumeric) RubyRandom.randCommon19(context.getCurrentContext(), null, params);
return num.getLongValue();
}
}
}
Original file line number Diff line number Diff line change
@@ -53,6 +53,7 @@ public static RubiniusPrimitiveManager create() {
nodeFactories.addAll(EncodingPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(RegexpPrimitiveNodesFactory.getFactories());
nodeFactories.addAll(ModulePrimitiveNodesFactory.getFactories());
nodeFactories.addAll(RandomPrimitiveNodesFactory.getFactories());

final Map<String, RubiniusPrimitiveConstructor> primitives = new HashMap<>();

Original file line number Diff line number Diff line change
@@ -43,6 +43,8 @@ public class RubyThread extends RubyBasicObject {

private String name;

/** We use this instead of {@link Thread#join()} since we don't always have a reference
* to the {@link Thread} and we want to handle cases where the Thread did not start yet. */
private final CountDownLatch finished = new CountDownLatch(1);

private volatile Thread thread;
@@ -99,7 +101,7 @@ public void run(final RubyContext context, Node currentNode, String info, Runnab
} catch (RaiseException e) {
exception = e.getRubyException();
} catch (ReturnException e) {
exception = getContext().getCoreLibrary().unexpectedReturn(currentNode);
exception = context.getCoreLibrary().unexpectedReturn(currentNode);
} finally {
cleanup(context);
}
@@ -108,7 +110,7 @@ public void run(final RubyContext context, Node currentNode, String info, Runnab
// Only used by the main thread which cannot easily wrap everything inside a try/finally.
public void cleanup(RubyContext context) {
status = Status.ABORTING;
context.getThreadManager().leaveGlobalLock();
manager.leaveGlobalLock();
context.getSafepointManager().leaveThread();
manager.unregisterThread(this);

@@ -123,7 +125,7 @@ public void setRootThread(Thread thread) {
}

public void join() {
getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
manager.runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
finished.await();
@@ -136,18 +138,19 @@ public Boolean block() throws InterruptedException {
}
}

public void join(final int timeout) {
getContext().getThreadManager().runUntilResult(new BlockingActionWithoutGlobalLock<Boolean>() {
public boolean join(final int timeoutInMillis) {
final boolean joined = manager.runOnce(new BlockingActionWithoutGlobalLock<Boolean>() {
@Override
public Boolean block() throws InterruptedException {
finished.await(timeout, TimeUnit.SECONDS);
return SUCCESS;
return finished.await(timeoutInMillis, TimeUnit.MILLISECONDS);
}
});

if (exception != null) {
if (joined && exception != null) {
throw new RaiseException(exception);
}

return joined;
}

public void interrupt() {
1 change: 1 addition & 0 deletions truffle/src/main/ruby/core.rb
Original file line number Diff line number Diff line change
@@ -72,6 +72,7 @@
require_relative 'core/rubinius/common/throw_catch'
require_relative 'core/rubinius/common/time'
require_relative 'core/rubinius/common/true'
require_relative 'core/rubinius/common/random'

require_relative 'core/rubinius/common/rational'
require_relative 'core/rubinius/common/rationalizer'
2 changes: 1 addition & 1 deletion truffle/src/main/ruby/core/rubinius/api/shims/array.rb
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ class Array

def new_reserved(count)
# TODO CS 6-Feb-15 do we want to reserve space or allow the runtime to optimise for us?
[]
self.class.new(0 , nil)
end

end
2 changes: 2 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/mutex.rb
Original file line number Diff line number Diff line change
@@ -40,6 +40,8 @@ def synchronize
def sleep(duration=undefined)
if duration.kind_of?(Numeric) && duration < 0
raise ArgumentError, "time interval must be positive"
elsif duration == nil
duration = undefined
end

unlock
203 changes: 203 additions & 0 deletions truffle/src/main/ruby/core/rubinius/common/random.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Copyright (c) 2007-2014, Evan Phoenix and contributors
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of Rubinius nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Only part of Rubinius' random.rb
# Extracted from https://github.com/rubinius/rubinius/blob/v2.4.1/kernel/common/random.rb
#
class Rubinius::Randomizer

def initialize
self.seed = generate_seed
end

attr_reader :seed
def seed=(new_seed)
set_seed new_seed
@seed = new_seed
end

def set_seed(new_seed)
Rubinius.primitive :randomizer_seed
raise PrimitiveFailure, "Randomizer#seed primitive failed"
end

def swap_seed(new_seed)
old_seed = self.seed
self.seed = new_seed
old_seed
end

def random(limit)
if undefined.equal?(limit)
random_float
else
if limit.kind_of?(Range)
if time_value?(limit.min)
random_time_range(limit)
else
random_range(limit)
end
elsif limit.kind_of?(Float)
raise ArgumentError, "invalid argument - #{limit}" if limit <= 0
random_float * limit
else
limit_int = Rubinius::Type.coerce_to limit, Integer, :to_int
raise ArgumentError, "invalid argument - #{limit}" if limit_int <= 0

if limit.is_a?(Integer)
random_integer(limit - 1)
elsif limit.respond_to?(:to_f)
random_float * limit
else
random_integer(limit_int - 1)
end
end
end
end

# Generate a random Float, in the range 0...1.0
def random_float
Rubinius.primitive :randomizer_rand_float
raise PrimitiveFailure, "Randomizer#rand_float primitive failed"
end

# Generate a random Integer, in the range 0...limit
def random_integer(limit)
Rubinius.primitive :randomizer_rand_int
raise PrimitiveFailure, "Randomizer#rand_int primitive failed"
end

def random_range(limit)
min, max = limit.max.coerce(limit.min)
diff = max - min
diff += 1 if max.kind_of?(Integer)
random(diff) + min
end

def generate_seed
Rubinius.primitive :randomizer_gen_seed
raise PrimitiveFailure, "Randomizer#gen_seed primitive failed"
end

##
# Returns a random value from a range made out of Time, Date or DateTime
# instances.
#
# @param [Range] range
# @return [Time|Date|DateTime]
#
def random_time_range(range)
min = time_to_float(range.min)
max = time_to_float(range.max)
time = Time.at(random(min..max))

if Object.const_defined?(:DateTime) && range.min.is_a?(DateTime)
time = time.to_datetime
elsif Object.const_defined?(:DateTime) && range.min.is_a?(Date)
time = time.to_date
end

return time
end

##
# Casts a Time/Date/DateTime instance to a Float.
#
# @param [Time|Date|DateTime] input
# @return [Float]
#
def time_to_float(input)
return input.respond_to?(:to_time) ? input.to_time.to_f : input.to_f
end

##
# Checks if a given value is a Time, Date or DateTime object.
#
# @param [Mixed] input
# @return [TrueClass|FalseClass]
#
def time_value?(input)
return input.is_a?(Time) || (Object.const_defined?(:Date) && input.is_a?(Date))
end
end

class Random
def self.new_seed
Thread.current.randomizer.generate_seed
end

def self.srand(seed=undefined)
if undefined.equal? seed
seed = Thread.current.randomizer.generate_seed
end

seed = Rubinius::Type.coerce_to seed, Integer, :to_int
Thread.current.randomizer.swap_seed seed
end

def self.rand(limit=undefined)
Thread.current.randomizer.random(limit)
end

def initialize(seed=undefined)
@randomizer = Rubinius::Randomizer.new
if !undefined.equal?(seed)
@randomizer.swap_seed seed.to_int
end
end

def rand(limit=undefined)
@randomizer.random(limit)
end

def seed
@randomizer.seed
end

def state
@randomizer.seed
end
private :state

def ==(other)
return false unless other.kind_of?(Random)
seed == other.seed
end

# Returns a random binary string.
# The argument size specified the length of the result string.
def bytes(length)
length = Rubinius::Type.coerce_to length, Integer, :to_int
s = ''
i = 0
while i < length
s << @randomizer.random_integer(255).chr
i += 1
end

s
end
end
13 changes: 0 additions & 13 deletions truffle/src/main/ruby/core/rubinius/common/string.rb
Original file line number Diff line number Diff line change
@@ -102,19 +102,6 @@ def slice!(one, two=undefined)
result
end

def sum(bits=16)
bits = Rubinius::Type.coerce_to bits, Fixnum, :to_int
i = -1
sum = 0

sum += @data[i] while (i += 1) < @num_bytes
if bits > 0
sum & ((1 << bits) - 1)
else
sum
end
end

def to_c
Complexifier.new(self).convert
end
4 changes: 0 additions & 4 deletions truffle/src/main/ruby/core/shims.rb
Original file line number Diff line number Diff line change
@@ -9,10 +9,6 @@
# These are implemented just to get other stuff working - we'll go back and
# implement these properly later.

# Here otherwise it causes problems for RubySpec
class Channel
end

class IO
def external_encoding
@external

0 comments on commit 86858cc

Please sign in to comment.