Skip to content
Permalink

Comparing changes

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

Open a pull request

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

Commits on Apr 11, 2016

  1. Copy the full SHA
    579d882 View commit details
  2. [Truffle] Moved RepeatingRope construction out to nodes.

    Also added bounds detection to check if the repeating rope would be longer than an int.
    nirvdrum committed Apr 11, 2016
    Copy the full SHA
    56de066 View commit details
81 changes: 81 additions & 0 deletions truffle/src/main/java/org/jruby/truffle/core/rope/RopeNodes.java
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@

import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.ExactMath;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
@@ -30,9 +31,12 @@
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.RubyNode;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.util.ByteList;
import org.jruby.util.StringSupport;

import java.util.Arrays;

import static org.jruby.truffle.core.rope.CodeRange.CR_7BIT;
import static org.jruby.truffle.core.rope.CodeRange.CR_BROKEN;
import static org.jruby.truffle.core.rope.CodeRange.CR_VALID;
@@ -241,6 +245,13 @@ public MakeConcatNode(RubyContext context, SourceSection sourceSection) {
@Specialization(guards = "isMutableRope(left)")
public Rope concatMutableRope(MutableRope left, Rope right, Encoding encoding,
@Cached("createBinaryProfile()") ConditionProfile differentEncodingProfile) {
try {
ExactMath.addExact(left.byteLength(), right.byteLength());
} catch(ArithmeticException e) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("Result of string concatenation exceeds the system maximum string length", this));
}

final ByteList byteList = left.getByteList();

byteList.append(right.getBytes());
@@ -257,6 +268,13 @@ public Rope concat(Rope left, Rope right, Encoding encoding,
@Cached("createBinaryProfile()") ConditionProfile sameCodeRangeProfile,
@Cached("createBinaryProfile()") ConditionProfile brokenCodeRangeProfile,
@Cached("createBinaryProfile()") ConditionProfile isLeftSingleByteOptimizableProfile) {
try {
ExactMath.addExact(left.byteLength(), right.byteLength());
} catch(ArithmeticException e) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("Result of string concatenation exceeds the system maximum string length", this));
}

int depth = depth(left, right);
/*if (depth >= 10) {
System.out.println("ConcatRope depth: " + depth);
@@ -488,6 +506,65 @@ protected static boolean isFixedWidth(Encoding encoding) {

}

@NodeChildren({
@NodeChild(type = RubyNode.class, value = "base"),
@NodeChild(type = RubyNode.class, value = "times")
})
public abstract static class MakeRepeatingNode extends RubyNode {

public static MakeRepeatingNode create(RubyContext context, SourceSection sourceSection) {
return RopeNodesFactory.MakeRepeatingNodeGen.create(context, sourceSection, null, null);
}

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

public abstract Rope executeMake(Rope base, int times);

@Specialization(guards = "times == 0")
public Rope repeatZero(Rope base, int times,
@Cached("create(getContext(), getSourceSection())") WithEncodingNode withEncodingNode) {
return withEncodingNode.executeWithEncoding(RopeConstants.EMPTY_UTF8_ROPE, base.getEncoding(), CodeRange.CR_7BIT);
}

@Specialization(guards = "times == 1")
public Rope repeatOne(Rope base, int times,
@Cached("create(getContext(), getSourceSection())") WithEncodingNode withEncodingNode) {
return base;
}

@Specialization(guards = { "isSingleByteString(base)", "times > 1" })
@TruffleBoundary
public Rope multiplySingleByteString(Rope base, int times,
@Cached("create(getContext(), getSourceSection())") MakeLeafRopeNode makeLeafRopeNode) {
final byte filler = base.getBytes()[0];

byte[] buffer = new byte[times];
Arrays.fill(buffer, filler);

return makeLeafRopeNode.executeMake(buffer, base.getEncoding(), base.getCodeRange(), times);
}

@Specialization(guards = { "!isSingleByteString(base)", "times > 1" })
public Rope repeat(Rope base, int times) {
try {
ExactMath.multiplyExact(base.byteLength(), times);
} catch (ArithmeticException e) {
CompilerDirectives.transferToInterpreter();
throw new RaiseException(getContext().getCoreLibrary().argumentError("Result of repeating string exceeds the system maximum string length", this));
}

return new RepeatingRope(base, times);
}

protected static boolean isSingleByteString(Rope rope) {
return rope.byteLength() == 1;
}

}


@NodeChildren({
@NodeChild(type = RubyNode.class, value = "rope"),
@NodeChild(type = RubyNode.class, value = "currentLevel"),
@@ -586,6 +663,10 @@ private void printPreamble(int level) {
})
public abstract static class WithEncodingNode extends RubyNode {

public static WithEncodingNode create(RubyContext context, SourceSection sourceSection) {
return RopeNodesFactory.WithEncodingNodeGen.create(context, sourceSection, null, null, null);
}

public WithEncodingNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
}
Original file line number Diff line number Diff line change
@@ -107,7 +107,6 @@

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static org.jruby.truffle.core.string.StringOperations.encoding;
@@ -1364,24 +1363,26 @@ public static abstract class StringPatternPrimitiveNode extends RubiniusPrimitiv

@Child private AllocateObjectNode allocateObjectNode;
@Child private RopeNodes.MakeLeafRopeNode makeLeafRopeNode;
@Child private RopeNodes.MakeRepeatingNode makeRepeatingNode;

public StringPatternPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
allocateObjectNode = AllocateObjectNodeGen.create(context, sourceSection, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null, null);
makeLeafRopeNode = RopeNodes.MakeLeafRopeNode.create(context, sourceSection);
makeRepeatingNode = RopeNodes.MakeRepeatingNode.create(context, sourceSection);
}

@Specialization(guards = "value >= 0")
public DynamicObject stringPatternZero(DynamicObject stringClass, int size, int value) {
final Rope repeatingRope = new RepeatingRope(RopeConstants.ASCII_8BIT_SINGLE_BYTE_ROPES[value], size);
final Rope repeatingRope = makeRepeatingNode.executeMake(RopeConstants.ASCII_8BIT_SINGLE_BYTE_ROPES[value], size);

return allocateObjectNode.allocate(stringClass, repeatingRope, null);
}

@Specialization(guards = { "isRubyString(string)", "patternFitsEvenly(string, size)" })
public DynamicObject stringPatternFitsEvenly(DynamicObject stringClass, int size, DynamicObject string) {
final Rope rope = rope(string);
final Rope repeatingRope = new RepeatingRope(rope, size / rope.byteLength());
final Rope repeatingRope = makeRepeatingNode.executeMake(rope, size / rope.byteLength());

return allocateObjectNode.allocate(stringClass, repeatingRope, null);
}
Original file line number Diff line number Diff line change
@@ -69,11 +69,11 @@
import org.jruby.truffle.core.kernel.KernelNodesFactory;
import org.jruby.truffle.core.numeric.FixnumLowerNodeGen;
import org.jruby.truffle.core.rope.CodeRange;
import org.jruby.truffle.core.rope.RepeatingRope;
import org.jruby.truffle.core.rope.MutableRope;
import org.jruby.truffle.core.rope.Rope;
import org.jruby.truffle.core.rope.RopeConstants;
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodes.MakeRepeatingNode;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.rope.RopeOperations;
import org.jruby.truffle.core.rubinius.StringPrimitiveNodes;
@@ -184,36 +184,12 @@ public DynamicObject multiplyTimesNegative(DynamicObject string, int times) {
throw new RaiseException(coreLibrary().argumentError("negative argument", this));
}

@Specialization(guards = "times == 0")
public DynamicObject multiplyTimesZero(DynamicObject string, int times) {
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), EMPTY_UTF8_ROPE, null);
}

@Specialization(guards = "times == 1")
public DynamicObject multiplyTimesOne(DynamicObject string, int times) {
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), rope(string), null);
}

@Specialization(guards = { "isSingleByteString(string)", "times > 1" })
public DynamicObject multiplySingleByteString(DynamicObject string, int times) {
if (makeLeafRopeNode == null) {
CompilerDirectives.transferToInterpreter();
makeLeafRopeNode = insert(RopeNodesFactory.MakeLeafRopeNodeGen.create(getContext(), getSourceSection(), null, null, null, null));
}

final Rope baseRope = rope(string);
final byte filler = baseRope.getBytes()[0];

byte[] buffer = new byte[times];
Arrays.fill(buffer, filler);
final Rope multipliedRope = makeLeafRopeNode.executeMake(buffer, baseRope.getEncoding(), baseRope.getCodeRange(), times);

return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), multipliedRope, null);
}
@Specialization(guards = "times >= 0")
public DynamicObject multiply(DynamicObject string, int times,
@Cached("create(getContext(), getSourceSection())") MakeRepeatingNode makeRepeatingNode) {
final Rope repeated = makeRepeatingNode.executeMake(rope(string), times);

@Specialization(guards = { "!isSingleByteString(string)", "times > 1" })
public DynamicObject multiply(DynamicObject string, int times) {
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), new RepeatingRope(rope(string), times), null);
return allocateObjectNode.allocate(Layouts.BASIC_OBJECT.getLogicalClass(string), repeated, null);
}

@Specialization(guards = "isRubyBignum(times)")