53 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
54 *
55 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
56 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
57 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
58 * @run main/othervm -Xverify:all -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 -Xverify:all -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 -Xverify:all -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.lookup();
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 // Simple factory: public Lookup is rejected
241 fail("Passing public Lookup",
242 () -> StringConcatFactory.makeConcat(MethodHandles.publicLookup(), methodName, mtEmpty));
243
244 // Advanced factory: public Lookup is rejected
245 fail("Passing public Lookup",
246 () -> StringConcatFactory.makeConcatWithConstants(MethodHandles.publicLookup(), methodName, mtEmpty, recipeEmpty));
247 }
248
249 public static void ok(String msg, Callable runnable) {
250 try {
|
53 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_INLINE_SIZED_EXACT -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
54 *
55 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
56 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=BC_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
57 * @run main/othervm -Xverify:all -Djava.lang.invoke.stringConcat=MH_SB_SIZED -Djava.lang.invoke.stringConcat.debug=true -Djava.lang.invoke.stringConcat.cache=true StringConcatFactoryInvariants
58 * @run main/othervm -Xverify:all -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 -Xverify:all -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 -Xverify:all -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.lookup();
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 Object[][] constants = new Object[][] {
74 new String[] { "bar" },
75 new Integer[] { 1 },
76 new Short[] { 2 },
77 new Long[] { 3L },
78 new Boolean[] { true },
79 new Character[] { 'a' },
80 new Byte[] { -128 },
81 new Class[] { String.class },
82 new MethodHandle[] { MethodHandles.constant(String.class, "constant") },
83 new MethodType[] { MethodType.methodType(String.class) }
84 };
85 // The string representation that should end up if the corresponding
86 // Object[] in constants is used as an argument to makeConcatWithConstants
87 String[] constantString = new String[] {
88 "bar",
89 "1",
90 "2",
91 "3",
92 "true",
93 "a",
94 "-128",
95 "class java.lang.String",
96 "MethodHandle()String",
97 "()String"
98 };
99
100
101 final int LIMIT = 200;
102
103 // Simple factory: check for dynamic arguments overflow
104 Class<?>[] underThreshold = new Class<?>[LIMIT - 1];
105 Class<?>[] threshold = new Class<?>[LIMIT];
106 Class<?>[] overThreshold = new Class<?>[LIMIT + 1];
107
108 StringBuilder sbUnderThreshold = new StringBuilder();
109 sbUnderThreshold.append(TAG_CONST);
110 for (int c = 0; c < LIMIT - 1; c++) {
111 underThreshold[c] = int.class;
112 threshold[c] = int.class;
113 overThreshold[c] = int.class;
114 sbUnderThreshold.append(TAG_ARG);
115 }
116 threshold[LIMIT - 1] = int.class;
117 overThreshold[LIMIT - 1] = int.class;
118 overThreshold[LIMIT] = int.class;
119
120 String recipeEmpty = "";
121 String recipeUnderThreshold = sbUnderThreshold.toString();
122 String recipeThreshold = sbUnderThreshold.append(TAG_ARG).toString();
123 String recipeOverThreshold = sbUnderThreshold.append(TAG_ARG).toString();
124
125 MethodType mtEmpty = MethodType.methodType(String.class);
126 MethodType mtUnderThreshold = MethodType.methodType(String.class, underThreshold);
127 MethodType mtThreshold = MethodType.methodType(String.class, threshold);
128 MethodType mtOverThreshold = MethodType.methodType(String.class, overThreshold);
129
130
131 // Check the basic functionality is working
132 {
133 CallSite cs = StringConcatFactory.makeConcat(lookup, methodName, mt);
134 test("foo42", (String) cs.getTarget().invokeExact("foo", 42));
135 }
136
137 {
138 for (int i = 0; i < constants.length; i++) {
139 CallSite cs = StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, constants[i]);
140 test("foo42".concat(constantString[i]), (String) cs.getTarget().invokeExact("foo", 42));
141 }
142 }
143
144 // Simple factory, check for nulls:
145 failNPE("Lookup is null",
146 () -> StringConcatFactory.makeConcat(null, methodName, mt));
147
148 failNPE("Method name is null",
149 () -> StringConcatFactory.makeConcat(lookup, null, mt));
150
151 failNPE("MethodType is null",
152 () -> StringConcatFactory.makeConcat(lookup, methodName, null));
153
154 // Advanced factory, check for nulls:
155 for (int i = 0; i < constants.length; i++) {
156 final Object[] consts = constants[i];
157
158 failNPE("Lookup is null",
159 () -> StringConcatFactory.makeConcatWithConstants(null, methodName, mt, recipe, consts));
160
161 failNPE("Method name is null",
162 () -> StringConcatFactory.makeConcatWithConstants(lookup, null, mt, recipe, consts));
163
164 failNPE("MethodType is null",
165 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, null, recipe, consts));
166
167 failNPE("Recipe is null",
168 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, null, consts));
169 }
170
171 failNPE("Constants vararg is null",
172 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, (Object[]) null));
173
174 failNPE("Constant argument is null",
175 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mt, recipe, new Object[] { null }));
176
177 // Simple factory, check for return type
178 fail("Return type: void",
179 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(void.class, String.class, int.class)));
180
181 fail("Return type: int",
182 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(int.class, String.class, int.class)));
183
184 fail("Return type: StringBuilder",
185 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class)));
186
187 ok("Return type: Object",
188 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class)));
189
190 ok("Return type: CharSequence",
191 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class)));
192
193 ok("Return type: Serializable",
194 () -> StringConcatFactory.makeConcat(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class)));
195
196 // Advanced factory, check for return types
197 for (int i = 0; i < constants.length; i++) {
198 final Object[] consts = constants[i];
199 fail("Return type: void",
200 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(void.class, String.class, int.class), recipe, consts));
201
202 fail("Return type: int",
203 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(int.class, String.class, int.class), recipe, consts));
204
205 fail("Return type: StringBuilder",
206 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(StringBuilder.class, String.class, int.class), recipe, consts));
207
208 ok("Return type: Object",
209 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Object.class, String.class, int.class), recipe, consts));
210
211 ok("Return type: CharSequence",
212 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(CharSequence.class, String.class, int.class), recipe, consts));
213
214 ok("Return type: Serializable",
215 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(Serializable.class, String.class, int.class), recipe, consts));
216 }
217
218 // Simple factory: check for dynamic arguments overflow
219 ok("Dynamic arguments is under limit",
220 () -> StringConcatFactory.makeConcat(lookup, methodName, mtUnderThreshold));
221
222 ok("Dynamic arguments is at the limit",
223 () -> StringConcatFactory.makeConcat(lookup, methodName, mtThreshold));
224
225 fail("Dynamic arguments is over the limit",
226 () -> StringConcatFactory.makeConcat(lookup, methodName, mtOverThreshold));
227
228 // Advanced factory: check for dynamic arguments overflow
229 ok("Dynamic arguments is under limit",
230 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtUnderThreshold, recipeUnderThreshold, constants[0]));
231
232 ok("Dynamic arguments is at the limit",
233 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants[0]));
234
235 fail("Dynamic arguments is over the limit",
236 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtOverThreshold, recipeOverThreshold, constants[0]));
237
238 // Advanced factory: check for mismatched recipe and Constants
239 ok("Static arguments and recipe match",
240 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar"));
241
242 fail("Static arguments and recipe mismatch",
243 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, "bar", "baz"));
244
245 // Advanced factory: check for mismatched recipe and dynamic arguments
246 fail("Dynamic arguments and recipe mismatch",
247 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeUnderThreshold, constants[0]));
248
249 ok("Dynamic arguments and recipe match",
250 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeThreshold, constants[0]));
251
252 fail("Dynamic arguments and recipe mismatch",
253 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtThreshold, recipeOverThreshold, constants[0]));
254
255 // Test passing array as constant
256 {
257 Object[] arg = {"boo", "bar"};
258
259 CallSite cs1 = StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST + TAG_CONST, arg);
260 test("42boobar", (String) cs1.getTarget().invokeExact(42));
261 }
262
263 // Test passing null constant
264 ok("Can pass regular constants",
265 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, "foo"));
266
267 failNPE("Cannot pass null constants",
268 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, MethodType.methodType(String.class, int.class), "" + TAG_ARG + TAG_CONST, new Object[]{null}));
269
270 // Simple factory: test empty arguments
271 ok("Ok to pass empty arguments",
272 () -> StringConcatFactory.makeConcat(lookup, methodName, mtEmpty));
273
274 // Advanced factory: test empty arguments
275 ok("Ok to pass empty arguments",
276 () -> StringConcatFactory.makeConcatWithConstants(lookup, methodName, mtEmpty, recipeEmpty));
277
278 // Simple factory: public Lookup is rejected
279 fail("Passing public Lookup",
280 () -> StringConcatFactory.makeConcat(MethodHandles.publicLookup(), methodName, mtEmpty));
281
282 // Advanced factory: public Lookup is rejected
283 fail("Passing public Lookup",
284 () -> StringConcatFactory.makeConcatWithConstants(MethodHandles.publicLookup(), methodName, mtEmpty, recipeEmpty));
285 }
286
287 public static void ok(String msg, Callable runnable) {
288 try {
|