Skip to content

Commit 07dbd65

Browse files
djoooooechumer
authored andcommitted
TruffleStrings: fix SwitchEncodingNode breaking string compaction invariants on native UTF-32 strings
1 parent a513307 commit 07dbd65

File tree

2 files changed

+53
-23
lines changed

2 files changed

+53
-23
lines changed

truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringSwitchEncodingTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ public void testAll() throws Exception {
133133
: new TranscodingErrorHandler[]{TranscodingErrorHandler.DEFAULT}) {
134134
TruffleString b = node.execute(a, targetEncoding, errorHandler);
135135
MutableTruffleString bMutable = nodeMutable.execute(a, targetEncoding, errorHandler);
136-
if (a instanceof TruffleString &&
137-
(encoding == targetEncoding || !isDebugStrictEncodingChecks() && codeRange == TruffleString.CodeRange.ASCII && isAsciiCompatible(targetEncoding))) {
136+
if (a instanceof TruffleString && (encoding == targetEncoding || !isDebugStrictEncodingChecks() &&
137+
codeRange == TruffleString.CodeRange.ASCII && isAsciiCompatible(targetEncoding) &&
138+
a.getStringCompactionLevelUncached(encoding).getLog2() <= getNaturalStride(targetEncoding))) {
138139
Assert.assertSame(a, b);
139140
}
140141
if (a instanceof MutableTruffleString && encoding == targetEncoding) {

truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6395,33 +6395,35 @@ abstract static class InternalSwitchEncodingNode extends AbstractInternalNode {
63956395

63966396
abstract TruffleString execute(Node node, AbstractTruffleString a, Encoding targetEncoding, TranscodingErrorHandler errorHandler);
63976397

6398-
@Specialization(guards = "a.isCompatibleToIntl(targetEncoding)")
6399-
static TruffleString compatibleImmutable(TruffleString a, @SuppressWarnings("unused") Encoding targetEncoding, @SuppressWarnings("unused") TranscodingErrorHandler errorHandler) {
6400-
assert !a.isJavaString();
6401-
return a;
6402-
}
6403-
6404-
@Specialization(guards = "a.isCompatibleToIntl(targetEncoding)")
6405-
static TruffleString compatibleMutable(Node node, MutableTruffleString a, Encoding targetEncoding, @SuppressWarnings("unused") TranscodingErrorHandler errorHandler,
6406-
@Cached InternalAsTruffleStringNode asTruffleStringNode) {
6407-
return asTruffleStringNode.execute(node, a, targetEncoding);
6408-
}
6409-
6410-
@Specialization(guards = "!a.isCompatibleToIntl(targetEncoding)")
6411-
static TruffleString transCode(Node node, TruffleString a, Encoding targetEncoding, TranscodingErrorHandler errorHandler,
6398+
@Specialization
6399+
static TruffleString immutable(Node node, TruffleString a, Encoding targetEncoding, TranscodingErrorHandler errorHandler,
64126400
@Cached @Shared TStringInternalNodes.GetPreciseCodeRangeNode getPreciseCodeRangeNode,
6413-
@Cached InlinedConditionProfile preciseCodeRangeIsCompatibleProfile,
6401+
@Cached InlinedConditionProfile isCompatibleProfile,
6402+
@Cached InlinedConditionProfile noOpProfile,
6403+
@Cached InlinedConditionProfile mustCompactProfile,
6404+
@Cached InlinedConditionProfile compact10Profile,
6405+
@Cached InlinedConditionProfile compact20Profile,
64146406
@Exclusive @Cached InlinedConditionProfile cacheHit,
64156407
@Cached ToIndexableNode toIndexableNode,
64166408
@Cached @Shared TStringInternalNodes.TransCodeNode transCodeNode) {
6417-
if (a.isEmpty()) {
6418-
return targetEncoding.getEmpty();
6409+
final boolean isCompatible;
6410+
final int preciseCodeRangeA;
6411+
if (isCompatibleProfile.profile(node, a.isCompatibleToIntl(targetEncoding))) {
6412+
isCompatible = true;
6413+
preciseCodeRangeA = a.codeRange();
6414+
} else {
6415+
Encoding encodingA = Encoding.get(a.encoding());
6416+
preciseCodeRangeA = getPreciseCodeRangeNode.execute(node, a, encodingA);
6417+
isCompatible = a.isCodeRangeCompatibleTo(preciseCodeRangeA, targetEncoding);
64196418
}
6420-
Encoding encodingA = Encoding.get(a.encoding());
6421-
int preciseCodeRangeA = getPreciseCodeRangeNode.execute(node, a, encodingA);
6422-
if (preciseCodeRangeIsCompatibleProfile.profile(node, a.isCodeRangeCompatibleTo(preciseCodeRangeA, targetEncoding))) {
6419+
final boolean mustCompact = a.stride() > targetEncoding.naturalStride;
6420+
if (noOpProfile.profile(node, isCompatible && !mustCompact)) {
6421+
assert !a.isJavaString();
64236422
return a;
64246423
}
6424+
if (a.isEmpty()) {
6425+
return targetEncoding.getEmpty();
6426+
}
64256427
TruffleString cur = a.next;
64266428
assert !a.isJavaString();
64276429
if (cur != null) {
@@ -6433,13 +6435,40 @@ static TruffleString transCode(Node node, TruffleString a, Encoding targetEncodi
64336435
return cur;
64346436
}
64356437
}
6436-
TruffleString transCoded = transCodeNode.execute(node, a, toIndexableNode.execute(node, a, a.data()), a.codePointLength(), preciseCodeRangeA, targetEncoding, errorHandler);
6438+
final TruffleString transCoded;
6439+
if (mustCompactProfile.profile(node, isCompatible && mustCompact)) {
6440+
final Object arrayA = a.data();
6441+
assert arrayA instanceof NativePointer;
6442+
final int offsetA = a.offset();
6443+
final int strideA = a.stride();
6444+
final int offset = 0;
6445+
final int lengthA = a.length();
6446+
final int stride = Stride.fromCodeRangeUTF16(preciseCodeRangeA);
6447+
final byte[] array = new byte[lengthA << stride];
6448+
if (compact10Profile.profile(node, strideA == 1 && stride == 0)) {
6449+
TStringOps.arraycopyWithStride(node, arrayA, offsetA, 1, 0, array, offset, 0, 0, lengthA);
6450+
} else if (compact20Profile.profile(node, strideA == 2 && stride == 0)) {
6451+
TStringOps.arraycopyWithStride(node, arrayA, offsetA, 2, 0, array, offset, 0, 0, lengthA);
6452+
} else {
6453+
assert strideA == 2 && stride == 1;
6454+
TStringOps.arraycopyWithStride(node, arrayA, offsetA, 2, 0, array, offset, 1, 0, lengthA);
6455+
}
6456+
transCoded = TruffleString.createFromArray(array, offset, lengthA, stride, targetEncoding, a.codePointLength(), preciseCodeRangeA, false);
6457+
} else {
6458+
transCoded = transCodeNode.execute(node, a, toIndexableNode.execute(node, a, a.data()), a.codePointLength(), preciseCodeRangeA, targetEncoding, errorHandler);
6459+
}
64376460
if (!transCoded.isCacheHead()) {
64386461
a.cacheInsert(transCoded);
64396462
}
64406463
return transCoded;
64416464
}
64426465

6466+
@Specialization(guards = "a.isCompatibleToIntl(targetEncoding)")
6467+
static TruffleString compatibleMutable(Node node, MutableTruffleString a, Encoding targetEncoding, @SuppressWarnings("unused") TranscodingErrorHandler errorHandler,
6468+
@Cached InternalAsTruffleStringNode asTruffleStringNode) {
6469+
return asTruffleStringNode.execute(node, a, targetEncoding);
6470+
}
6471+
64436472
@Specialization(guards = "!a.isCompatibleToIntl(targetEncoding)")
64446473
static TruffleString transCodeMutable(Node node, MutableTruffleString a, Encoding targetEncoding, TranscodingErrorHandler errorHandler,
64456474
@Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthNode,

0 commit comments

Comments
 (0)