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

Commits on Jun 9, 2016

  1. [Truffle] Remove extra bound checks in String#[int].

    * SubtringNode already normalizes and checks the index more efficiently.
    * There is only one special case to handle.
    eregon committed Jun 9, 2016
    Copy the full SHA
    f935c80 View commit details
  2. [Truffle] Add a specialization for String#== on 1-character String.

    * This makes character comparisons much faster.
    * Split the byte length comparison in another specialization for automatic profiling.
    eregon committed Jun 9, 2016
    3
    Copy the full SHA
    3aae3a3 View commit details
  3. Copy the full SHA
    f9bc67d View commit details
Showing with 50 additions and 28 deletions.
  1. +50 −28 truffle/src/main/java/org/jruby/truffle/core/string/StringNodes.java
Original file line number Diff line number Diff line change
@@ -300,6 +300,7 @@ public abstract static class EqualNode extends CoreMethodArrayArgumentsNode {
@Child private StringEqualPrimitiveNode stringEqualNode;
@Child private KernelNodes.RespondToNode respondToNode;
@Child private CallDispatchHeadNode objectEqualNode;
@Child private CheckLayoutNode checkLayoutNode;

public EqualNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
@@ -329,6 +330,15 @@ public boolean equal(VirtualFrame frame, DynamicObject a, Object b) {

return false;
}

protected boolean isRubyString(DynamicObject object) {
if (checkLayoutNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
checkLayoutNode = insert(new CheckLayoutNode());
}

return checkLayoutNode.isString(object);
}
}

@CoreMethod(names = "<=>", required = 1)
@@ -476,16 +486,12 @@ public GetIndexNode(RubyContext context, SourceSection sourceSection) {

@Specialization(guards = "wasNotProvided(length) || isRubiniusUndefined(length)")
public Object getIndex(VirtualFrame frame, DynamicObject string, int index, Object length) {
final Rope rope = rope(string);
final int stringLength = rope.characterLength();
int normalizedIndex = StringOperations.normalizeIndex(stringLength, index);

if (normalizedIndex < 0 || normalizedIndex >= rope.characterLength()) {
// Check for the only difference from str[index, 1]
if (index == rope(string).characterLength()) {
outOfBounds.enter();
return nil();
} else {
return getSubstringNode().execute(frame, string, index, 1);
}
return getSubstringNode().execute(frame, string, index, 1);
}

@Specialization(guards = { "!isRubyRange(index)", "!isRubyRegexp(index)", "!isRubyString(index)", "wasNotProvided(length) || isRubiniusUndefined(length)" })
@@ -3016,21 +3022,18 @@ protected boolean areComparable(DynamicObject first, DynamicObject second,
@ImportStatic(StringGuards.class)
public static abstract class StringEqualPrimitiveNode extends PrimitiveArrayArgumentsNode {

@Child CheckLayoutNode checkLayoutNode;
@Child StringAreComparableNode areComparableNode;

public abstract boolean executeStringEqual(DynamicObject string, DynamicObject other);

@Specialization(guards = {
"isRubyString(other)",
"ropeReferenceEqual(string, other)"
})
public boolean stringEqualsRopeEquals(DynamicObject string, DynamicObject other) {
return true;
}

@Specialization(guards = {
"isRubyString(other)",
"!ropeReferenceEqual(string, other)",
"bytesReferenceEqual(string, other)"
})
@@ -3039,7 +3042,6 @@ public boolean stringEqualsBytesEquals(DynamicObject string, DynamicObject other
}

@Specialization(guards = {
"isRubyString(other)",
"!ropeReferenceEqual(string, other)",
"!bytesReferenceEqual(string, other)",
"!areComparable(string, other)"
@@ -3049,31 +3051,42 @@ public boolean stringEqualNotComparable(DynamicObject string, DynamicObject othe
}

@Specialization(guards = {
"isRubyString(other)",
"!ropeReferenceEqual(string, other)",
"!bytesReferenceEqual(string, other)",
"areComparable(string, other)"
"areComparable(string, other)",
"byteLength(string) != byteLength(other)"
})
public boolean equal(DynamicObject string, DynamicObject other,
@Cached("createBinaryProfile()") ConditionProfile differentSizeProfile) {

final Rope a = Layouts.STRING.getRope(string);
final Rope b = Layouts.STRING.getRope(other);
public boolean stringEqualDifferentLength(DynamicObject string, DynamicObject other) {
return false;
}

if (differentSizeProfile.profile(a.byteLength() != b.byteLength())) {
return false;
}
@Specialization(guards = {
"!ropeReferenceEqual(string, other)",
"!bytesReferenceEqual(string, other)",
"areComparable(string, other)",
"byteLength(string) == 1",
"byteLength(other) == 1",
"hasRawBytes(string)",
"hasRawBytes(other)"
})
public boolean equalCharacters(DynamicObject string, DynamicObject other) {
final Rope a = rope(string);
final Rope b = rope(other);

return a.equals(b);
return a.getRawBytes()[0] == b.getRawBytes()[0];
}

protected boolean isRubyString(DynamicObject object) {
if (checkLayoutNode == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
checkLayoutNode = insert(new CheckLayoutNode());
}
@Specialization(guards = {
"!ropeReferenceEqual(string, other)",
"!bytesReferenceEqual(string, other)",
"areComparable(string, other)",
"byteLength(string) == byteLength(other)"
}, contains = "equalCharacters")
public boolean fullEqual(DynamicObject string, DynamicObject other) {
final Rope a = rope(string);
final Rope b = rope(other);

return checkLayoutNode.isString(object);
return a.equals(b);
}

protected boolean areComparable(DynamicObject first, DynamicObject second) {
@@ -3098,6 +3111,15 @@ protected static boolean bytesReferenceEqual(DynamicObject first, DynamicObject
firstRope.getRawBytes() != null &&
firstRope.getRawBytes() == secondRope.getRawBytes();
}

protected static int byteLength(DynamicObject string) {
return rope(string).byteLength();
}

protected static boolean hasRawBytes(DynamicObject string) {
return rope(string).getRawBytes() != null;
}

}

@Primitive(name = "string_find_character")