diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringConstructorTests.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringConstructorTests.java index 847e6524b399..8af23c11e2d7 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringConstructorTests.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringConstructorTests.java @@ -50,12 +50,12 @@ import java.nio.ByteOrder; -import com.oracle.truffle.api.strings.InternalByteArray; import org.graalvm.shadowed.org.jcodings.Encoding; import org.junit.Assert; import org.junit.Test; import com.oracle.truffle.api.strings.AbstractTruffleString; +import com.oracle.truffle.api.strings.InternalByteArray; import com.oracle.truffle.api.strings.MutableTruffleString; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilder; diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringCornerCaseTests.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringCornerCaseTests.java index 5edfca335a98..a98a10ab74a8 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringCornerCaseTests.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringCornerCaseTests.java @@ -43,10 +43,10 @@ import static com.oracle.truffle.api.strings.test.TStringTestUtil.byteArray; -import com.oracle.truffle.api.strings.MutableTruffleString; import org.junit.Assert; import org.junit.Test; +import com.oracle.truffle.api.strings.MutableTruffleString; import com.oracle.truffle.api.strings.TruffleString; public class TStringCornerCaseTests extends TStringTestBase { diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringTestBase.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringTestBase.java index d84c5ac264ed..19113a1f12d3 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringTestBase.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringTestBase.java @@ -185,7 +185,17 @@ public interface TestStrings { } public interface TestIndexOfString { - void run(AbstractTruffleString b, int expectedIndex); + + int run(AbstractTruffleString b, int fromIndex, int toIndex); + + default void run(AbstractTruffleString b, int fromIndex, int toIndex, int expectedResult) { + if (expectedResult < 0) { + int result = run(b, fromIndex, toIndex); + Assert.assertTrue("expected: negative value, actual: " + result, result < 0); + } else { + Assert.assertEquals(expectedResult, run(b, fromIndex, toIndex)); + } + } } public interface TestS { @@ -460,21 +470,52 @@ protected static void testIndexOfString(AbstractTruffleString a, byte[] array, b // ignore broken strings return; } - int lastCodepoint = codepoints[codepoints.length - 1]; - TruffleString first = TruffleString.fromCodePointUncached(codepoints[0], encoding); + int lastCPI = codepoints.length - 1; + int firstCodepoint = codepoints[0]; + int lastCodepoint = codepoints[lastCPI]; + TruffleString first = TruffleString.fromCodePointUncached(firstCodepoint, encoding); TruffleString firstSubstring = a.substringByteIndexUncached(0, codepoints.length == 1 ? array.length : byteIndices[1], encoding, true); TruffleString last = TruffleString.fromCodePointUncached(lastCodepoint, encoding); - TruffleString lastSubstring = a.substringByteIndexUncached(byteIndices[codepoints.length - 1], array.length - byteIndices[codepoints.length - 1], encoding, true); - int expectedFirst = lastIndex ? lastIndexOfCodePoint(codepoints, byteIndices, byteIndex, codepoints[0]) : 0; - int expectedLast = lastIndex ? byteIndex ? byteIndices[codepoints.length - 1] : codepoints.length - 1 : indexOfCodePoint(codepoints, byteIndices, byteIndex, lastCodepoint); - test.run(first, expectedFirst); - test.run(firstSubstring, expectedFirst); - test.run(last, expectedLast); - test.run(lastSubstring, expectedLast); + TruffleString lastSubstring = a.substringByteIndexUncached(byteIndices[lastCPI], array.length - byteIndices[lastCPI], encoding, true); + int expectedFirst = lastIndex ? lastIndexOfCodePoint(codepoints, byteIndices, byteIndex, codepoints.length, 0, firstCodepoint) : 0; + int expectedLast = lastIndex ? byteIndex ? byteIndices[lastCPI] : lastCPI : indexOfCodePoint(codepoints, byteIndices, byteIndex, 0, codepoints.length, lastCodepoint); + int fromIndex; + int toIndex; + if (lastIndex) { + fromIndex = byteIndex ? array.length : codepoints.length; + toIndex = 0; + } else { + fromIndex = 0; + toIndex = byteIndex ? array.length : codepoints.length; + } + test.run(first, fromIndex, toIndex, expectedFirst); + test.run(firstSubstring, fromIndex, toIndex, expectedFirst); + test.run(last, fromIndex, toIndex, expectedLast); + test.run(lastSubstring, fromIndex, toIndex, expectedLast); + test.run(first, 0, 0, -1); + + int i1 = byteIndex ? byteIndices[1] : 1; + int iLast1 = byteIndex ? byteIndices[codepoints.length - 1] : codepoints.length - 1; + + if (lastIndex) { + expectedFirst = lastIndexOfCodePoint(codepoints, byteIndices, byteIndex, codepoints.length, 1, firstCodepoint); + expectedLast = lastIndexOfCodePoint(codepoints, byteIndices, byteIndex, codepoints.length - 1, 0, lastCodepoint); + test.run(first, fromIndex, i1, expectedFirst); + test.run(firstSubstring, fromIndex, i1, expectedFirst); + test.run(last, iLast1, toIndex, expectedLast); + test.run(lastSubstring, iLast1, toIndex, expectedLast); + } else { + expectedFirst = indexOfCodePoint(codepoints, byteIndices, byteIndex, 1, codepoints.length, firstCodepoint); + expectedLast = indexOfCodePoint(codepoints, byteIndices, byteIndex, 0, codepoints.length - 1, lastCodepoint); + test.run(first, i1, toIndex, expectedFirst); + test.run(firstSubstring, i1, toIndex, expectedFirst); + test.run(last, fromIndex, iLast1, expectedLast); + test.run(lastSubstring, fromIndex, iLast1, expectedLast); + } } - private static int indexOfCodePoint(int[] codepoints, int[] byteIndices, boolean byteIndex, int cp) { - for (int i = 0; i < codepoints.length; i++) { + private static int indexOfCodePoint(int[] codepoints, int[] byteIndices, boolean byteIndex, int fromIndex, int toIndex, int cp) { + for (int i = fromIndex; i < toIndex; i++) { if (codepoints[i] == cp) { return byteIndex ? byteIndices[i] : i; } @@ -482,8 +523,8 @@ private static int indexOfCodePoint(int[] codepoints, int[] byteIndices, boolean return -1; } - private static int lastIndexOfCodePoint(int[] codepoints, int[] byteIndices, boolean byteIndex, int cp) { - for (int i = codepoints.length - 1; i >= 0; i--) { + private static int lastIndexOfCodePoint(int[] codepoints, int[] byteIndices, boolean byteIndex, int fromIndex, int toIndex, int cp) { + for (int i = fromIndex - 1; i >= toIndex; i--) { if (codepoints[i] == cp) { return byteIndex ? byteIndices[i] : i; } diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringUTF8Tests.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringUTF8Tests.java index 8f637bcfda11..72daf8a5f1ad 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringUTF8Tests.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/TStringUTF8Tests.java @@ -41,6 +41,8 @@ package com.oracle.truffle.api.strings.test; +import static com.oracle.truffle.api.strings.TruffleString.Encoding.UTF_8; + import java.nio.charset.StandardCharsets; import org.junit.Assert; @@ -95,29 +97,75 @@ private static byte[] utf8Encode(int codepoint) { @Test public void testValid() { for (byte[] arr : VALID) { - Assert.assertTrue(TStringTestUtil.hex(arr), TruffleString.fromByteArrayUncached(arr, 0, arr.length, TruffleString.Encoding.UTF_8, false).isValidUncached(TruffleString.Encoding.UTF_8)); + Assert.assertTrue(TStringTestUtil.hex(arr), TruffleString.fromByteArrayUncached(arr, 0, arr.length, UTF_8, false).isValidUncached(UTF_8)); } } @Test public void testInvalid() { for (byte[] arr : INVALID) { - Assert.assertFalse(TStringTestUtil.hex(arr), TruffleString.fromByteArrayUncached(arr, 0, arr.length, TruffleString.Encoding.UTF_8, false).isValidUncached(TruffleString.Encoding.UTF_8)); + Assert.assertFalse(TStringTestUtil.hex(arr), TruffleString.fromByteArrayUncached(arr, 0, arr.length, UTF_8, false).isValidUncached(UTF_8)); } } @Test public void testCodePointLength1() { byte[] arr = TStringTestUtil.byteArray(0xf4, 0x90, 0x80, 0x80, 0x7f, 0x7f); - TruffleString a = TruffleString.fromByteArrayUncached(arr, 0, arr.length, TruffleString.Encoding.UTF_8, false); + TruffleString a = TruffleString.fromByteArrayUncached(arr, 0, arr.length, UTF_8, false); a.toString(); - Assert.assertEquals(6, a.codePointLengthUncached(TruffleString.Encoding.UTF_8)); + Assert.assertEquals(6, a.codePointLengthUncached(UTF_8)); } @Test public void testCodePointLength2() { byte[] arr = TStringTestUtil.byteArray(0, 0, 0xc0, 0xbf); - TruffleString a = TruffleString.fromByteArrayUncached(arr, 0, arr.length, TruffleString.Encoding.UTF_8, false); - Assert.assertEquals(4, a.codePointLengthUncached(TruffleString.Encoding.UTF_8)); + TruffleString a = TruffleString.fromByteArrayUncached(arr, 0, arr.length, UTF_8, false); + Assert.assertEquals(4, a.codePointLengthUncached(UTF_8)); + } + + @Test + public void testIndexOf() { + TruffleString s1 = TruffleString.fromJavaStringUncached("aaa", UTF_8); + TruffleString s2 = TruffleString.fromJavaStringUncached("a", UTF_8); + Assert.assertEquals(-1, s1.byteIndexOfStringUncached(s2, 1, 1, UTF_8)); + } + + @Test + public void testIndexOf2() { + TruffleString a = TruffleString.fromCodePointUncached(0x102, UTF_8); + TruffleString b = TruffleString.fromCodePointUncached(0x10_0304, UTF_8); + TruffleString s1 = a.repeatUncached(10, UTF_8); + TruffleString s2 = a.concatUncached(b, UTF_8, false); + Assert.assertEquals(-1, s1.byteIndexOfStringUncached(s2, 0, s1.byteLength(UTF_8), UTF_8)); + Assert.assertEquals(-1, s1.indexOfStringUncached(s2, 0, s1.codePointLengthUncached(UTF_8), UTF_8)); + } + + @Test + public void testIndexOf3() { + TruffleString a = TruffleString.fromJavaStringUncached("aaa", UTF_8); + TruffleString b = TruffleString.fromJavaStringUncached("baa", UTF_8); + Assert.assertEquals(-1, a.lastIndexOfStringUncached(b, 3, 0, UTF_8)); + } + + @Test + public void testIndexOf4() { + TruffleString a = TruffleString.fromJavaStringUncached("defghiabc", UTF_8); + TruffleString b = TruffleString.fromJavaStringUncached("def", UTF_8); + Assert.assertEquals(-1, a.lastIndexOfStringUncached(b, 9, 1, UTF_8)); + } + + @Test + public void testIndexOf5() { + TruffleString ts1 = TruffleString.fromJavaStringUncached("a\u00A3b\u00A3", UTF_8); + TruffleString ts2 = TruffleString.fromJavaStringUncached("a\u00A3", UTF_8); + Assert.assertEquals(-1, ts1.lastIndexOfStringUncached(ts2, 4, 1, UTF_8)); + Assert.assertEquals(-1, ts1.lastByteIndexOfStringUncached(ts2, 6, 1, UTF_8)); + } + + @Test + public void testIndexOf6() { + TruffleString ts1 = TruffleString.fromJavaStringUncached("<......\u043c...", UTF_8); + TruffleString ts2 = TruffleString.fromJavaStringUncached("<", UTF_8); + Assert.assertEquals(0, ts1.lastIndexOfStringUncached(ts2, ts1.codePointLengthUncached(UTF_8), 0, UTF_8)); } } diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringByteIndexOfStringTest.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringByteIndexOfStringTest.java index 579a1ccee968..296f5a5740f5 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringByteIndexOfStringTest.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringByteIndexOfStringTest.java @@ -79,9 +79,7 @@ public static Iterable data() { @Test public void testAll() throws Exception { forAllStrings(true, (a, array, codeRange, isValid, encoding, codepoints, byteIndices) -> { - testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, true, false, (b, expectedIndex) -> { - Assert.assertEquals(expectedIndex, node.execute(a, b, 0, array.length, encoding)); - }); + testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, true, false, (b, fromIndex, toIndex) -> node.execute(a, b, fromIndex, toIndex, encoding)); }); } diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringGetInternalByteArrayTest.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringGetInternalByteArrayTest.java index 94f2c8f85c25..d3a50adf0f84 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringGetInternalByteArrayTest.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringGetInternalByteArrayTest.java @@ -45,13 +45,13 @@ import java.util.Arrays; -import com.oracle.truffle.api.strings.InternalByteArray; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; +import com.oracle.truffle.api.strings.InternalByteArray; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.test.TStringTestBase; diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringIndexOfStringTest.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringIndexOfStringTest.java index 6c01b92ebc40..d0658f15fe45 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringIndexOfStringTest.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringIndexOfStringTest.java @@ -45,7 +45,6 @@ import java.util.Arrays; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -67,9 +66,7 @@ public static Iterable data() { @Test public void testAll() throws Exception { forAllStrings(true, (a, array, codeRange, isValid, encoding, codepoints, byteIndices) -> { - testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, false, false, (b, expectedIndex) -> { - Assert.assertEquals(expectedIndex, node.execute(a, b, 0, codepoints.length, encoding)); - }); + testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, false, false, (b, fromIndex, toIndex) -> node.execute(a, b, fromIndex, toIndex, encoding)); }); } diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastByteIndexOfStringTest.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastByteIndexOfStringTest.java index 573ee3049ed4..f9c405192d11 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastByteIndexOfStringTest.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastByteIndexOfStringTest.java @@ -68,9 +68,7 @@ public static Iterable data() { @Test public void testAll() throws Exception { forAllStrings(true, (a, array, codeRange, isValid, encoding, codepoints, byteIndices) -> { - testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, true, true, (b, expectedIndex) -> { - Assert.assertEquals(expectedIndex, node.execute(a, b, array.length, 0, encoding)); - }); + testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, true, true, (b, fromIndex, toIndex) -> node.execute(a, b, fromIndex, toIndex, encoding)); }); } diff --git a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastIndexOfStringTest.java b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastIndexOfStringTest.java index cf33cb0f2822..8430c7ed37bc 100644 --- a/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastIndexOfStringTest.java +++ b/truffle/src/com.oracle.truffle.api.strings.test/src/com/oracle/truffle/api/strings/test/ops/TStringLastIndexOfStringTest.java @@ -45,7 +45,6 @@ import java.util.Arrays; -import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -67,9 +66,7 @@ public static Iterable data() { @Test public void testAll() throws Exception { forAllStrings(true, (a, array, codeRange, isValid, encoding, codepoints, byteIndices) -> { - testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, false, true, (b, expectedIndex) -> { - Assert.assertEquals(expectedIndex, node.execute(a, b, codepoints.length, 0, encoding)); - }); + testIndexOfString(a, array, isValid, encoding, codepoints, byteIndices, false, true, (b, fromIndex, toIndex) -> node.execute(a, b, fromIndex, toIndex, encoding)); }); } diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/Encodings.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/Encodings.java index 42bad8836c3c..2093ddc29676 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/Encodings.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/Encodings.java @@ -130,6 +130,14 @@ static byte[] utf8Encode(int codepoint) { return ret; } + static byte[] utf8EncodeNonAscii(int codepoint, int encodedSize) { + assert encodedSize == utf8EncodedSize(codepoint); + assert encodedSize > 1; + byte[] ret = new byte[encodedSize]; + utf8Encode(codepoint, encodedSize, ret, 0); + return ret; + } + static void utf8Encode(int codepoint, byte[] buffer, int index, int length) { assert length == utf8EncodedSize(codepoint); if (length == 1) { diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringGuards.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringGuards.java index 191599f2bdd3..5cded9141944 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringGuards.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringGuards.java @@ -108,8 +108,16 @@ static boolean isFixedWidth(int codeRangeA, int codeRangeB) { return isFixedWidth(codeRangeA) && isFixedWidth(codeRangeB); } - static boolean indexOfCannotMatch(AbstractTruffleString a, int codeRangeA, AbstractTruffleString b, int codeRangeB, byte[] mask) { - return a.length() < b.length() || mask == null && + static boolean indexOfCannotMatch(int codeRangeA, AbstractTruffleString b, int codeRangeB, int regionLength, TStringInternalNodes.GetCodePointLengthNode getCodePointLengthNodeB) { + return regionLength < getCodePointLengthNodeB.execute(b) || codeRangesCannotMatch(codeRangeA, codeRangeB, null); + } + + static boolean indexOfCannotMatch(int codeRangeA, AbstractTruffleString b, int codeRangeB, byte[] mask, int regionLength) { + return regionLength < b.length() || codeRangesCannotMatch(codeRangeA, codeRangeB, mask); + } + + private static boolean codeRangesCannotMatch(int codeRangeA, int codeRangeB, byte[] mask) { + return mask == null && !TSCodeRange.isBrokenMultiByteOrUnknown(codeRangeA) && !TSCodeRange.isBrokenMultiByteOrUnknown(codeRangeB) && TSCodeRange.isMoreRestrictiveThan(codeRangeA, codeRangeB); diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringInternalNodes.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringInternalNodes.java index 3799504ccfa1..a84f1bfc8e1b 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringInternalNodes.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringInternalNodes.java @@ -734,7 +734,7 @@ static int unsupported(AbstractTruffleString a, Object arrayA, @SuppressWarnings static int indexOfFixedWidth(AbstractTruffleString a, Object arrayA, int codeRangeA, int codepoint, int fromIndex, int toIndex, TStringOpsNodes.RawIndexOfCodePointNode indexOfNode) { - if (!TSCodeRange.isInCodeRange(codepoint, codeRangeA)) { + if (fromIndex == toIndex || !TSCodeRange.isInCodeRange(codepoint, codeRangeA)) { return -1; } return indexOfNode.execute(a, arrayA, codepoint, fromIndex, toIndex); @@ -742,50 +742,12 @@ static int indexOfFixedWidth(AbstractTruffleString a, Object arrayA, int codeRan static int lastIndexOfFixedWidth(AbstractTruffleString a, Object arrayA, int codeRangeA, int codepoint, int fromIndex, int toIndex, TStringOpsNodes.RawLastIndexOfCodePointNode indexOfNode) { - if (!TSCodeRange.isInCodeRange(codepoint, codeRangeA)) { + if (fromIndex == toIndex || !TSCodeRange.isInCodeRange(codepoint, codeRangeA)) { return -1; } return indexOfNode.execute(a, arrayA, codepoint, fromIndex, toIndex); } - static int indexOf08BitUTF8(Node location, AbstractTruffleString a, Object arrayA, int codepoint, int fromIndex, int toIndex) { - assert a.stride() == 0; - assert codepoint > 0x7f; - byte[] encoded = Encodings.utf8Encode(codepoint); - assert encoded.length > 1; - if (encoded.length > a.length()) { - return -1; - } - TruffleString b = TruffleString.createFromByteArray(encoded, encoded.length, 0, Encodings.getUTF8(), 1, TSCodeRange.getValidMultiByte()); - return TStringOps.indexOfStringWithOrMaskWithStride(location, a, arrayA, 0, b, encoded, 0, fromIndex, toIndex, null); - } - - static int indexOf16BitUTF16(Node location, AbstractTruffleString a, Object arrayA, int codepoint, int fromIndex, int toIndex) { - assert a.stride() == 1; - assert codepoint > 0xffff; - return TStringOps.indexOf2ConsecutiveWithStride( - location, a, arrayA, 1, fromIndex, toIndex, Character.highSurrogate(codepoint), Character.lowSurrogate(codepoint)); - } - - static int lastIndexOf08BitUTF8(Node location, AbstractTruffleString a, Object arrayA, int codepoint, int fromIndex, int toIndex) { - assert a.stride() == 0; - assert codepoint > 0x7f; - byte[] encoded = Encodings.utf8Encode(codepoint); - assert encoded.length > 1; - if (encoded.length > a.length()) { - return -1; - } - TruffleString b = TruffleString.createFromByteArray(encoded, encoded.length, 0, Encodings.getUTF8(), 1, TSCodeRange.getValidMultiByte()); - return TStringOps.lastIndexOfStringWithOrMaskWithStride(location, a, arrayA, 0, b, encoded, 0, fromIndex, toIndex, null); - } - - static int lastIndexOf16BitUTF16(Node location, AbstractTruffleString a, Object arrayA, int codepoint, int fromIndex, int toIndex) { - assert a.stride() == 1; - assert codepoint > 0xffff; - return TStringOps.lastIndexOf2ConsecutiveWithOrMaskWithStride( - location, a, arrayA, 1, fromIndex, toIndex, Character.highSurrogate(codepoint), Character.lowSurrogate(codepoint), 0, 0); - } - @ImportStatic(TStringGuards.class) @GenerateUncached abstract static class IndexOfCodePointNode extends Node { @@ -820,19 +782,30 @@ static int utf8Fixed(AbstractTruffleString a, Object arrayA, int codeRangeA, int @Specialization(guards = {"isUTF8(a)", "!isFixedWidth(codeRangeA)"}) int utf8Variable(AbstractTruffleString a, Object arrayA, @SuppressWarnings("unused") int codeRangeA, int codepoint, int fromIndex, int toIndex) { assert isStride0(a); - if (codepoint <= 0x7f) { + int encodedSize = Encodings.utf8EncodedSize(codepoint); + if (encodedSize > toIndex - fromIndex) { + return -1; + } + if (encodedSize == 1) { return TStringOps.indexOfCodePointWithStride(this, a, arrayA, 0, fromIndex, toIndex, codepoint); } - return indexOf08BitUTF8(this, a, arrayA, codepoint, fromIndex, toIndex); + byte[] encoded = Encodings.utf8EncodeNonAscii(codepoint, encodedSize); + TruffleString b = TruffleString.createFromByteArray(encoded, encoded.length, 0, Encodings.getUTF8(), 1, TSCodeRange.getValidMultiByte()); + return TStringOps.indexOfStringWithOrMaskWithStride(this, a, arrayA, 0, b, encoded, 0, fromIndex, toIndex, null); } @Specialization(guards = {"isUTF16(a)", "!isFixedWidth(codeRangeA)"}) int utf16Variable(AbstractTruffleString a, Object arrayA, @SuppressWarnings("unused") int codeRangeA, int codepoint, int fromIndex, int toIndex) { assert isStride1(a); - if (codepoint <= 0xffff) { + int encodedSize = Encodings.utf16EncodedSize(codepoint); + if (encodedSize > toIndex - fromIndex) { + return -1; + } + if (encodedSize == 1) { return TStringOps.indexOfCodePointWithStride(this, a, arrayA, 1, fromIndex, toIndex, codepoint); } - return indexOf16BitUTF16(this, a, arrayA, codepoint, fromIndex, toIndex); + return TStringOps.indexOf2ConsecutiveWithStride( + this, a, arrayA, 1, fromIndex, toIndex, Character.highSurrogate(codepoint), Character.lowSurrogate(codepoint)); } @Specialization(guards = {"isUnsupportedEncoding(a)", "!isFixedWidth(codeRangeA)"}) @@ -886,19 +859,31 @@ static int utf8Fixed(AbstractTruffleString a, Object arrayA, int codeRangeA, int @Specialization(guards = {"isUTF8(a)", "!isFixedWidth(codeRangeA)"}) int utf8Variable(AbstractTruffleString a, Object arrayA, int codeRangeA, int codepoint, int fromIndex, int toIndex, @Cached @Shared("lastIndexOfNode") TStringOpsNodes.RawLastIndexOfCodePointNode lastIndexOfNode) { - if (codepoint <= 0x7f) { + int encodedSize = Encodings.utf8EncodedSize(codepoint); + if (encodedSize > fromIndex - toIndex) { + return -1; + } + if (encodedSize == 1) { return lastIndexOfFixedWidth(a, arrayA, codeRangeA, codepoint, fromIndex, toIndex, lastIndexOfNode); } - return lastIndexOf08BitUTF8(this, a, arrayA, codepoint, fromIndex, toIndex); + byte[] encoded = Encodings.utf8EncodeNonAscii(codepoint, encodedSize); + TruffleString b = TruffleString.createFromByteArray(encoded, encoded.length, 0, Encodings.getUTF8(), 1, TSCodeRange.getValidMultiByte()); + return TStringOps.lastIndexOfStringWithOrMaskWithStride(this, a, arrayA, 0, b, encoded, 0, fromIndex, toIndex, null); } @Specialization(guards = {"isUTF16(a)", "!isFixedWidth(codeRangeA)"}) int utf16Variable(AbstractTruffleString a, Object arrayA, int codeRangeA, int codepoint, int fromIndex, int toIndex, @Cached @Shared("lastIndexOfNode") TStringOpsNodes.RawLastIndexOfCodePointNode lastIndexOfNode) { - if (codepoint <= 0xffff) { + assert isStride1(a); + int encodedSize = Encodings.utf16EncodedSize(codepoint); + if (encodedSize > fromIndex - toIndex) { + return -1; + } + if (encodedSize == 1) { return lastIndexOfFixedWidth(a, arrayA, codeRangeA, codepoint, fromIndex, toIndex, lastIndexOfNode); } - return lastIndexOf16BitUTF16(this, a, arrayA, codepoint, fromIndex, toIndex); + return TStringOps.lastIndexOf2ConsecutiveWithOrMaskWithStride( + this, a, arrayA, 1, fromIndex, toIndex, Character.highSurrogate(codepoint), Character.lowSurrogate(codepoint), 0, 0); } @Specialization(guards = {"isUnsupportedEncoding(a)", "!isFixedWidth(codeRangeA)"}) @@ -1114,7 +1099,7 @@ static int direct( AbstractTruffleString a, Object arrayA, int codeRangeA, AbstractTruffleString b, Object arrayB, int codeRangeB, int fromIndex, int toIndex, @Cached RawIndexOfStringNode indexOfStringNode) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, toIndex - fromIndex, GetCodePointLengthNode.getUncached()); return indexOfStringNode.execute(a, arrayA, b, arrayB, fromIndex, toIndex, null); } @@ -1124,7 +1109,7 @@ int decode( AbstractTruffleString b, Object arrayB, int codeRangeB, int fromIndex, int toIndex, @Cached TruffleStringIterator.NextNode nextNodeA, @Cached TruffleStringIterator.NextNode nextNodeB) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, toIndex - fromIndex, GetCodePointLengthNode.getUncached()); TruffleStringIterator aIt = AbstractTruffleString.forwardIterator(a, arrayA, codeRangeA); TruffleStringIterator bIt = AbstractTruffleString.forwardIterator(b, arrayB, codeRangeB); return TruffleStringIterator.indexOfString(this, aIt, bIt, fromIndex, toIndex, nextNodeA, nextNodeB); @@ -1142,7 +1127,7 @@ static int supported( AbstractTruffleString a, Object arrayA, int codeRangeA, AbstractTruffleString b, Object arrayB, int codeRangeB, int fromIndex, int toIndex, byte[] mask, @Cached TStringOpsNodes.RawIndexOfStringNode indexOfStringNode) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, toIndex - fromIndex); return indexOfStringNode.execute(a, arrayA, b, arrayB, fromIndex, toIndex, mask); } @@ -1153,7 +1138,7 @@ int unsupported( @Cached TruffleStringIterator.NextNode nextNodeA, @Cached TruffleStringIterator.NextNode nextNodeB) { assert mask == null; - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, toIndex - fromIndex); TruffleStringIterator aIt = AbstractTruffleString.forwardIterator(a, arrayA, codeRangeA); TruffleStringIterator bIt = AbstractTruffleString.forwardIterator(b, arrayB, codeRangeB); return TruffleStringIterator.byteIndexOfString(this, aIt, bIt, fromIndex, toIndex, nextNodeA, nextNodeB); @@ -1171,7 +1156,7 @@ static int direct( AbstractTruffleString a, Object arrayA, int codeRangeA, AbstractTruffleString b, Object arrayB, int codeRangeB, int fromIndex, int toIndex, @Cached RawLastIndexOfStringNode indexOfStringNode) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, fromIndex - toIndex, GetCodePointLengthNode.getUncached()); return indexOfStringNode.execute(a, arrayA, b, arrayB, fromIndex, toIndex, null); } @@ -1182,7 +1167,7 @@ int decode( @Cached TruffleStringIterator.NextNode nextNodeA, @Cached TruffleStringIterator.PreviousNode prevNodeA, @Cached TruffleStringIterator.PreviousNode prevNodeB) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, fromIndex - toIndex, GetCodePointLengthNode.getUncached()); TruffleStringIterator aIt = AbstractTruffleString.forwardIterator(a, arrayA, codeRangeA); TruffleStringIterator bIt = AbstractTruffleString.backwardIterator(b, arrayB, codeRangeB); return TruffleStringIterator.lastIndexOfString(this, aIt, bIt, fromIndex, toIndex, nextNodeA, prevNodeA, prevNodeB); @@ -1200,7 +1185,7 @@ static int lios8SameEncoding( AbstractTruffleString a, Object arrayA, int codeRangeA, AbstractTruffleString b, Object arrayB, int codeRangeB, int fromIndex, int toIndex, byte[] mask, @Cached TStringOpsNodes.RawLastIndexOfStringNode indexOfStringNode) { - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, fromIndex - toIndex); return indexOfStringNode.execute(a, arrayA, b, arrayB, fromIndex, toIndex, mask); } @@ -1212,7 +1197,7 @@ int unsupported( @Cached TruffleStringIterator.PreviousNode prevNodeA, @Cached TruffleStringIterator.PreviousNode prevNodeB) { assert mask == null; - assert !b.isEmpty() && !indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask); + assert !b.isEmpty() && !indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, fromIndex - toIndex); TruffleStringIterator aIt = AbstractTruffleString.forwardIterator(a, arrayA, codeRangeA); TruffleStringIterator bIt = AbstractTruffleString.backwardIterator(b, arrayB, codeRangeB); return TruffleStringIterator.lastByteIndexOfString(this, aIt, bIt, fromIndex, toIndex, nextNodeA, prevNodeA, prevNodeB); diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringOps.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringOps.java index f7c8cea7a809..4f39f45bad7f 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringOps.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringOps.java @@ -475,8 +475,9 @@ static int lastIndexOfStringWithOrMaskWithStride(Node location, final int b1 = readValue(b, arrayB, strideB, b.length() - 1); final int mask0 = maskB == null ? 0 : readValue(maskB, offsetMask, b.length(), strideB, b.length() - 2); final int mask1 = maskB == null ? 0 : readValue(maskB, offsetMask, b.length(), strideB, b.length() - 1); - while (index > toIndex) { - index = lastIndexOf2ConsecutiveWithOrMaskWithStrideIntl(location, arrayA, a.offset(), strideA, index, b.length() - 2, b0, b1, mask0, mask1); + final int toIndex2Consecutive = toIndex + b.length() - 2; + while (index > toIndex2Consecutive) { + index = lastIndexOf2ConsecutiveWithOrMaskWithStrideIntl(location, arrayA, a.offset(), strideA, index, toIndex2Consecutive, b0, b1, mask0, mask1); if (index < 0) { return -1; } @@ -1198,7 +1199,7 @@ private static int runIndexOf2ConsecutiveWithOrMaskWithStride(Node location, Obj private static int runLastIndexOf2ConsecutiveWithOrMaskWithStride(Node location, Object array, long offset, int stride, boolean isNative, int fromIndex, int toIndex, int c1, int c2, int mask1, int mask2) { - for (int i = fromIndex - 1; i >= toIndex; i--) { + for (int i = fromIndex - 1; i > toIndex; i--) { if ((readValue(array, offset, stride, i - 1, isNative) | mask1) == c1 && (readValue(array, offset, stride, i, isNative) | mask2) == c2) { return i - 1; } diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringUnsafe.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringUnsafe.java index b250132f14e4..55db945f75e5 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringUnsafe.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TStringUnsafe.java @@ -121,15 +121,15 @@ static int getJavaStringStride(String s) { private static String allocateJavaString() { try { return (String) UNSAFE.allocateInstance(String.class); - } catch (Throwable e) { - throw CompilerDirectives.shouldNotReachHere("Could not allocate java string"); + } catch (InstantiationException e) { + throw CompilerDirectives.shouldNotReachHere("unsafe string allocation failed", e); } } @TruffleBoundary static String createJavaString(byte[] bytes, int stride) { if (stride < 0 || stride > 1) { - throw CompilerDirectives.shouldNotReachHere("stride must be 0 or 1!"); + throw new IllegalArgumentException("stride must be 0 or 1!"); } String ret = allocateJavaString(); UNSAFE.putInt(ret, javaStringHashFieldOffset, 0); diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java index 25243a9f7be8..3672f6a1315b 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleString.java @@ -3027,7 +3027,7 @@ int indexOfRaw(AbstractTruffleString a, int fromByteIndex, int maxByteIndex, byt return -1; } a.boundsCheckRaw(fromByteIndex, maxByteIndex); - if (TSCodeRange.is7Bit(getCodeRangeNode.execute(a)) && noneIsAscii(this, values)) { + if (fromByteIndex == maxByteIndex || TSCodeRange.is7Bit(getCodeRangeNode.execute(a)) && noneIsAscii(this, values)) { return -1; } assert isStride0(a); @@ -3099,7 +3099,7 @@ int indexOfRaw(AbstractTruffleString a, int fromCharIndex, int maxCharIndex, cha } a.boundsCheckRaw(fromCharIndex, maxCharIndex); int codeRangeA = getCodeRangeNode.execute(a); - if (TSCodeRange.isFixedWidth(codeRangeA) && noneInCodeRange(this, codeRangeA, values)) { + if (fromCharIndex == maxCharIndex || TSCodeRange.isFixedWidth(codeRangeA) && noneInCodeRange(this, codeRangeA, values)) { return -1; } return indexOfNode.execute(a, toIndexableNode.execute(a, a.data()), fromCharIndex, maxCharIndex, values); @@ -3168,7 +3168,7 @@ int indexOfRaw(AbstractTruffleString a, int fromIntIndex, int maxIntIndex, int[] return -1; } a.boundsCheckRaw(fromIntIndex, maxIntIndex); - if (noneInCodeRange(this, getCodeRangeNode.execute(a), values)) { + if (fromIntIndex == maxIntIndex || noneInCodeRange(this, getCodeRangeNode.execute(a), values)) { return -1; } return indexOfNode.execute(a, toIndexableNode.execute(a, a.data()), fromIntIndex, maxIntIndex, values); @@ -3281,7 +3281,7 @@ public abstract static class ByteIndexOfCodePointNode extends Node { public abstract int execute(AbstractTruffleString a, int codepoint, int fromByteIndex, int toByteIndex, Encoding expectedEncoding); @Specialization - static int doIndexOf(AbstractTruffleString a, int codepoint, int fromIndexB, int toIndexB, Encoding expectedEncoding, + static int doIndexOf(AbstractTruffleString a, int codepoint, int fromByteIndex, int toByteIndex, Encoding expectedEncoding, @Cached ToIndexableNode toIndexableNode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeNode, @Cached TStringInternalNodes.IndexOfCodePointRawNode indexOfNode) { @@ -3289,8 +3289,8 @@ static int doIndexOf(AbstractTruffleString a, int codepoint, int fromIndexB, int if (a.isEmpty()) { return -1; } - final int fromIndex = rawIndex(fromIndexB, expectedEncoding); - final int toIndex = rawIndex(toIndexB, expectedEncoding); + final int fromIndex = rawIndex(fromByteIndex, expectedEncoding); + final int toIndex = rawIndex(toByteIndex, expectedEncoding); a.boundsCheckRaw(fromIndex, toIndex); return byteIndex(indexOfNode.execute(a, toIndexableNode.execute(a, a.data()), getCodeRangeNode.execute(a), codepoint, fromIndex, toIndex), expectedEncoding); } @@ -3392,7 +3392,7 @@ public abstract static class LastByteIndexOfCodePointNode extends Node { public abstract int execute(AbstractTruffleString a, int codepoint, int fromByteIndex, int toByteIndex, Encoding expectedEncoding); @Specialization - static int doIndexOf(AbstractTruffleString a, int codepoint, int fromIndexB, int toIndexB, Encoding expectedEncoding, + static int doIndexOf(AbstractTruffleString a, int codepoint, int fromByteIndex, int toByteIndex, Encoding expectedEncoding, @Cached ToIndexableNode toIndexableNode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeNode, @Cached TStringInternalNodes.LastIndexOfCodePointRawNode lastIndexOfNode) { @@ -3400,8 +3400,8 @@ static int doIndexOf(AbstractTruffleString a, int codepoint, int fromIndexB, int if (a.isEmpty()) { return -1; } - final int fromIndex = rawIndex(fromIndexB, expectedEncoding); - final int toIndex = rawIndex(toIndexB, expectedEncoding); + final int fromIndex = rawIndex(fromByteIndex, expectedEncoding); + final int toIndex = rawIndex(toByteIndex, expectedEncoding); a.boundsCheckRaw(toIndex, fromIndex); return byteIndex(lastIndexOfNode.execute(a, toIndexableNode.execute(a, a.data()), getCodeRangeNode.execute(a), codepoint, fromIndex, toIndex), expectedEncoding); } @@ -3453,7 +3453,8 @@ public abstract static class IndexOfStringNode extends Node { static int indexOfString(AbstractTruffleString a, AbstractTruffleString b, int fromIndex, int toIndex, Encoding expectedEncoding, @Cached ToIndexableNode toIndexableNodeA, @Cached ToIndexableNode toIndexableNodeB, - @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthNode, + @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthANode, + @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthBNode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeANode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeBNode, @Cached TStringInternalNodes.IndexOfStringNode indexOfStringNode) { @@ -3467,10 +3468,10 @@ static int indexOfString(AbstractTruffleString a, AbstractTruffleString b, int f if (a.isEmpty()) { return -1; } - a.boundsCheck(fromIndex, toIndex, getCodePointLengthNode); + a.boundsCheck(fromIndex, toIndex, getCodePointLengthANode); Object arrayA = toIndexableNodeA.execute(a, a.data()); Object arrayB = toIndexableNodeB.execute(b, b.data()); - if (indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null)) { + if (indexOfCannotMatch(codeRangeA, b, codeRangeB, toIndex - fromIndex, getCodePointLengthBNode)) { return -1; } return indexOfStringNode.execute(a, arrayA, codeRangeA, b, arrayB, codeRangeB, fromIndex, toIndex); @@ -3537,10 +3538,10 @@ public final int execute(AbstractTruffleString a, WithMask b, int fromByteIndex, return execute(a, b.string, fromByteIndex, toByteIndex, b.mask, expectedEncoding); } - abstract int execute(AbstractTruffleString a, AbstractTruffleString b, int fromIndex, int toIndex, byte[] mask, Encoding expectedEncoding); + abstract int execute(AbstractTruffleString a, AbstractTruffleString b, int fromByteIndex, int toByteIndex, byte[] mask, Encoding expectedEncoding); @Specialization - static int indexOfString(AbstractTruffleString a, AbstractTruffleString b, int fromIndexB, int toIndexB, byte[] mask, Encoding expectedEncoding, + static int indexOfString(AbstractTruffleString a, AbstractTruffleString b, int fromByteIndex, int toByteIndex, byte[] mask, Encoding expectedEncoding, @Cached ToIndexableNode toIndexableNodeA, @Cached ToIndexableNode toIndexableNodeB, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeANode, @@ -3554,17 +3555,17 @@ static int indexOfString(AbstractTruffleString a, AbstractTruffleString b, int f throw InternalErrors.unsupportedOperation(); } if (b.isEmpty()) { - return fromIndexB; + return fromByteIndex; } if (a.isEmpty()) { return -1; } - final int fromIndex = rawIndex(fromIndexB, expectedEncoding); - final int toIndex = rawIndex(toIndexB, expectedEncoding); + final int fromIndex = rawIndex(fromByteIndex, expectedEncoding); + final int toIndex = rawIndex(toByteIndex, expectedEncoding); a.boundsCheckRaw(fromIndex, toIndex); Object arrayA = toIndexableNodeA.execute(a, a.data()); Object arrayB = toIndexableNodeB.execute(b, b.data()); - if (indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask)) { + if (indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, toIndex - fromIndex)) { return -1; } return byteIndex(indexOfStringNode.execute(a, arrayA, codeRangeA, b, arrayB, codeRangeB, fromIndex, toIndex, mask), expectedEncoding); @@ -3617,7 +3618,8 @@ public abstract static class LastIndexOfStringNode extends Node { static int lastIndexOfString(AbstractTruffleString a, AbstractTruffleString b, int fromIndex, int toIndex, Encoding expectedEncoding, @Cached ToIndexableNode toIndexableNodeA, @Cached ToIndexableNode toIndexableNodeB, - @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthNode, + @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthANode, + @Cached TStringInternalNodes.GetCodePointLengthNode getCodePointLengthBNode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeANode, @Cached TStringInternalNodes.GetCodeRangeNode getCodeRangeBNode, @Cached TStringInternalNodes.LastIndexOfStringNode indexOfStringNode) { @@ -3631,10 +3633,10 @@ static int lastIndexOfString(AbstractTruffleString a, AbstractTruffleString b, i if (a.isEmpty()) { return -1; } - a.boundsCheck(toIndex, fromIndex, getCodePointLengthNode); + a.boundsCheck(toIndex, fromIndex, getCodePointLengthANode); Object arrayA = toIndexableNodeA.execute(a, a.data()); Object arrayB = toIndexableNodeB.execute(b, b.data()); - if (indexOfCannotMatch(a, codeRangeA, b, codeRangeB, null)) { + if (indexOfCannotMatch(codeRangeA, b, codeRangeB, fromIndex - toIndex, getCodePointLengthBNode)) { return -1; } return indexOfStringNode.execute(a, arrayA, codeRangeA, b, arrayB, codeRangeB, fromIndex, toIndex); @@ -3728,7 +3730,7 @@ static int lastByteIndexOfString(AbstractTruffleString a, AbstractTruffleString a.boundsCheckRaw(toIndex, fromIndex); Object arrayA = toIndexableNodeA.execute(a, a.data()); Object arrayB = toIndexableNodeB.execute(b, b.data()); - if (indexOfCannotMatch(a, codeRangeA, b, codeRangeB, mask)) { + if (indexOfCannotMatch(codeRangeA, b, codeRangeB, mask, fromIndex - toIndex)) { return -1; } return byteIndex(indexOfStringNode.execute(a, arrayA, codeRangeA, b, arrayB, codeRangeB, fromIndex, toIndex, mask), expectedEncoding); diff --git a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleStringIterator.java b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleStringIterator.java index 05c19baf605b..032b86a08c64 100644 --- a/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleStringIterator.java +++ b/truffle/src/com.oracle.truffle.api.strings/src/com/oracle/truffle/api/strings/TruffleStringIterator.java @@ -579,6 +579,9 @@ static int indexOfString(Node location, TruffleStringIterator aIt, TruffleString int bSecondIndex = bIt.getRawIndex(); while (aIt.hasNext() && aCodepointIndex < toIndex) { if (nextNodeA.execute(aIt) == bFirst) { + if (!bIt.hasNext()) { + return aCodepointIndex; + } int aCurIndex = aIt.getRawIndex(); int innerLoopCount = 0; while (bIt.hasNext()) { @@ -588,11 +591,11 @@ static int indexOfString(Node location, TruffleStringIterator aIt, TruffleString if (nextNodeA.execute(aIt) != nextNodeB.execute(bIt)) { break; } + if (!bIt.hasNext()) { + return aCodepointIndex; + } TStringConstants.truffleSafePointPoll(location, ++innerLoopCount); } - if (!bIt.hasNext()) { - return aCodepointIndex; - } aIt.setRawIndex(aCurIndex); bIt.setRawIndex(bSecondIndex); } @@ -613,6 +616,9 @@ static int byteIndexOfString(Node location, TruffleStringIterator aIt, TruffleSt while (aIt.hasNext() && aIt.getRawIndex() < toByteIndex) { int ret = aIt.getRawIndex(); if (nextNodeA.execute(aIt) == bFirst) { + if (!bIt.hasNext()) { + return ret; + } int aCurIndex = aIt.getRawIndex(); while (bIt.hasNext()) { if (!aIt.hasNext()) { @@ -621,11 +627,11 @@ static int byteIndexOfString(Node location, TruffleStringIterator aIt, TruffleSt if (nextNodeA.execute(aIt) != nextNodeB.execute(bIt)) { break; } + if (!bIt.hasNext()) { + return ret; + } TStringConstants.truffleSafePointPoll(location, ++loopCount); } - if (!bIt.hasNext()) { - return ret; - } aIt.setRawIndex(aCurIndex); bIt.setRawIndex(bSecondIndex); } @@ -658,6 +664,9 @@ static int lastIndexOfString(Node location, TruffleStringIterator aIt, TruffleSt int bSecondIndex = bIt.getRawIndex(); while (aIt.hasPrevious() && aCodepointIndex >= toIndex) { if (prevNodeA.execute(aIt) == bFirstCodePoint) { + if (!bIt.hasPrevious()) { + return aCodepointIndex; + } int aCurIndex = aIt.getRawIndex(); int aCurCodePointIndex = aCodepointIndex; while (bIt.hasPrevious()) { @@ -668,11 +677,11 @@ static int lastIndexOfString(Node location, TruffleStringIterator aIt, TruffleSt break; } aCurCodePointIndex--; + if (!bIt.hasPrevious() && aCurCodePointIndex >= toIndex) { + return aCurCodePointIndex; + } TStringConstants.truffleSafePointPoll(location, aCurCodePointIndex); } - if (!bIt.hasPrevious()) { - return aCurCodePointIndex; - } aIt.setRawIndex(aCurIndex); bIt.setRawIndex(bSecondIndex); } @@ -701,8 +710,11 @@ static int lastByteIndexOfString(Node location, TruffleStringIterator aIt, Truff } aIt.setRawIndex(lastMatchByteIndex); int bSecondIndex = bIt.getRawIndex(); - while (aIt.hasPrevious() && aIt.getRawIndex() >= toByteIndex) { + while (aIt.hasPrevious() && aIt.getRawIndex() > toByteIndex) { if (prevNodeA.execute(aIt) == bFirstCodePoint) { + if (!bIt.hasPrevious()) { + return aIt.getRawIndex(); + } int aCurIndex = aIt.getRawIndex(); while (bIt.hasPrevious()) { if (!aIt.hasPrevious()) { @@ -711,11 +723,11 @@ static int lastByteIndexOfString(Node location, TruffleStringIterator aIt, Truff if (prevNodeA.execute(aIt) != prevNodeB.execute(bIt)) { break; } + if (!bIt.hasPrevious() && aIt.getRawIndex() >= toByteIndex) { + return aIt.getRawIndex(); + } TStringConstants.truffleSafePointPoll(location, ++loopCount); } - if (!bIt.hasPrevious()) { - return aIt.getRawIndex(); - } aIt.setRawIndex(aCurIndex); bIt.setRawIndex(bSecondIndex); }