author | mcimadamore |
Fri, 16 Dec 2016 15:27:47 +0000 | |
changeset 42828 | cce89649f958 |
parent 39920 | 4923274643f2 |
permissions | -rw-r--r-- |
35424 | 1 |
/* |
2 |
* Copyright (c) 2015, 2016, 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. Oracle designates this |
|
8 |
* particular file as subject to the "Classpath" exception as provided |
|
9 |
* by Oracle in the LICENSE file that accompanied this code. |
|
10 |
* |
|
11 |
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 |
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 |
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 |
* version 2 for more details (a copy is included in the LICENSE file that |
|
15 |
* accompanied this code). |
|
16 |
* |
|
17 |
* You should have received a copy of the GNU General Public License version |
|
18 |
* 2 along with this work; if not, write to the Free Software Foundation, |
|
19 |
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 |
* |
|
21 |
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 |
* or visit www.oracle.com if you need additional information or have any |
|
23 |
* questions. |
|
24 |
*/ |
|
25 |
||
26 |
package com.sun.tools.javac.jvm; |
|
27 |
||
28 |
import com.sun.tools.javac.code.*; |
|
29 |
import com.sun.tools.javac.comp.Resolve; |
|
30 |
import com.sun.tools.javac.tree.JCTree; |
|
31 |
import com.sun.tools.javac.tree.TreeInfo; |
|
32 |
import com.sun.tools.javac.tree.TreeMaker; |
|
33 |
import com.sun.tools.javac.util.*; |
|
34 |
||
35 |
import static com.sun.tools.javac.code.Kinds.Kind.MTH; |
|
36495
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
36 |
import static com.sun.tools.javac.code.TypeTag.*; |
35424 | 37 |
import static com.sun.tools.javac.jvm.ByteCodes.*; |
38 |
import static com.sun.tools.javac.tree.JCTree.Tag.PLUS; |
|
39 |
import com.sun.tools.javac.jvm.Items.*; |
|
40 |
||
41 |
import java.util.HashMap; |
|
42 |
import java.util.Map; |
|
43 |
||
44 |
/** This lowers the String concatenation to something that JVM can understand. |
|
45 |
* |
|
46 |
* <p><b>This is NOT part of any supported API. |
|
47 |
* If you write code that depends on this, you do so at your own risk. |
|
48 |
* This code and its internal interfaces are subject to change or |
|
49 |
* deletion without notice.</b> |
|
50 |
*/ |
|
51 |
public abstract class StringConcat { |
|
52 |
||
53 |
/** |
|
54 |
* Maximum number of slots for String Concat call. |
|
55 |
* JDK's StringConcatFactory does not support more than that. |
|
56 |
*/ |
|
57 |
private static final int MAX_INDY_CONCAT_ARG_SLOTS = 200; |
|
58 |
private static final char TAG_ARG = '\u0001'; |
|
59 |
private static final char TAG_CONST = '\u0002'; |
|
60 |
||
61 |
protected final Gen gen; |
|
62 |
protected final Symtab syms; |
|
63 |
protected final Names names; |
|
64 |
protected final TreeMaker make; |
|
65 |
protected final Types types; |
|
66 |
protected final Map<Type, Symbol> sbAppends; |
|
67 |
protected final Resolve rs; |
|
68 |
||
69 |
protected static final Context.Key<StringConcat> concatKey = new Context.Key<>(); |
|
70 |
||
71 |
public static StringConcat instance(Context context) { |
|
72 |
StringConcat instance = context.get(concatKey); |
|
73 |
if (instance == null) { |
|
74 |
instance = makeConcat(context); |
|
75 |
} |
|
76 |
return instance; |
|
77 |
} |
|
78 |
||
79 |
private static StringConcat makeConcat(Context context) { |
|
80 |
Target target = Target.instance(context); |
|
81 |
String opt = Options.instance(context).get("stringConcat"); |
|
82 |
if (target.hasStringConcatFactory()) { |
|
83 |
if (opt == null) { |
|
84 |
opt = "indyWithConstants"; |
|
85 |
} |
|
86 |
} else { |
|
87 |
if (opt != null && !"inline".equals(opt)) { |
|
88 |
Assert.error("StringConcatFactory-based string concat is requested on a platform that does not support it."); |
|
89 |
} |
|
90 |
opt = "inline"; |
|
91 |
} |
|
92 |
||
93 |
switch (opt) { |
|
94 |
case "inline": |
|
95 |
return new Inline(context); |
|
96 |
case "indy": |
|
97 |
return new IndyPlain(context); |
|
98 |
case "indyWithConstants": |
|
99 |
return new IndyConstants(context); |
|
100 |
default: |
|
101 |
Assert.error("Unknown stringConcat: " + opt); |
|
102 |
throw new IllegalStateException("Unknown stringConcat: " + opt); |
|
103 |
} |
|
104 |
} |
|
105 |
||
106 |
protected StringConcat(Context context) { |
|
107 |
context.put(concatKey, this); |
|
108 |
gen = Gen.instance(context); |
|
109 |
syms = Symtab.instance(context); |
|
110 |
types = Types.instance(context); |
|
111 |
names = Names.instance(context); |
|
112 |
make = TreeMaker.instance(context); |
|
113 |
rs = Resolve.instance(context); |
|
114 |
sbAppends = new HashMap<>(); |
|
115 |
} |
|
116 |
||
117 |
public abstract Item makeConcat(JCTree.JCAssignOp tree); |
|
118 |
public abstract Item makeConcat(JCTree.JCBinary tree); |
|
119 |
||
120 |
protected List<JCTree> collectAll(JCTree tree) { |
|
121 |
return collect(tree, List.nil()); |
|
122 |
} |
|
123 |
||
124 |
protected List<JCTree> collectAll(JCTree.JCExpression lhs, JCTree.JCExpression rhs) { |
|
125 |
return List.<JCTree>nil() |
|
126 |
.appendList(collectAll(lhs)) |
|
127 |
.appendList(collectAll(rhs)); |
|
128 |
} |
|
129 |
||
130 |
private List<JCTree> collect(JCTree tree, List<JCTree> res) { |
|
131 |
tree = TreeInfo.skipParens(tree); |
|
132 |
if (tree.hasTag(PLUS) && tree.type.constValue() == null) { |
|
133 |
JCTree.JCBinary op = (JCTree.JCBinary) tree; |
|
39920
4923274643f2
8161708: javac, consider a different way to handle access code for operators
vromero
parents:
36495
diff
changeset
|
134 |
if (op.operator.kind == MTH && op.operator.opcode == string_add) { |
35424 | 135 |
return res |
136 |
.appendList(collect(op.lhs, res)) |
|
137 |
.appendList(collect(op.rhs, res)); |
|
138 |
} |
|
139 |
} |
|
140 |
return res.append(tree); |
|
141 |
} |
|
142 |
||
143 |
/** |
|
36495
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
144 |
* If the type is not accessible from current context, try to figure out the |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
145 |
* sharpest accessible supertype. |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
146 |
* |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
147 |
* @param originalType type to sharpen |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
148 |
* @return sharped type |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
149 |
*/ |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
150 |
Type sharpestAccessible(Type originalType) { |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
151 |
if (originalType.hasTag(ARRAY)) { |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
152 |
return types.makeArrayType(sharpestAccessible(types.elemtype(originalType))); |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
153 |
} |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
154 |
|
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
155 |
Type type = originalType; |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
156 |
while (!rs.isAccessible(gen.getAttrEnv(), type.asElement())) { |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
157 |
type = types.supertype(type); |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
158 |
} |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
159 |
return type; |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
160 |
} |
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
161 |
|
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
162 |
/** |
35424 | 163 |
* "Legacy" bytecode flavor: emit the StringBuilder.append chains for string |
164 |
* concatenation. |
|
165 |
*/ |
|
166 |
private static class Inline extends StringConcat { |
|
167 |
public Inline(Context context) { |
|
168 |
super(context); |
|
169 |
} |
|
170 |
||
171 |
@Override |
|
172 |
public Item makeConcat(JCTree.JCAssignOp tree) { |
|
173 |
// Generate code to make a string builder |
|
174 |
JCDiagnostic.DiagnosticPosition pos = tree.pos(); |
|
175 |
||
176 |
// Create a string builder. |
|
177 |
newStringBuilder(tree); |
|
178 |
||
179 |
// Generate code for first string, possibly save one |
|
180 |
// copy under builder |
|
181 |
Item l = gen.genExpr(tree.lhs, tree.lhs.type); |
|
182 |
if (l.width() > 0) { |
|
183 |
gen.getCode().emitop0(dup_x1 + 3 * (l.width() - 1)); |
|
184 |
} |
|
185 |
||
186 |
// Load first string and append to builder. |
|
187 |
l.load(); |
|
188 |
appendString(tree.lhs); |
|
189 |
||
190 |
// Append all other strings to builder. |
|
191 |
List<JCTree> args = collectAll(tree.rhs); |
|
192 |
for (JCTree t : args) { |
|
193 |
gen.genExpr(t, t.type).load(); |
|
194 |
appendString(t); |
|
195 |
} |
|
196 |
||
197 |
// Convert builder to string. |
|
198 |
builderToString(pos); |
|
199 |
||
200 |
return l; |
|
201 |
} |
|
202 |
||
203 |
@Override |
|
204 |
public Item makeConcat(JCTree.JCBinary tree) { |
|
205 |
JCDiagnostic.DiagnosticPosition pos = tree.pos(); |
|
206 |
||
207 |
// Create a string builder. |
|
208 |
newStringBuilder(tree); |
|
209 |
||
210 |
// Append all strings to builder. |
|
211 |
List<JCTree> args = collectAll(tree); |
|
212 |
for (JCTree t : args) { |
|
213 |
gen.genExpr(t, t.type).load(); |
|
214 |
appendString(t); |
|
215 |
} |
|
216 |
||
217 |
// Convert builder to string. |
|
218 |
builderToString(pos); |
|
219 |
||
220 |
return gen.getItems().makeStackItem(syms.stringType); |
|
221 |
} |
|
222 |
||
223 |
private JCDiagnostic.DiagnosticPosition newStringBuilder(JCTree tree) { |
|
224 |
JCDiagnostic.DiagnosticPosition pos = tree.pos(); |
|
225 |
gen.getCode().emitop2(new_, gen.makeRef(pos, syms.stringBuilderType)); |
|
226 |
gen.getCode().emitop0(dup); |
|
42828
cce89649f958
8171371: Remove redundant type-arguments from generic method calls
mcimadamore
parents:
39920
diff
changeset
|
227 |
gen.callMethod(pos, syms.stringBuilderType, names.init, List.nil(), false); |
35424 | 228 |
return pos; |
229 |
} |
|
230 |
||
231 |
private void appendString(JCTree tree) { |
|
232 |
Type t = tree.type.baseType(); |
|
233 |
if (!t.isPrimitive() && t.tsym != syms.stringType.tsym) { |
|
234 |
t = syms.objectType; |
|
235 |
} |
|
236 |
||
237 |
Assert.checkNull(t.constValue()); |
|
238 |
Symbol method = sbAppends.get(t); |
|
239 |
if (method == null) { |
|
240 |
method = rs.resolveInternalMethod(tree.pos(), gen.getAttrEnv(), syms.stringBuilderType, names.append, List.of(t), null); |
|
241 |
sbAppends.put(t, method); |
|
242 |
} |
|
243 |
||
244 |
gen.getItems().makeMemberItem(method, false).invoke(); |
|
245 |
} |
|
246 |
||
247 |
private void builderToString(JCDiagnostic.DiagnosticPosition pos) { |
|
42828
cce89649f958
8171371: Remove redundant type-arguments from generic method calls
mcimadamore
parents:
39920
diff
changeset
|
248 |
gen.callMethod(pos, syms.stringBuilderType, names.toString, List.nil(), false); |
35424 | 249 |
} |
250 |
} |
|
251 |
||
252 |
/** |
|
253 |
* Base class for indified concatenation bytecode flavors. |
|
254 |
*/ |
|
255 |
private static abstract class Indy extends StringConcat { |
|
256 |
public Indy(Context context) { |
|
257 |
super(context); |
|
258 |
} |
|
259 |
||
260 |
@Override |
|
261 |
public Item makeConcat(JCTree.JCAssignOp tree) { |
|
262 |
List<JCTree> args = collectAll(tree.lhs, tree.rhs); |
|
263 |
Item l = gen.genExpr(tree.lhs, tree.lhs.type); |
|
264 |
emit(args, tree.type, tree.pos()); |
|
265 |
return l; |
|
266 |
} |
|
267 |
||
268 |
@Override |
|
269 |
public Item makeConcat(JCTree.JCBinary tree) { |
|
270 |
List<JCTree> args = collectAll(tree.lhs, tree.rhs); |
|
271 |
emit(args, tree.type, tree.pos()); |
|
272 |
return gen.getItems().makeStackItem(syms.stringType); |
|
273 |
} |
|
274 |
||
275 |
protected abstract void emit(List<JCTree> args, Type type, JCDiagnostic.DiagnosticPosition pos); |
|
276 |
||
277 |
/** Peel the argument list into smaller chunks. */ |
|
278 |
protected List<List<JCTree>> split(List<JCTree> args) { |
|
279 |
ListBuffer<List<JCTree>> splits = new ListBuffer<>(); |
|
280 |
||
281 |
int slots = 0; |
|
282 |
||
283 |
// Need to peel, so that neither call has more than acceptable number |
|
284 |
// of slots for the arguments. |
|
285 |
ListBuffer<JCTree> cArgs = new ListBuffer<>(); |
|
286 |
for (JCTree t : args) { |
|
287 |
int needSlots = (t.type.getTag() == LONG || t.type.getTag() == DOUBLE) ? 2 : 1; |
|
288 |
if (slots + needSlots >= MAX_INDY_CONCAT_ARG_SLOTS) { |
|
289 |
splits.add(cArgs.toList()); |
|
290 |
cArgs.clear(); |
|
291 |
slots = 0; |
|
292 |
} |
|
293 |
cArgs.add(t); |
|
294 |
slots += needSlots; |
|
295 |
} |
|
296 |
||
297 |
// Flush the tail slice |
|
298 |
if (!cArgs.isEmpty()) { |
|
299 |
splits.add(cArgs.toList()); |
|
300 |
} |
|
301 |
||
302 |
return splits.toList(); |
|
303 |
} |
|
304 |
} |
|
305 |
||
306 |
/** |
|
307 |
* Emits the invokedynamic call to JDK java.lang.invoke.StringConcatFactory, |
|
308 |
* without handling constants specially. |
|
309 |
* |
|
310 |
* We bypass empty strings, because they have no meaning at this level. This |
|
311 |
* captures the Java language trick to force String concat with e.g. ("" + int)-like |
|
312 |
* expression. Down here, we already know we are in String concat business, and do |
|
313 |
* not require these markers. |
|
314 |
*/ |
|
315 |
private static class IndyPlain extends Indy { |
|
316 |
public IndyPlain(Context context) { |
|
317 |
super(context); |
|
318 |
} |
|
319 |
||
320 |
/** Emit the indy concat for all these arguments, possibly peeling along the way */ |
|
321 |
protected void emit(List<JCTree> args, Type type, JCDiagnostic.DiagnosticPosition pos) { |
|
322 |
List<List<JCTree>> split = split(args); |
|
323 |
||
324 |
for (List<JCTree> t : split) { |
|
325 |
Assert.check(!t.isEmpty(), "Arguments list is empty"); |
|
326 |
||
327 |
ListBuffer<Type> dynamicArgs = new ListBuffer<>(); |
|
328 |
for (JCTree arg : t) { |
|
329 |
Object constVal = arg.type.constValue(); |
|
330 |
if ("".equals(constVal)) continue; |
|
331 |
if (arg.type == syms.botType) { |
|
332 |
dynamicArgs.add(types.boxedClass(syms.voidType).type); |
|
333 |
} else { |
|
36495
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
334 |
dynamicArgs.add(sharpestAccessible(arg.type)); |
35424 | 335 |
} |
336 |
gen.genExpr(arg, arg.type).load(); |
|
337 |
} |
|
338 |
||
339 |
doCall(type, pos, dynamicArgs.toList()); |
|
340 |
} |
|
341 |
||
342 |
// More that one peel slice produced: concatenate the results |
|
343 |
if (split.size() > 1) { |
|
344 |
ListBuffer<Type> argTypes = new ListBuffer<>(); |
|
345 |
for (int c = 0; c < split.size(); c++) { |
|
346 |
argTypes.append(syms.stringType); |
|
347 |
} |
|
348 |
doCall(type, pos, argTypes.toList()); |
|
349 |
} |
|
350 |
} |
|
351 |
||
352 |
/** Produce the actual invokedynamic call to StringConcatFactory */ |
|
353 |
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, List<Type> dynamicArgTypes) { |
|
354 |
Type.MethodType indyType = new Type.MethodType(dynamicArgTypes, |
|
355 |
type, |
|
42828
cce89649f958
8171371: Remove redundant type-arguments from generic method calls
mcimadamore
parents:
39920
diff
changeset
|
356 |
List.nil(), |
35424 | 357 |
syms.methodClass); |
358 |
||
359 |
int prevPos = make.pos; |
|
360 |
try { |
|
361 |
make.at(pos); |
|
362 |
||
363 |
List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, |
|
364 |
syms.stringType, |
|
365 |
syms.methodTypeType); |
|
366 |
||
367 |
Symbol bsm = rs.resolveInternalMethod(pos, |
|
368 |
gen.getAttrEnv(), |
|
369 |
syms.stringConcatFactory, |
|
370 |
names.makeConcat, |
|
371 |
bsm_staticArgs, |
|
372 |
null); |
|
373 |
||
374 |
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcat, |
|
375 |
syms.noSymbol, |
|
376 |
ClassFile.REF_invokeStatic, |
|
377 |
(Symbol.MethodSymbol)bsm, |
|
378 |
indyType, |
|
379 |
List.nil().toArray()); |
|
380 |
||
381 |
Items.Item item = gen.getItems().makeDynamicItem(dynSym); |
|
382 |
item.invoke(); |
|
383 |
} finally { |
|
384 |
make.at(prevPos); |
|
385 |
} |
|
386 |
} |
|
387 |
} |
|
388 |
||
389 |
/** |
|
390 |
* Emits the invokedynamic call to JDK java.lang.invoke.StringConcatFactory. |
|
391 |
* This code concatenates all known constants into the recipe, possibly escaping |
|
392 |
* some constants separately. |
|
393 |
* |
|
394 |
* We also bypass empty strings, because they have no meaning at this level. This |
|
395 |
* captures the Java language trick to force String concat with e.g. ("" + int)-like |
|
396 |
* expression. Down here, we already know we are in String concat business, and do |
|
397 |
* not require these markers. |
|
398 |
*/ |
|
399 |
private static final class IndyConstants extends Indy { |
|
400 |
public IndyConstants(Context context) { |
|
401 |
super(context); |
|
402 |
} |
|
403 |
||
404 |
@Override |
|
405 |
protected void emit(List<JCTree> args, Type type, JCDiagnostic.DiagnosticPosition pos) { |
|
406 |
List<List<JCTree>> split = split(args); |
|
407 |
||
408 |
for (List<JCTree> t : split) { |
|
409 |
Assert.check(!t.isEmpty(), "Arguments list is empty"); |
|
410 |
||
411 |
StringBuilder recipe = new StringBuilder(t.size()); |
|
412 |
ListBuffer<Type> dynamicArgs = new ListBuffer<>(); |
|
413 |
ListBuffer<Object> staticArgs = new ListBuffer<>(); |
|
414 |
||
415 |
for (JCTree arg : t) { |
|
416 |
Object constVal = arg.type.constValue(); |
|
417 |
if ("".equals(constVal)) continue; |
|
418 |
if (arg.type == syms.botType) { |
|
419 |
// Concat the null into the recipe right away |
|
420 |
recipe.append((String) null); |
|
421 |
} else if (constVal != null) { |
|
422 |
// Concat the String representation of the constant, except |
|
423 |
// for the case it contains special tags, which requires us |
|
424 |
// to expose it as detached constant. |
|
425 |
String a = arg.type.stringValue(); |
|
426 |
if (a.indexOf(TAG_CONST) != -1 || a.indexOf(TAG_ARG) != -1) { |
|
427 |
recipe.append(TAG_CONST); |
|
428 |
staticArgs.add(a); |
|
429 |
} else { |
|
430 |
recipe.append(a); |
|
431 |
} |
|
432 |
} else { |
|
433 |
// Ordinary arguments come through the dynamic arguments. |
|
434 |
recipe.append(TAG_ARG); |
|
36495
dd9141ca331a
8151223: String concatenation fails with implicit toString() on package-private class
shade
parents:
35424
diff
changeset
|
435 |
dynamicArgs.add(sharpestAccessible(arg.type)); |
35424 | 436 |
gen.genExpr(arg, arg.type).load(); |
437 |
} |
|
438 |
} |
|
439 |
||
440 |
doCall(type, pos, recipe.toString(), staticArgs.toList(), dynamicArgs.toList()); |
|
441 |
} |
|
442 |
||
443 |
// More that one peel slice produced: concatenate the results |
|
444 |
// All arguments are assumed to be non-constant Strings. |
|
445 |
if (split.size() > 1) { |
|
446 |
ListBuffer<Type> argTypes = new ListBuffer<>(); |
|
447 |
StringBuilder recipe = new StringBuilder(); |
|
448 |
for (int c = 0; c < split.size(); c++) { |
|
449 |
argTypes.append(syms.stringType); |
|
450 |
recipe.append(TAG_ARG); |
|
451 |
} |
|
452 |
doCall(type, pos, recipe.toString(), List.nil(), argTypes.toList()); |
|
453 |
} |
|
454 |
} |
|
455 |
||
456 |
/** Produce the actual invokedynamic call to StringConcatFactory */ |
|
457 |
private void doCall(Type type, JCDiagnostic.DiagnosticPosition pos, String recipe, List<Object> staticArgs, List<Type> dynamicArgTypes) { |
|
458 |
Type.MethodType indyType = new Type.MethodType(dynamicArgTypes, |
|
459 |
type, |
|
42828
cce89649f958
8171371: Remove redundant type-arguments from generic method calls
mcimadamore
parents:
39920
diff
changeset
|
460 |
List.nil(), |
35424 | 461 |
syms.methodClass); |
462 |
||
463 |
int prevPos = make.pos; |
|
464 |
try { |
|
465 |
make.at(pos); |
|
466 |
||
467 |
ListBuffer<Type> constTypes = new ListBuffer<>(); |
|
468 |
ListBuffer<Object> constants = new ListBuffer<>(); |
|
469 |
for (Object t : staticArgs) { |
|
470 |
constants.add(t); |
|
471 |
constTypes.add(syms.stringType); |
|
472 |
} |
|
473 |
||
474 |
List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType, |
|
475 |
syms.stringType, |
|
476 |
syms.methodTypeType) |
|
477 |
.append(syms.stringType) |
|
478 |
.appendList(constTypes); |
|
479 |
||
480 |
Symbol bsm = rs.resolveInternalMethod(pos, |
|
481 |
gen.getAttrEnv(), |
|
482 |
syms.stringConcatFactory, |
|
483 |
names.makeConcatWithConstants, |
|
484 |
bsm_staticArgs, |
|
485 |
null); |
|
486 |
||
487 |
Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(names.makeConcatWithConstants, |
|
488 |
syms.noSymbol, |
|
489 |
ClassFile.REF_invokeStatic, |
|
490 |
(Symbol.MethodSymbol)bsm, |
|
491 |
indyType, |
|
492 |
List.<Object>of(recipe).appendList(constants).toArray()); |
|
493 |
||
494 |
Items.Item item = gen.getItems().makeDynamicItem(dynSym); |
|
495 |
item.invoke(); |
|
496 |
} finally { |
|
497 |
make.at(prevPos); |
|
498 |
} |
|
499 |
} |
|
500 |
} |
|
501 |
||
502 |
} |