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: 1d5230886635
Choose a base ref
...
head repository: jruby/jruby
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: e3c2107f1a13
Choose a head ref
  • 3 commits
  • 2 files changed
  • 1 contributor

Commits on Dec 21, 2016

  1. [Truffle] Consolidated two nodes that basically did the same thing, w…

    …ith slight differences.
    nirvdrum committed Dec 21, 2016
    Copy the full SHA
    7349e2d View commit details
  2. Copy the full SHA
    15f7d64 View commit details
  3. Copy the full SHA
    e3c2107 View commit details
Showing with 45 additions and 156 deletions.
  1. +19 −156 truffle/src/main/java/org/jruby/truffle/core/string/StringNodes.java
  2. +26 −0 truffle/src/main/ruby/core/string.rb
175 changes: 19 additions & 156 deletions truffle/src/main/java/org/jruby/truffle/core/string/StringNodes.java
Original file line number Diff line number Diff line change
@@ -1319,114 +1319,6 @@ public Object initializeCopy(DynamicObject self, DynamicObject from,

}

@CoreMethod(names = "insert", required = 2, lowerFixnum = 1, raiseIfFrozenSelf = true)
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "string"),
@NodeChild(type = RubyNode.class, value = "index"),
@NodeChild(type = RubyNode.class, value = "otherString")
})
public abstract static class InsertNode extends CoreMethodNode {

@Child private CallDispatchHeadNode appendNode;
@Child private CharacterByteIndexNode characterByteIndexNode;
@Child private CheckCharacterIndexNode checkCharacterIndexNode;
@Child private EncodingNodes.CheckEncodingNode checkEncodingNode;
@Child private RopeNodes.MakeConcatNode prependMakeConcatNode;
@Child private RopeNodes.MakeConcatNode leftMakeConcatNode;
@Child private RopeNodes.MakeConcatNode rightMakeConcatNode;
@Child private RopeNodes.MakeSubstringNode leftMakeSubstringNode;
@Child private RopeNodes.MakeSubstringNode rightMakeSubstringNode;
@Child private TaintResultNode taintResultNode;

public InsertNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
characterByteIndexNode = StringNodesFactory.CharacterByteIndexNodeFactory.create(new RubyNode[] {});
checkEncodingNode = EncodingNodesFactory.CheckEncodingNodeGen.create(context, sourceSection, null, null);
checkCharacterIndexNode = StringNodesFactory.CheckCharacterIndexNodeGen.create(null, null);
leftMakeConcatNode = RopeNodesFactory.MakeConcatNodeGen.create(null, null, null);
rightMakeConcatNode = RopeNodesFactory.MakeConcatNodeGen.create(null, null, null);
leftMakeSubstringNode = RopeNodesFactory.MakeSubstringNodeGen.create(null, null, null);
rightMakeSubstringNode = RopeNodesFactory.MakeSubstringNodeGen.create(null, null, null);
taintResultNode = new TaintResultNode(context, sourceSection);
}

@CreateCast("index") public RubyNode coerceIndexToInt(RubyNode index) {
return ToIntNodeGen.create(index);
}

@CreateCast("otherString") public RubyNode coerceOtherToString(RubyNode other) {
return ToStrNodeGen.create(null, null, other);
}

@Specialization(guards = { "indexAtStartBound(index)", "isRubyString(other)" })
public Object insertPrepend(DynamicObject string, int index, DynamicObject other) {
final Rope left = rope(other);
final Rope right = rope(string);

final Encoding compatibleEncoding = checkEncodingNode.executeCheckEncoding(string, other);

if (prependMakeConcatNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
prependMakeConcatNode = insert(RopeNodesFactory.MakeConcatNodeGen.create(null, null, null));
}

StringOperations.setRope(string, prependMakeConcatNode.executeMake(left, right, compatibleEncoding));

return taintResultNode.maybeTaint(other, string);
}

@Specialization(guards = { "indexAtEndBound(index)", "isRubyString(other)" })
public Object insertAppend(VirtualFrame frame, DynamicObject string, int index, DynamicObject other) {
if (appendNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
appendNode = insert(DispatchHeadNodeFactory.createMethodCall(getContext()));
}

appendNode.call(frame, string, "append", other);

return taintResultNode.maybeTaint(other, string);
}

@Specialization(guards = { "!indexAtEitherBounds(index)", "isRubyString(other)" })
public Object insert(VirtualFrame frame, DynamicObject string, int index, DynamicObject other,
@Cached("createBinaryProfile()") ConditionProfile negativeIndexProfile) {
if (negativeIndexProfile.profile(index < 0)) {
// Incrementing first seems weird, but MRI does it and it's significant because it uses the modified
// index value in its error messages. This seems wrong, but we should be compatible.
index++;
}

final Rope source = rope(string);
final Rope insert = rope(other);
final Encoding compatibleEncoding = checkEncodingNode.executeCheckEncoding(string, other);

final int normalizedIndex = checkCharacterIndexNode.executeCheck(source, index);
final int byteIndex = characterByteIndexNode.executeInt(frame, string, normalizedIndex, 0);

final Rope splitLeft = leftMakeSubstringNode.executeMake(source, 0, byteIndex);
final Rope splitRight = rightMakeSubstringNode.executeMake(source, byteIndex, source.byteLength() - byteIndex);
final Rope joinedLeft = leftMakeConcatNode.executeMake(splitLeft, insert, compatibleEncoding);
final Rope joinedRight = rightMakeConcatNode.executeMake(joinedLeft, splitRight, compatibleEncoding);

StringOperations.setRope(string, joinedRight);

return taintResultNode.maybeTaint(other, string);
}

protected boolean indexAtStartBound(int index) {
return index == 0;
}

protected boolean indexAtEndBound(int index) {
// TODO (nirvdrum 14-Jan-16) Now that we know the character length of the string, we can update the check for positive numbers as well.
return index == -1;
}

protected boolean indexAtEitherBounds(int index) {
return indexAtStartBound(index) || indexAtEndBound(index);
}
}

@CoreMethod(names = "lstrip!", raiseIfFrozenSelf = true)
@ImportStatic(StringGuards.class)
public abstract static class LstripBangNode extends CoreMethodArrayArgumentsNode {
@@ -1875,7 +1767,7 @@ private int codePointX(Encoding enc, byte[] bytes, int p, int end) {
@ImportStatic(StringGuards.class)
public abstract static class SetByteNode extends CoreMethodNode {

@Child private CheckByteIndexNode checkByteIndexNode;
@Child private CheckIndexNode checkIndexNode;
@Child private RopeNodes.MakeConcatNode composedMakeConcatNode;
@Child private RopeNodes.MakeConcatNode middleMakeConcatNode;
@Child private RopeNodes.MakeLeafRopeNode makeLeafRopeNode;
@@ -1884,7 +1776,7 @@ public abstract static class SetByteNode extends CoreMethodNode {

public SetByteNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
checkByteIndexNode = StringNodesFactory.CheckByteIndexNodeGen.create(null, null);
checkIndexNode = StringNodesFactory.CheckIndexNodeGen.create(null, null);
composedMakeConcatNode = RopeNodesFactory.MakeConcatNodeGen.create(null, null, null);
middleMakeConcatNode = RopeNodesFactory.MakeConcatNodeGen.create(null, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(null, null, null, null);
@@ -1905,7 +1797,7 @@ public SetByteNode(RubyContext context, SourceSection sourceSection) {
@Specialization(guards = "!isRopeBuffer(string)")
public int setByte(DynamicObject string, int index, int value) {
final Rope rope = rope(string);
final int normalizedIndex = checkByteIndexNode.executeCheck(rope, index);
final int normalizedIndex = checkIndexNode.executeCheck(index, rope.byteLength());

final Rope left = leftMakeSubstringNode.executeMake(rope, 0, normalizedIndex);
final Rope right = rightMakeSubstringNode.executeMake(rope, normalizedIndex + 1, rope.byteLength() - normalizedIndex - 1);
@@ -1920,7 +1812,7 @@ public int setByte(DynamicObject string, int index, int value) {
@Specialization(guards = "isRopeBuffer(string)")
public int setByteRopeBuffer(DynamicObject string, int index, int value) {
final RopeBuffer rope = (RopeBuffer) rope(string);
final int normalizedIndex = checkByteIndexNode.executeCheck(rope, index);
final int normalizedIndex = checkIndexNode.executeCheck(index, rope.byteLength());

rope.getByteList().set(normalizedIndex, value);

@@ -1929,63 +1821,30 @@ public int setByteRopeBuffer(DynamicObject string, int index, int value) {

}

@NodeChildren({ @NodeChild("string"), @NodeChild("index") })
public static abstract class CheckByteIndexNode extends RubyNode {
@NodeChildren({ @NodeChild("index"), @NodeChild("length") })
public static abstract class CheckIndexNode extends RubyNode {

public abstract int executeCheck(Rope string, int index);
public abstract int executeCheck(int index, int length);

@Specialization
protected int checkIndex(Rope rope, int byteIndex,
protected int checkIndex(int index, int length,
@Cached("createBinaryProfile()") ConditionProfile negativeIndexProfile,
@Cached("create()") BranchProfile errorProfile) {
final int byteLength = rope.byteLength();

if (byteIndex >= byteLength) {
errorProfile.enter();
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(byteIndex, this));
}

if (negativeIndexProfile.profile(byteIndex < 0)) {
if (-byteIndex > byteLength) {
errorProfile.enter();
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(byteIndex, this));
}

byteIndex += byteLength;
}

return byteIndex;
}

}

@ImportStatic(StringGuards.class)
@NodeChildren({ @NodeChild("string"), @NodeChild("index") })
public static abstract class CheckCharacterIndexNode extends RubyNode {

public abstract int executeCheck(Rope string, int index);

@Specialization
protected int check(Rope rope, int characterIndex,
@Cached("createBinaryProfile()") ConditionProfile negativeIndexProfile,
@Cached("create()") BranchProfile errorProfile) {
final int characterLength = rope.characterLength();

if (characterIndex > characterLength) {
if (index >= length) {
errorProfile.enter();
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(characterIndex, this));
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(index, this));
}

if (negativeIndexProfile.profile(characterIndex < 0)) {
if (-characterIndex > characterLength) {
if (negativeIndexProfile.profile(index < 0)) {
if (-index > length) {
errorProfile.enter();
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(characterIndex, this));
throw new RaiseException(getContext().getCoreExceptions().indexErrorOutOfString(index, this));
}

characterIndex += characterLength;
index += length;
}

return characterIndex;
return index;
}

}
@@ -2746,6 +2605,10 @@ public static abstract class StringAppendPrimitiveNode extends PrimitiveArrayArg
@Child private EncodingNodes.CheckEncodingNode checkEncodingNode;
@Child private RopeNodes.MakeConcatNode makeConcatNode;

public static StringAppendPrimitiveNode create() {
return StringNodesFactory.StringAppendPrimitiveNodeFactory.create(null, null, null);
}

public StringAppendPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
checkEncodingNode = EncodingNodesFactory.CheckEncodingNodeGen.create(context, sourceSection, null, null);
26 changes: 26 additions & 0 deletions truffle/src/main/ruby/core/string.rb
Original file line number Diff line number Diff line change
@@ -1634,6 +1634,32 @@ def start_with?(*prefixes)
false
end

def insert(index, other)
other = StringValue(other)

index = Rubinius::Type.coerce_to index, Fixnum, :to_int
index = length + 1 + index if index < 0

if index > length or index < 0 then
raise IndexError, "index #{index} out of string"
end

Truffle.check_frozen

if index == 0
replace(other + self)
elsif index == length
self << other
else
left = self[0...index]
right = self[index..-1]
replace(left + other + right)
end

Rubinius::Type.infect self, other
self
end

def %(args)
if args.is_a? Hash
sprintf(self, args)