1 /* 2 * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.Serializable; 25 import java.lang.invoke.*; 26 import java.util.concurrent.Callable; 27 28 /** 29 * @test 30 * @summary Test input invariants for StringConcatFactory 31 * 32 * @compile StringConcatFactoryInvariants.java 33 * 34 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB StringConcatFactoryInvariants 35 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED StringConcatFactoryInvariants 36 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED StringConcatFactoryInvariants 37 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT StringConcatFactoryInvariants 38 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT StringConcatFactoryInvariants 39 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT StringConcatFactoryInvariants 40 * 41 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 42 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 43 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 44 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 45 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 46 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true StringConcatFactoryInvariants 47 * 48 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 49 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 50 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 51 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 52 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 53 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 54 * 55 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 56 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 57 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 58 * @run main/othervm -Djava.lang.invoke.stringConcat=BC_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 59 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_SB_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 60 * @run main/othervm -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants 61 * 62 */ 63 public class StringConcatFactoryInvariants { 64 65 private static final char TAG_ARG = '\u0001'; 66 private static final char TAG_CONST = '\u0002'; 67 68 public static void main(String[] args) throws Throwable { 69 MethodHandles.Lookup lookup = MethodHandles.publicLookup(); 70 String methodName = "foo"; 71 MethodType mt = MethodType.methodType(String.class, String.class, int.class); 72 String recipe = "" + TAG_ARG + TAG_ARG + TAG_CONST; 73 String[] constants = new String[]{"bar"}; 74 75 final int LIMIT = 200; 76 77 // Simple factory: check for dynamic arguments overflow 78 Class<?>[] underThreshold = new Class<?>[LIMIT - 1]; 79 Class<?>[] threshold = new Class<?>[LIMIT]; 80 Class<?>[] overThreshold = new Class<?>[LIMIT + 1]; 81 82 StringBuilder sbUnderThreshold = new StringBuilder(); 83 sbUnderThreshold.append(TAG_CONST); 84 for (int c = 0; c < LIMIT - 1; c++) { 85 underThreshold[c] = int.class; 86 threshold[c] = int.class; 87 overThreshold[c] = int.class; 88 sbUnderThreshold.append(TAG_ARG); 89 } 90 threshold[LIMIT - 1] = int.class; 91 overThreshold[LIMIT - 1] = int.class; 92 overThreshold[LIMIT] = int.class; 93 94 String recipeEmpty = ""; 95 String recipeUnderThreshold = sbUnderThreshold.toString(); 96 String recipeThreshold = sbUnderThreshold.append(TAG_ARG).toString(); 97 String recipeOverThreshold = sbUnderThreshold.append(TAG_ARG).toString(); 98 99 MethodType mtEmpty = MethodType.methodType(String.class); 100 MethodType mtUnderThreshold = MethodType.methodType(String.class, underThreshold); 101 MethodType mtThreshold = MethodType.methodType(String.class, threshold); 102 MethodType mtOverThreshold = MethodType.methodType(String.class, overThreshold); 103 104 105 // Check the basic functionality is working 106 { 107 CallSite cs = StringConcatFactory.makeConcat(lookup, methodName, mt); 108 test("foo42", (String) cs.getTarget().invokeExact("foo", 42)); 109 } 110 111 { 112 CallSite cs = StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, constants); 113 test("foo42bar", (String) cs.getTarget().invokeExact("foo", 42)); 114 } 115 116 // Simple factory, check for nulls: 117 failNPE("Lookup is null", 118 () -> StringConcatFactory.makeConcat(null, methodName, mt)); 119 120 failNPE("Method name is null", 121 () -> StringConcatFactory.makeConcat(lookup, null, mt)); 122 123 failNPE("MethodType is null", 124 () -> StringConcatFactory.makeConcat(lookup, methodName, null)); 125 126 // Advanced factory, check for nulls: 127 failNPE("Lookup is null", 128 () -> StringConcatFactory.makeConcatWithConstants(null, methodName, mt, recipe, constants)); 129 130 failNPE("Method name is null", 131 () -> StringConcatFactory.makeConcatWithConstants(lookup, null, mt, recipe, constants)); 132 133 failNPE("MethodType is null", 134 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, null, recipe, constants)); 135 136 failNPE("Recipe is null", 137 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, null, constants)); 138 139 failNPE("Constants vararg is null", 140 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, null)); 141 142 // Simple factory, check for return type 143 fail("Return type: void", 144 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(void.class, String.class, int.class))); 145 146 fail("Return type: int", 147 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(int.class, String.class, int.class))); 148 149 fail("Return type: StringBuilder", 150 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class))); 151 152 ok("Return type: Object", 153 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class))); 154 155 ok("Return type: CharSequence", 156 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class))); 157 158 ok("Return type: Serializable", 159 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class))); 160 161 // Advanced factory, check for return types 162 fail("Return type: void", 163 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(void.class, String.class, int.class), recipe, constants)); 164 165 fail("Return type: int", 166 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(int.class, String.class, int.class), recipe, constants)); 167 168 fail("Return type: StringBuilder", 169 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class), recipe, constants)); 170 171 ok("Return type: Object", 172 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class), recipe, constants)); 173 174 ok("Return type: CharSequence", 175 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class), recipe, constants)); 176 177 ok("Return type: Serializable", 178 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class), recipe, constants)); 179 180 // Simple factory: check for dynamic arguments overflow 181 ok("Dynamic arguments is under limit", 182 () -> StringConcatFactory.makeConcat(lookup, methodName, mtUnderThreshold)); 183 184 ok("Dynamic arguments is at the limit", 185 () -> StringConcatFactory.makeConcat(lookup, methodName, mtThreshold)); 186 187 fail("Dynamic arguments is over the limit", 188 () -> StringConcatFactory.makeConcat(lookup, methodName, mtOverThreshold)); 189 190 // Advanced factory: check for dynamic arguments overflow 191 ok("Dynamic arguments is under limit", 192 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtUnderThreshold, recipeUnderThreshold, constants)); 193 194 ok("Dynamic arguments is at the limit", 195 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants)); 196 197 fail("Dynamic arguments is over the limit", 198 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtOverThreshold, recipeOverThreshold, constants)); 199 200 // Advanced factory: check for mismatched recipe and Constants 201 ok("Static arguments and recipe match", 202 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar")); 203 204 fail("Static arguments and recipe mismatch", 205 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar", "baz")); 206 207 // Advanced factory: check for mismatched recipe and dynamic arguments 208 fail("Dynamic arguments and recipe mismatch", 209 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeUnderThreshold, constants)); 210 211 ok("Dynamic arguments and recipe match", 212 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants)); 213 214 fail("Dynamic arguments and recipe mismatch", 215 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeOverThreshold, constants)); 216 217 // Test passing array as constant 218 { 219 String[] arg = {"boo", "bar"}; 220 221 CallSite cs1 = StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST + TAG_CONST, arg); 222 test("42boobar", (String) cs1.getTarget().invokeExact(42)); 223 } 224 225 // Test passing null constant 226 ok("Can pass regular constants", 227 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, "foo")); 228 229 failNPE("Cannot pass null constants", 230 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, new String[]{null})); 231 232 // Simple factory: test empty arguments 233 ok("Ok to pass empty arguments", 234 () -> StringConcatFactory.makeConcat(lookup, methodName, mtEmpty)); 235 236 // Advanced factory: test empty arguments 237 ok("Ok to pass empty arguments", 238 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtEmpty, recipeEmpty)); 239 } 240 241 public static void ok(String msg, Callable runnable) { 242 try { 243 runnable.call(); 244 } catch (Throwable e) { 245 e.printStackTrace(); 246 throw new IllegalStateException(msg + ", should have passed", e); 247 } 248 } 249 250 public static void fail(String msg, Callable runnable) { 251 boolean expected = false; 252 try { 253 runnable.call(); 254 } catch (StringConcatException e) { 255 expected = true; 256 } catch (Throwable e) { 257 e.printStackTrace(); 258 } 259 260 if (!expected) { 261 throw new IllegalStateException(msg + ", should have failed with StringConcatException"); 262 } 263 } 264 265 266 public static void failNPE(String msg, Callable runnable) { 267 boolean expected = false; 268 try { 269 runnable.call(); 270 } catch (NullPointerException e) { 271 expected = true; 272 } catch (Throwable e) { 273 e.printStackTrace(); 274 } 275 276 if (!expected) { 277 throw new IllegalStateException(msg + ", should have failed with NullPointerException"); 278 } 279 } 280 281 public static void test(String expected, String actual) { 282 // Fingers crossed: String concat should work. 283 if (!expected.equals(actual)) { 284 StringBuilder sb = new StringBuilder(); 285 sb.append("Expected = "); 286 sb.append(expected); 287 sb.append(", actual = "); 288 sb.append(actual); 289 throw new IllegalStateException(sb.toString()); 290 } 291 } 292 293 }