Path: blob/master/test/hotspot/jtreg/compiler/intrinsics/string/TestStringIntrinsics.java
41153 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 805430726* @summary Tests correctness of string related intrinsics and C2 optimizations.27* @library /test/lib28*29* @run main/timeout=240 compiler.intrinsics.string.TestStringIntrinsics30*/3132package compiler.intrinsics.string;3334import jdk.test.lib.format.Format;35import jdk.test.lib.format.ArrayCodec;3637import java.lang.annotation.ElementType;38import java.lang.annotation.Retention;39import java.lang.annotation.RetentionPolicy;40import java.lang.annotation.Target;41import java.lang.reflect.Method;42import java.util.Arrays;4344public class TestStringIntrinsics {4546public enum Operation {47ARR_EQUALS_B, ARR_EQUALS_C, EQUALS, COMPARE_TO, INDEX_OF, INDEX_OF_CON_U, INDEX_OF_CON_L,48INDEX_OF_CON_UL, CONCAT, CONCAT_C, CONCAT_I, CONCAT_M, INDEX_OF_CHAR49}5051@Retention(RetentionPolicy.RUNTIME)52@Target(ElementType.METHOD)53@interface Test {54Operation op();55String constString() default "";56String[] inStrings() default {};57char[] inChars() default {};58int[] inInts() default {};59String[] outStrings() default {};60}6162public static void main(String[] args) throws Exception {63new TestStringIntrinsics().run();64}6566public void run() throws Exception {67// Build latin1 and UTF16 strings68StringBuilder latin1Builder = new StringBuilder();69for (int i = 0; i <= 255; ++i) {70latin1Builder.append((char) i);71}72String latin1 = latin1Builder.toString();73StringBuilder utf16Builder = new StringBuilder();74for (int i = 0; i <= 10000; ++i) {75utf16Builder.append((char) i);76}77String utf16 = utf16Builder.toString();7879// Invoke test methods80for (Method m : TestStringIntrinsics.class.getMethods()) {81if (m.isAnnotationPresent(Test.class)) {82System.out.print("Checking " + m.getName() + "... ");83Test antn = m.getAnnotation(Test.class);84Operation op = antn.op();85if (isStringConcatTest(op)) {86checkStringConcat(op, m, antn);87} else {88checkIntrinsics(op, m, latin1, utf16, antn);89}90System.out.println("Done.");91}92}93}9495private boolean isStringConcatTest(Operation op) {96return op == Operation.CONCAT ||97op == Operation.CONCAT_C ||98op == Operation.CONCAT_I ||99op == Operation.CONCAT_M;100}101102/**103* Checks correctness of the String.equals, String.compareTo and String.indexOf intrinsics.104* -XX:SpecialStringEquals105* -XX:SpecialStringCompareTo106* -XX:SpecialStringIndexOf107*/108private void checkIntrinsics(Operation op, Method m, String latin1, String utf16, Test antn) throws Exception {109for (int i = 0; i < 50_000; ++i) {110// Copy and permute latin1 and UTF16 string111char[] arrL = latin1.toCharArray();112int indexL = i % arrL.length;113int mod = (arrL.length - arrL[indexL]);114int incL = i % ((mod != 0) ? mod : 1);115arrL[indexL] = (char) ((int) arrL[indexL] + incL);116String latin1Copy = String.valueOf(arrL);117118char[] arrU = utf16.toCharArray();119int indexU = i % arrU.length;120mod = (arrU.length - arrU[indexU]);121int incU = i % ((mod != 0) ? mod : 1);122arrU[indexU] = (char) ((int) arrU[indexU] + incU);123String utf16Copy = String.valueOf(arrU);124125switch (op) {126case ARR_EQUALS_B:127invokeAndCompareArrays(m, (incL == 0), latin1.getBytes("ISO-8859-1"), latin1Copy.getBytes("ISO-8859-1"));128invokeAndCompareArrays(m, true, new byte[] {1, 2, 3}, new byte[] {1, 2, 3});129invokeAndCompareArrays(m, true, new byte[] {1}, new byte[] {1});130invokeAndCompareArrays(m, true, new byte[] {}, new byte[] {});131break;132case ARR_EQUALS_C:133invokeAndCompareArrays(m, (incU == 0), utf16.toCharArray(), arrU);134break;135case EQUALS:136invokeAndCheck(m, (incL == 0), latin1, latin1Copy);137invokeAndCheck(m, false, latin1, "");138invokeAndCheck(m, false, "", latin1);139140invokeAndCheck(m, (incU == 0), utf16, utf16Copy);141invokeAndCheck(m, false, utf16, "");142invokeAndCheck(m, false, "", utf16);143144invokeAndCheck(m, false, latin1, utf16);145break;146case COMPARE_TO:147invokeAndCheck(m, -incL, latin1, latin1Copy);148invokeAndCheck(m, latin1.length(), latin1, "");149150invokeAndCheck(m, -incU, utf16, utf16Copy);151invokeAndCheck(m, utf16.length(), utf16, "");152153// Cross coder154char cL = latin1.charAt(indexL);155char cU = utf16.charAt(indexU);156invokeAndCheck(m, cL - cU, latin1, latin1.replace(cL, cU));157invokeAndCheck(m, cU - cL, utf16, utf16.replace(cU, cL));158159// Different lengths160invokeAndCheck(m, 1, "ABCD", "ABC");161invokeAndCheck(m, -1, "\uff21\uff22\uff23", "\uff21\uff22\uff23\uff24");162invokeAndCheck(m, 1, "ABC\uff24", "ABC");163invokeAndCheck(m, 3, "ABC\uff24\uff25\uff26", "ABC");164invokeAndCheck(m, -1, "ABC","ABC\uff24");165invokeAndCheck(m, -3, "ABC","ABC\uff24\uff25\uff26");166break;167case INDEX_OF:168invokeAndCheck(m, indexL, latin1, latin1.substring(indexL), (indexL > 42) ? 42 : 0);169invokeAndCheck(m, 0, latin1, "", 0);170171invokeAndCheck(m, indexU, utf16, utf16.substring(indexU), (indexU > 42) ? 42 : 0);172invokeAndCheck(m, 0, utf16, "", 0);173174// Cross coder175invokeAndCheck(m, -1, latin1.substring(0, indexL), utf16.substring(indexU), (indexL > 42) ? 42 : 0);176// Skip latin1 chars in utf16 string177int start = 256;178int end = indexU > start ? indexU : start;179invokeAndCheck(m, end-start, utf16.substring(start, end) + latin1.substring(indexL), latin1.substring(indexL), 0);180break;181case INDEX_OF_CON_L:182invokeAndCheck(m, antn.constString(), latin1);183break;184case INDEX_OF_CON_U:185invokeAndCheck(m, antn.constString(), utf16);186break;187case INDEX_OF_CON_UL:188invokeAndCheck(m, antn.constString(), utf16);189break;190case INDEX_OF_CHAR:191invokeAndCheck(m, 7, "abcdefg\uD800\uDC00", 65536, 0);192invokeAndCheck(m, -1, "abcdefg\uD800\uDC01", 65536, 0);193invokeAndCheck(m, -1, "abcdefg\uD800", 65536, 0);194invokeAndCheck(m, 3, "abc\u0107", 263, 0);195invokeAndCheck(m, -1, "abc\u0108", 263, 0);196invokeAndCheck(m, 7, "abcdefg\u0107", 263, 0);197invokeAndCheck(m, 7, "abcdefg\u0107", 263, -1);198invokeAndCheck(m, 0, "\u0107", 263, 0);199break;200default:201throw new RuntimeException("Unexpected operation.");202}203}204}205206/**207* Checks correctness of the C2 string concatenation optimization.208* -XX:OptimizeStringConcat209*/210private void checkStringConcat(Operation op, Method m, Test antn) throws Exception {211for (int i = 0; i < 50_000; ++i) {212String[] result = antn.outStrings();213switch(op) {214case CONCAT:215String[] strs = antn.inStrings();216for (int j = 0; j < strs.length; ++j) {217invokeAndCheck(m, result[j], strs[j]);218}219break;220case CONCAT_C:221char[] ch = antn.inChars();222for (int j = 0; j < ch.length; ++j) {223invokeAndCheck(m, result[j], ch[j]);224}225break;226case CONCAT_I:227int[] k = antn.inInts();228for (int j = 0; j < k.length; ++j) {229invokeAndCheck(m, result[j], k[j]);230}231break;232case CONCAT_M:233strs = antn.inStrings();234ch = antn.inChars();235k = antn.inInts();236for (int j = 0; j < strs.length; ++j) {237invokeAndCheck(m, result[j], strs[j], ch[j], k[j]);238}239break;240default:241throw new RuntimeException("Unexpected operation.");242}243}244}245246/**247* Invokes method 'm' by passing arguments the two 'args' (which are supposed to be arrays)248* checks if the returned value. In case of error and arrays being not equal, prints their difference.249*/250private void invokeAndCompareArrays(Method m, boolean expectedResult, Object arg0, Object arg1) throws Exception {251boolean result = (Boolean)m.invoke(null, arg0, arg1);252if (expectedResult == result)253return;254255String cause = String.format("Result: (%b) of '%s' is not equal to expected (%b)",256result, m.getName(), expectedResult);257258if (expectedResult == true) {259System.err.println(cause);260System.err.println(Format.arrayDiff(arg0, arg1));261} else {262System.err.println(cause);263System.err.printf("First array argument: %n %s%n", ArrayCodec.format(arg0));264}265266throw new RuntimeException(cause);267}268269/**270* Invokes method 'm' by passing arguments 'args' and checks if the271* returned value equals 'expectedResult'.272*/273private void invokeAndCheck(Method m, Object expectedResult, Object... args) throws Exception {274Object actualResult = m.invoke(null, args);275if (!actualResult.equals(expectedResult)) {276var nl = System.lineSeparator();277StringBuilder msgBuilder = new StringBuilder();278msgBuilder.append("Actual result of '" + m.getName() + "' is not equal to expected value." + nl);279msgBuilder.append("Expected: " + Format.asLiteral(expectedResult) + nl);280msgBuilder.append("Actual: " + Format.asLiteral(actualResult));281282for (int i = 0; i < args.length; i++) {283msgBuilder.append(nl + " Arg" + i + ": " + Format.asLiteral(args[i]));284}285286final String message = msgBuilder.toString();287System.err.println(message);288throw new RuntimeException(message);289}290}291292/*293* Constants294*/295static final char charU = '\uff21';296static final char charL = 'A';297static final String emptyString = "";298static final String stringL = "abcdefghijklmnop";299static final String stringSmallL = "abc";300static final String stringU = "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28";301static final String stringSmallU = "\u0f21\u0f22\u0f23";302static final int constInt = 123;303static final int constIntNeg = -123;304305/*306* Arrays.equals307*/308@Test(op = Operation.ARR_EQUALS_B)309public static boolean arrayEqualsB(byte[] a, byte[] b) {310return Arrays.equals(a, b);311}312313@Test(op = Operation.ARR_EQUALS_C)314public static boolean arrayEqualsC(char[] a, char[] b) {315return Arrays.equals(a, b);316}317318/*319* String.equals320*/321@Test(op = Operation.EQUALS)322public static boolean equals(String a, String b) {323return a.equals(b);324}325326/*327* String.compareTo328*/329@Test(op = Operation.COMPARE_TO)330public static int compareTo(String a, String b) {331return a.compareTo(b);332}333334/*335* String.indexOf336*/337@Test(op = Operation.INDEX_OF)338public static int indexOf(String a, String b, int from) {339return a.indexOf(b, from);340}341342@Test(op = Operation.INDEX_OF_CON_U, constString = stringSmallU)343public static String indexOfConstU(String a) {344int result = a.indexOf(stringSmallU);345return a.substring(result, result + stringSmallU.length());346}347348@Test(op = Operation.INDEX_OF_CON_U, constString = stringU)349public static String indexOfConstLargeU(String a) {350int result = a.indexOf(stringU);351return a.substring(result, result + stringU.length());352}353354@Test(op = Operation.INDEX_OF_CON_U, constString = emptyString)355public static String indexOfConstEmptyU(String a) {356int result = a.indexOf(emptyString);357return a.substring(result, result + emptyString.length());358}359360@Test(op = Operation.INDEX_OF_CON_L, constString = stringSmallL)361public static String indexOfConstL(String a) {362int result = a.indexOf(stringSmallL);363return a.substring(result, result + stringSmallL.length());364}365366@Test(op = Operation.INDEX_OF_CON_L, constString = stringL)367public static String indexOfConstLargeL(String a) {368int result = a.indexOf(stringL);369return a.substring(result, result + stringL.length());370}371372@Test(op = Operation.INDEX_OF_CON_L, constString = emptyString)373public static String indexOfConstEmptyL(String a) {374int result = a.indexOf(emptyString);375return a.substring(result, result + emptyString.length());376}377378@Test(op = Operation.INDEX_OF_CON_UL, constString = stringSmallL)379public static String indexOfConstUL(String a) {380int result = a.indexOf(stringSmallL);381return a.substring(result, result + stringSmallL.length());382}383384@Test(op = Operation.INDEX_OF_CON_UL, constString = stringL)385public static String indexOfConstLargeUL(String a) {386int result = a.indexOf(stringL);387return a.substring(result, result + stringL.length());388}389390@Test(op = Operation.INDEX_OF_CHAR)391public static int indexOfChar(String a, int ch, int from) {392return a.indexOf(ch, from);393}394395/*396* String concatenation optimization397*/398@Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"ABC", "\uff21\uff22\uff23"})399public static String concatString(String a) {400return new StringBuilder().append(a).toString();401}402403@Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {""})404public static String concatStringEmpty(String a) {405return new StringBuilder().toString();406}407408@Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"null"})409public static String concatStringNull(String a) {410return new StringBuilder().append((String)null).toString();411}412413@Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"abcdefghijklmnopABCabc", "abcdefghijklmnop\uff21\uff22\uff23abc"})414public static String concatStringConstL(String a) {415return new StringBuilder().append(stringL).append(a).append(stringSmallL).toString();416}417418@Test(op = Operation.CONCAT, inStrings = {"ABC", "\uff21\uff22\uff23"}, outStrings = {"\u0f21\u0f22\u0f23ABC\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28", "\u0f21\u0f22\u0f23\uff21\uff22\uff23\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"})419public static String concatStringConstU(String a) {420return new StringBuilder().append(stringSmallU).append(a).append(stringU).toString();421}422423@Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"A", "\uff21"})424public static String concatChar(char a) {425return new StringBuilder().append(a).toString();426}427428@Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"abcdefghijklmnopAabcA\uff21", "abcdefghijklmnop\uff21abcA\uff21"})429public static String concatCharConstL(char a) {430return new StringBuilder().append(stringL).append(a).append(stringSmallL).append(charL).append(charU).toString();431}432433@Test(op = Operation.CONCAT_C, inChars = {'A', '\uff21'}, outStrings = {"\u0f21\u0f22\u0f23A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21A", "\u0f21\u0f22\u0f23\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21A"})434public static String concatCharConstU(char a) {435return new StringBuilder().append(stringSmallU).append(a).append(stringU).append(charU).append(charL).toString();436}437438@Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"-2147483648", "-42", "42", "2147483647"})439public static String concatInt(int a) {440return new StringBuilder().append(a).toString();441}442443@Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"abcdefghijklmnop-2147483648abc123-123", "abcdefghijklmnop-42abc123-123", "abcdefghijklmnop42abc123-123", "abcdefghijklmnop2147483647abc123-123"})444public static String concatIntConstL(int b) {445return new StringBuilder().append(stringL).append(b).append(stringSmallL).append(constInt).append(constIntNeg).toString();446}447448@Test(op = Operation.CONCAT_I, inInts = {Integer.MIN_VALUE, -42, 42, Integer.MAX_VALUE}, outStrings = {"\u0f21\u0f22\u0f23-2147483648\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f23-42\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f2342\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123", "\u0f21\u0f22\u0f232147483647\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28123-123"})449public static String concatIntConstU(int b) {450return new StringBuilder().append(stringSmallU).append(b).append(stringU).append(constInt).append(constIntNeg).toString();451}452453@Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnopA123-123"})454public static String concatConstL(String a) {455return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(charL).append(constInt).append(constIntNeg).toString();456}457458@Test(op = Operation.CONCAT, inStrings = {""}, outStrings = {"nullabcabcdefghijklmnop\u0f21\u0f22\u0f23\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A\uff21123-123"})459public static String concatConstU(String a) {460return new StringBuilder().append((String)null).append(stringSmallL).append(stringL).append(stringSmallU).append(stringU).append(charL).append(charU).append(constInt).append(constIntNeg).toString();461}462463@Test(op = Operation.CONCAT_M,464inStrings = {"ABCDEFG", "ABCDEFG", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28", "\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28"},465inChars = {'A', '\uff21', 'A', '\uff21'},466inInts = {Integer.MIN_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MAX_VALUE},467outStrings = {"ABCDEFGA-2147483648nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFGA-2147483648null",468"ABCDEFG\uff212147483647nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21ABCDEFG\uff212147483647null",469"\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A-2147483648nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28A-2147483648null",470"\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff212147483647nullabcdefghijklmnop123-123A\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff21\u0f21\u0f22\u0f23\u0f24\u0f25\u0f26\u0f27\u0f28\uff212147483647null"})471public static String concatMixed(String a, char b, int c) {472return new StringBuilder().append(a).append(b).append(c).append((String)null)473.append(stringL).append(constInt).append(constIntNeg).append(charL).append(stringU).append(charU)474.append(a).append(b).append(c).append((String)null).toString();475}476}477478479