Skip to content

Commit

Permalink
[Truffle] Updated the make leaf rope nodes to pass along the characte…
Browse files Browse the repository at this point in the history
…r length of the rope if we already have it.
nirvdrum committed Mar 19, 2016

Unverified

This user has not yet uploaded their public signing key.
1 parent 3d3ab2b commit 9dd4e21
Showing 5 changed files with 67 additions and 74 deletions.
Original file line number Diff line number Diff line change
@@ -2393,7 +2393,7 @@ public abstract static class PackNode extends ArrayCoreMethodNode {

public PackNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null, null);
}

@Specialization(guards = {"isRubyString(format)", "ropesEqual(format, cachedFormat)"}, limit = "getCacheLimit()")
@@ -2479,14 +2479,7 @@ private DynamicObject finishPack(int formatLength, PackResult result) {
}


final Rope rope;
if (result.getStringCodeRange() == CodeRange.CR_VALID) {
// TODO (nirvdrum 01-Feb-16): We probably should have a node for creating ropes with a known character length.
rope = new ValidLeafRope(bytes, encoding, result.getStringLength());
} else {
rope = makeLeafRopeNode.executeMake(bytes, encoding, result.getStringCodeRange());
}

final Rope rope = makeLeafRopeNode.executeMake(bytes, encoding, result.getStringCodeRange(), result.getStringLength());
final DynamicObject string = createString(rope);

if (result.isTainted()) {
83 changes: 41 additions & 42 deletions truffle/src/main/java/org/jruby/truffle/core/rope/RopeNodes.java
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.api.dsl.Cached;
import com.oracle.truffle.api.dsl.CreateCast;
import com.oracle.truffle.api.dsl.NodeChild;
import com.oracle.truffle.api.dsl.NodeChildren;
import com.oracle.truffle.api.dsl.Specialization;
@@ -28,6 +29,7 @@
import org.jcodings.specific.USASCIIEncoding;
import org.jcodings.specific.UTF8Encoding;
import org.jruby.truffle.RubyContext;
import org.jruby.truffle.core.numeric.FixnumLowerNodeGen;
import org.jruby.truffle.language.RubyNode;
import org.jruby.util.ByteList;
import org.jruby.util.StringSupport;
@@ -45,6 +47,8 @@ public abstract class RopeNodes {
})
public abstract static class MakeSubstringNode extends RubyNode {

@Child private MakeLeafRopeNode makeLeafRopeNode;

public static MakeSubstringNode create(RubyContext context, SourceSection sourceSection) {
return RopeNodesFactory.MakeSubstringNodeGen.create(context, sourceSection, null, null, null);
}
@@ -188,25 +192,14 @@ private Rope makeSubstringNon7Bit(Rope base, int offset, int byteLength) {
if (getContext().getOptions().ROPE_LAZY_SUBSTRINGS) {
return new SubstringRope(base, offset, byteLength, characterLength, codeRange);
} else {
final byte[] bytes = base.extractRange(offset, byteLength);

switch (codeRange) {
case CR_VALID: {
return new ValidLeafRope(bytes, base.getEncoding(), characterLength);
}

case CR_BROKEN: {
return new InvalidLeafRope(bytes, base.getEncoding());
}
if (makeLeafRopeNode == null) {
CompilerDirectives.transferToInterpreter();
makeLeafRopeNode = insert(RopeNodesFactory.MakeLeafRopeNodeGen.create(getContext(), getSourceSection(), null, null, null, null));
}

case CR_7BIT: {
return new AsciiOnlyLeafRope(bytes, base.getEncoding());
}
final byte[] bytes = base.extractRange(offset, byteLength);

default: {
throw new UnsupportedOperationException("Don't know how to make leaf rope for code range: " + codeRange);
}
}
return makeLeafRopeNode.executeMake(bytes, base.getEncoding(), codeRange, characterLength);
}
}

@@ -273,7 +266,7 @@ public Rope concatLeaves(LeafRope left, LeafRope right, Encoding encoding,
@Cached("createBinaryProfile()") ConditionProfile brokenCodeRangeProfile) {
if (makeLeafRopeNode == null) {
CompilerDirectives.transferToInterpreter();
makeLeafRopeNode = insert(RopeNodesFactory.MakeLeafRopeNodeGen.create(getContext(), getSourceSection(), null, null, null));
makeLeafRopeNode = insert(RopeNodesFactory.MakeLeafRopeNodeGen.create(getContext(), getSourceSection(), null, null, null, null));
}

final byte[] bytes = new byte[left.byteLength() + right.byteLength()];
@@ -282,7 +275,7 @@ public Rope concatLeaves(LeafRope left, LeafRope right, Encoding encoding,

final CodeRange codeRange = commonCodeRange(left.getCodeRange(), right.getCodeRange(), sameCodeRangeProfile, brokenCodeRangeProfile);

return makeLeafRopeNode.executeMake(bytes, encoding, codeRange);
return makeLeafRopeNode.executeMake(bytes, encoding, codeRange, left.characterLength() + right.characterLength());
}

@Specialization(guards = { "!right.isEmpty()", "!isMutableRope(left)", "left.byteLength() >= SHORT_LEAF_BYTESIZE_THRESHOLD", "right.byteLength() < SHORT_LEAF_BYTESIZE_THRESHOLD" })
@@ -381,44 +374,50 @@ protected static boolean isMutableRope(Rope rope) {
@NodeChildren({
@NodeChild(type = RubyNode.class, value = "bytes"),
@NodeChild(type = RubyNode.class, value = "encoding"),
@NodeChild(type = RubyNode.class, value = "codeRange")
@NodeChild(type = RubyNode.class, value = "codeRange"),
@NodeChild(type = RubyNode.class, value = "characterLength")
})
public abstract static class MakeLeafRopeNode extends RubyNode {

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

public abstract LeafRope executeMake(byte[] bytes, Encoding encoding, CodeRange codeRange);
public abstract LeafRope executeMake(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength);

@Specialization(guards = "is7Bit(codeRange)")
public LeafRope makeAsciiOnlyLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange) {
public LeafRope makeAsciiOnlyLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength) {
return new AsciiOnlyLeafRope(bytes, encoding);
}

@Specialization(guards = { "isValid(codeRange)", "isFixedWidth(encoding)" })
public LeafRope makeValidLeafRopeFixedWidthEncoding(byte[] bytes, Encoding encoding, CodeRange codeRange) {
final int characterLength = bytes.length / encoding.minLength();

@Specialization(guards = { "isValid(codeRange)", "wasProvided(characterLength)" })
public LeafRope makeValidLeafRopeWithCharacterLength(byte[] bytes, Encoding encoding, CodeRange codeRange, int characterLength) {
return new ValidLeafRope(bytes, encoding, characterLength);
}

@Specialization(guards = { "isValid(codeRange)", "!isFixedWidth(encoding)" })
public LeafRope makeValidLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange) {
@Specialization(guards = { "isValid(codeRange)", "isFixedWidth(encoding)", "wasNotProvided(characterLength)" })
public LeafRope makeValidLeafRopeFixedWidthEncoding(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength) {
final int calculatedCharacterLength = bytes.length / encoding.minLength();

return new ValidLeafRope(bytes, encoding, calculatedCharacterLength);
}

@Specialization(guards = { "isValid(codeRange)", "!isFixedWidth(encoding)", "wasNotProvided(characterLength)" })
public LeafRope makeValidLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength) {
// Exctracted from StringSupport.strLength.

int characterLength = 0;
int calculatedCharacterLength = 0;
int p = 0;
int e = bytes.length;

while (p < e) {
if (Encoding.isAscii(bytes[p])) {
int q = StringSupport.searchNonAscii(bytes, p, e);
if (q == -1) {
characterLength += (e - p);
calculatedCharacterLength += (e - p);
break;
}
characterLength += q - p;
calculatedCharacterLength += q - p;
p = q;
}
int delta = StringSupport.encFastMBCLen(bytes, p, e, encoding);
@@ -429,19 +428,19 @@ public LeafRope makeValidLeafRope(byte[] bytes, Encoding encoding, CodeRange cod
}

p += delta;
characterLength++;
calculatedCharacterLength++;
}

return new ValidLeafRope(bytes, encoding, characterLength);
return new ValidLeafRope(bytes, encoding, calculatedCharacterLength);
}

@Specialization(guards = "isBroken(codeRange)")
public LeafRope makeInvalidLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange) {
public LeafRope makeInvalidLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength) {
return new InvalidLeafRope(bytes, encoding);
}

@Specialization(guards = { "isUnknown(codeRange)", "isEmpty(bytes)" })
public LeafRope makeUnknownLeafRopeEmpty(byte[] bytes, Encoding encoding, CodeRange codeRange,
public LeafRope makeUnknownLeafRopeEmpty(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength,
@Cached("createBinaryProfile()") ConditionProfile isUTF8,
@Cached("createBinaryProfile()") ConditionProfile isUSAscii,
@Cached("createBinaryProfile()") ConditionProfile isAscii8Bit,
@@ -466,7 +465,7 @@ public LeafRope makeUnknownLeafRopeEmpty(byte[] bytes, Encoding encoding, CodeRa
}

@Specialization(guards = { "isUnknown(codeRange)", "!isEmpty(bytes)", "isBinaryString(encoding)" })
public LeafRope makeUnknownLeafRopeBinary(byte[] bytes, Encoding encoding, CodeRange codeRange,
public LeafRope makeUnknownLeafRopeBinary(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength,
@Cached("createBinaryProfile()") ConditionProfile discovered7BitProfile) {
CodeRange newCodeRange = CR_7BIT;
for (int i = 0; i < bytes.length; i++) {
@@ -484,38 +483,38 @@ public LeafRope makeUnknownLeafRopeBinary(byte[] bytes, Encoding encoding, CodeR
}

@Specialization(guards = { "isUnknown(codeRange)", "!isEmpty(bytes)", "!isBinaryString(encoding)", "isAsciiCompatible(encoding)" })
public LeafRope makeUnknownLeafRopeAsciiCompatible(byte[] bytes, Encoding encoding, CodeRange codeRange,
public LeafRope makeUnknownLeafRopeAsciiCompatible(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength,
@Cached("createBinaryProfile()") ConditionProfile discovered7BitProfile,
@Cached("createBinaryProfile()") ConditionProfile discoveredValidProfile) {
final long packedLengthAndCodeRange = StringSupport.strLengthWithCodeRangeAsciiCompatible(encoding, bytes, 0, bytes.length);
final CodeRange newCodeRange = CodeRange.fromInt(StringSupport.unpackArg(packedLengthAndCodeRange));
final int characterLength = StringSupport.unpackResult(packedLengthAndCodeRange);
final int calculatedCharacterLength = StringSupport.unpackResult(packedLengthAndCodeRange);

if (discovered7BitProfile.profile(newCodeRange == CR_7BIT)) {
return new AsciiOnlyLeafRope(bytes, encoding);
}

if (discoveredValidProfile.profile(newCodeRange == CR_VALID)) {
return new ValidLeafRope(bytes, encoding, characterLength);
return new ValidLeafRope(bytes, encoding, calculatedCharacterLength);
}

return new InvalidLeafRope(bytes, encoding);
}

@Specialization(guards = { "isUnknown(codeRange)", "!isEmpty(bytes)", "!isBinaryString(encoding)", "!isAsciiCompatible(encoding)" })
public LeafRope makeUnknownLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange,
public LeafRope makeUnknownLeafRope(byte[] bytes, Encoding encoding, CodeRange codeRange, Object characterLength,
@Cached("createBinaryProfile()") ConditionProfile discovered7BitProfile,
@Cached("createBinaryProfile()") ConditionProfile discoveredValidProfile) {
final long packedLengthAndCodeRange = StringSupport.strLengthWithCodeRangeNonAsciiCompatible(encoding, bytes, 0, bytes.length);
final CodeRange newCodeRange = CodeRange.fromInt(StringSupport.unpackArg(packedLengthAndCodeRange));
final int characterLength = StringSupport.unpackResult(packedLengthAndCodeRange);
final int calculatedCharacterLength = StringSupport.unpackResult(packedLengthAndCodeRange);

if (discovered7BitProfile.profile(newCodeRange == CR_7BIT)) {
return new AsciiOnlyLeafRope(bytes, encoding);
}

if (discoveredValidProfile.profile(newCodeRange == CR_VALID)) {
return new ValidLeafRope(bytes, encoding, characterLength);
return new ValidLeafRope(bytes, encoding, calculatedCharacterLength);
}

return new InvalidLeafRope(bytes, encoding);
Original file line number Diff line number Diff line change
@@ -27,6 +27,7 @@
import org.jruby.truffle.core.rope.RopeNodes;
import org.jruby.truffle.core.rope.RopeNodesFactory;
import org.jruby.truffle.core.string.StringOperations;
import org.jruby.truffle.language.NotProvided;
import org.jruby.truffle.language.control.RaiseException;
import org.jruby.truffle.language.objects.AllocateObjectNode;
import org.jruby.truffle.language.objects.AllocateObjectNodeGen;
@@ -704,7 +705,7 @@ public abstract static class GetcwdNode extends CoreMethodArrayArgumentsNode {

public GetcwdNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null, null);
}

@CompilerDirectives.TruffleBoundary
@@ -713,7 +714,7 @@ public DynamicObject getcwd(DynamicObject resultPath, int maxSize) {
// We just ignore maxSize - I think this is ok

final String path = getContext().getJRubyRuntime().getCurrentDirectory();
StringOperations.setRope(resultPath, makeLeafRopeNode.executeMake(path.getBytes(StandardCharsets.UTF_8), Layouts.STRING.getRope(resultPath).getEncoding(), CodeRange.CR_UNKNOWN));
StringOperations.setRope(resultPath, makeLeafRopeNode.executeMake(path.getBytes(StandardCharsets.UTF_8), Layouts.STRING.getRope(resultPath).getEncoding(), CodeRange.CR_UNKNOWN, NotProvided.INSTANCE));
return resultPath;
}

Original file line number Diff line number Diff line change
@@ -1352,7 +1352,7 @@ public static abstract class StringPatternPrimitiveNode extends RubiniusPrimitiv
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);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null, null);
}

@Specialization(guards = "value == 0")
@@ -1381,7 +1381,7 @@ public DynamicObject stringPattern(DynamicObject stringClass, int size, DynamicO
}

// TODO (nirvdrum 21-Jan-16): Verify the encoding and code range are correct.
return allocateObjectNode.allocate(stringClass, makeLeafRopeNode.executeMake(bytes, encoding(string), CodeRange.CR_UNKNOWN), null);
return allocateObjectNode.allocate(stringClass, makeLeafRopeNode.executeMake(bytes, encoding(string), CodeRange.CR_UNKNOWN, NotProvided.INSTANCE), null);
}

}
@@ -1543,7 +1543,7 @@ public static abstract class StringByteAppendPrimitiveNode extends RubiniusPrimi
public StringByteAppendPrimitiveNode(RubyContext context, SourceSection sourceSection) {
super(context, sourceSection);
makeConcatNode = RopeNodesFactory.MakeConcatNodeGen.create(context, sourceSection, null, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null);
makeLeafRopeNode = RopeNodesFactory.MakeLeafRopeNodeGen.create(context, sourceSection, null, null, null, null);
}

@Specialization(guards = "isRubyString(other)")
@@ -1560,7 +1560,7 @@ public DynamicObject stringByteAppend(DynamicObject string, DynamicObject other)
// this, StringIO ceases to work -- the resulting string must retain the original CR_7BIT code range. It's
// ugly, but seems to be due to a difference in how Rubinius keeps track of byte optimizable strings.

final Rope rightConverted = makeLeafRopeNode.executeMake(right.getBytes(), left.getEncoding(), left.getCodeRange());
final Rope rightConverted = makeLeafRopeNode.executeMake(right.getBytes(), left.getEncoding(), left.getCodeRange(), NotProvided.INSTANCE);

StringOperations.setRope(string, makeConcatNode.executeMake(left, rightConverted, left.getEncoding()));

Loading

0 comments on commit 9dd4e21

Please sign in to comment.