Skip to content

Commit

Permalink
[Truffle] Re-implement String#sum in Java.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisseaton committed Mar 13, 2015
1 parent 613dd63 commit fa10edc
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -1706,23 +1721,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(arguments[1])", "!isLong(arguments[1])", "!isUndefinedPlaceholder(arguments[1])"})
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")
Expand Down
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
Expand Up @@ -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
Expand Down

1 comment on commit fa10edc

@nirvdrum
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the JRuby bits, unless I've really needed to copy them, I've been pushing them out to StringSupport so the code can be shared. I haven't looked in this case, but just a general FYI. I suspect with all the additional call nodes, you needed to copy it.

Please sign in to comment.