Mercurial > hg > truffle
comparison truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 21951:9c8c0937da41
Moving all sources into truffle subdirectory
author | Jaroslav Tulach <jaroslav.tulach@oracle.com> |
---|---|
date | Wed, 17 Jun 2015 10:58:08 +0200 |
parents | graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java@90fd69243227 |
children | 844d6d053d1b |
comparison
equal
deleted
inserted
replaced
21950:2a5011c7e641 | 21951:9c8c0937da41 |
---|---|
1 /* | |
2 * Copyright (c) 2014, 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 package com.oracle.truffle.dsl.processor.generator; | |
24 | |
25 import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; | |
26 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; | |
27 import static javax.lang.model.element.Modifier.*; | |
28 | |
29 import java.util.*; | |
30 | |
31 import javax.lang.model.element.*; | |
32 import javax.lang.model.type.*; | |
33 import javax.lang.model.util.*; | |
34 | |
35 import com.oracle.truffle.api.*; | |
36 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; | |
37 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; | |
38 import com.oracle.truffle.api.dsl.*; | |
39 import com.oracle.truffle.api.dsl.internal.*; | |
40 import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization; | |
41 import com.oracle.truffle.api.dsl.internal.DSLOptions.TypeBoxingOptimization; | |
42 import com.oracle.truffle.api.frame.*; | |
43 import com.oracle.truffle.api.nodes.*; | |
44 import com.oracle.truffle.api.nodes.Node.Child; | |
45 import com.oracle.truffle.api.nodes.Node.Children; | |
46 import com.oracle.truffle.dsl.processor.*; | |
47 import com.oracle.truffle.dsl.processor.expression.*; | |
48 import com.oracle.truffle.dsl.processor.expression.DSLExpression.Variable; | |
49 import com.oracle.truffle.dsl.processor.java.*; | |
50 import com.oracle.truffle.dsl.processor.java.model.*; | |
51 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror; | |
52 import com.oracle.truffle.dsl.processor.model.*; | |
53 import com.oracle.truffle.dsl.processor.parser.*; | |
54 import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard; | |
55 | |
56 public class NodeGenFactory { | |
57 | |
58 private static final String FRAME_VALUE = TemplateMethod.FRAME_NAME; | |
59 private static final String NAME_SUFFIX = "_"; | |
60 private static final String NODE_SUFFIX = "NodeGen"; | |
61 | |
62 private final ProcessorContext context; | |
63 private final NodeData node; | |
64 private final TypeSystemData typeSystem; | |
65 private final TypeMirror genericType; | |
66 private final DSLOptions options; | |
67 private final boolean singleSpecializable; | |
68 private final int varArgsThreshold; | |
69 private final Set<TypeMirror> expectedTypes = new HashSet<>(); | |
70 private final Set<NodeExecutionData> usedExecuteChildMethods = new HashSet<>(); | |
71 private boolean nextUsed; | |
72 private boolean singleSpecializableUnsupportedUsed; | |
73 | |
74 private List<ExecutableTypeData> usedTypes; | |
75 private List<SpecializationData> reachableSpecializations; | |
76 | |
77 public NodeGenFactory(ProcessorContext context, NodeData node) { | |
78 this.context = context; | |
79 this.node = node; | |
80 this.typeSystem = node.getTypeSystem(); | |
81 this.genericType = context.getType(Object.class); | |
82 this.options = typeSystem.getOptions(); | |
83 this.varArgsThreshold = calculateVarArgsThreshold(); | |
84 this.reachableSpecializations = calculateReachableSpecializations(); | |
85 this.singleSpecializable = isSingleSpecializableImpl(); | |
86 this.usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), reachableSpecializations); | |
87 } | |
88 | |
89 private int calculateVarArgsThreshold() { | |
90 TypeMirror specialization = context.getType(SpecializationNode.class); | |
91 TypeElement specializationType = fromTypeMirror(specialization); | |
92 | |
93 int maxParameters = 0; | |
94 for (ExecutableElement element : ElementFilter.methodsIn(specializationType.getEnclosedElements())) { | |
95 if (element.getSimpleName().contentEquals("acceptAndExecute")) { | |
96 maxParameters = Math.max(maxParameters, element.getParameters().size()); | |
97 } | |
98 } | |
99 return maxParameters; | |
100 } | |
101 | |
102 public static String nodeTypeName(NodeData node) { | |
103 return resolveNodeId(node) + NODE_SUFFIX; | |
104 } | |
105 | |
106 private static String assumptionName(AssumptionExpression assumption) { | |
107 return assumption.getId() + NAME_SUFFIX; | |
108 } | |
109 | |
110 private static String resolveNodeId(NodeData node) { | |
111 String nodeid = node.getNodeId(); | |
112 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
113 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
114 } | |
115 return nodeid; | |
116 } | |
117 | |
118 public static TypeMirror nodeType(NodeData node) { | |
119 return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), nodeTypeName(node)); | |
120 } | |
121 | |
122 private static String specializationTypeName(SpecializationData specialization) { | |
123 String id; | |
124 if (specialization == null) { | |
125 id = "Base"; | |
126 } else { | |
127 id = specialization.getId(); | |
128 } | |
129 return id + "Node_"; | |
130 } | |
131 | |
132 private TypeMirror specializationType(SpecializationData specialization) { | |
133 return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()) + "." + nodeTypeName(node), specializationTypeName(specialization)); | |
134 } | |
135 | |
136 private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) { | |
137 return execution.getName() + "Type" + NAME_SUFFIX; | |
138 } | |
139 | |
140 private static String nodeFieldName(NodeExecutionData execution) { | |
141 return execution.getName() + NAME_SUFFIX; | |
142 } | |
143 | |
144 private static String specializationStartFieldName() { | |
145 return "specialization" + NAME_SUFFIX; | |
146 } | |
147 | |
148 private static String excludedFieldName(SpecializationData specialization) { | |
149 return "exclude" + specialization.getId() + NAME_SUFFIX; | |
150 } | |
151 | |
152 private static String executeChildMethodName(NodeExecutionData execution, TypeMirror type) { | |
153 return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (ElementUtils.isObject(type) ? "" : getTypeId(type)) + NAME_SUFFIX; | |
154 } | |
155 | |
156 private CodeTree accessParent(String name) { | |
157 if (singleSpecializable) { | |
158 if (name == null) { | |
159 return CodeTreeBuilder.singleString("this"); | |
160 } else { | |
161 return CodeTreeBuilder.singleString(name); | |
162 } | |
163 } else { | |
164 if (name == null) { | |
165 return CodeTreeBuilder.singleString("root"); | |
166 } else { | |
167 return CodeTreeBuilder.createBuilder().string("root.").string(name).build(); | |
168 } | |
169 } | |
170 } | |
171 | |
172 public CodeTypeElement create() { | |
173 CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(FINAL), nodeTypeName(node), node.getTemplateType().asType()); | |
174 ElementUtils.setVisibility(clazz.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); | |
175 | |
176 for (NodeChildData child : node.getChildren()) { | |
177 clazz.addOptional(createAccessChildMethod(child)); | |
178 } | |
179 | |
180 for (NodeFieldData field : node.getFields()) { | |
181 if (!field.isGenerated()) { | |
182 continue; | |
183 } | |
184 | |
185 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), field.getType(), field.getName())); | |
186 if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { | |
187 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), field.getGetter()); | |
188 method.getModifiers().remove(Modifier.ABSTRACT); | |
189 method.createBuilder().startReturn().string("this.").string(field.getName()).end(); | |
190 clazz.add(method); | |
191 } | |
192 } | |
193 | |
194 for (ExecutableElement superConstructor : GeneratorUtils.findUserConstructors(node.getTemplateType().asType())) { | |
195 clazz.add(createNodeConstructor(clazz, superConstructor)); | |
196 } | |
197 | |
198 for (NodeExecutionData execution : node.getChildExecutions()) { | |
199 if (execution.getChild() != null) { | |
200 clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class)); | |
201 } | |
202 } | |
203 | |
204 for (NodeExecutionData execution : node.getChildExecutions()) { | |
205 if (!resolvePolymorphicExecutables(execution).isEmpty()) { | |
206 clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class)); | |
207 } | |
208 } | |
209 | |
210 for (SpecializationData specialization : node.getSpecializations()) { | |
211 if (mayBeExcluded(specialization)) { | |
212 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); | |
213 } | |
214 } | |
215 | |
216 clazz.add(createGetCostMethod()); | |
217 | |
218 avoidFindbugsProblems(clazz); | |
219 | |
220 if (singleSpecializable) { | |
221 SpecializationData specialization = reachableSpecializations.iterator().next(); | |
222 | |
223 for (ExecutableTypeData execType : usedTypes) { | |
224 if (execType.getMethod() == null) { | |
225 boolean foundDelegate = false; | |
226 for (ExecutableTypeData type : usedTypes) { | |
227 if (type == execType) { | |
228 continue; | |
229 } | |
230 if (findFastPathDelegate(specialization.getReturnType().getType(), type, usedTypes) == execType) { | |
231 foundDelegate = true; | |
232 break; | |
233 } | |
234 } | |
235 // just exclude synthetic execute methods that were not delegated to | |
236 if (!foundDelegate) { | |
237 continue; | |
238 } | |
239 } | |
240 | |
241 clazz.add(createExecutableTypeOverride(usedTypes, execType)); | |
242 } | |
243 | |
244 if (singleSpecializableUnsupportedUsed) { | |
245 addUnsupportedMethod(clazz); | |
246 } | |
247 } else { | |
248 | |
249 for (ExecutableTypeData execType : usedTypes) { | |
250 if (execType.getMethod() == null) { | |
251 continue; | |
252 } | |
253 clazz.add(createExecutableTypeOverride(usedTypes, execType)); | |
254 } | |
255 | |
256 clazz.getImplements().add(getType(SpecializedNode.class)); | |
257 clazz.add(createMethodGetSpecializationNode()); | |
258 clazz.add(createDeepCopyMethod()); | |
259 SpecializationData specializationStart = createSpecializations(clazz); | |
260 clazz.add(createNodeField(PRIVATE, specializationType(null), specializationStartFieldName(), Child.class)); | |
261 | |
262 for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { | |
263 CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder(); | |
264 builder.startStatement(); | |
265 builder.string("this.").string(specializationStartFieldName()); | |
266 builder.string(" = ").tree(createCallCreateMethod(specializationStart, "this", null)); | |
267 builder.end(); | |
268 } | |
269 } | |
270 | |
271 for (TypeMirror type : ElementUtils.uniqueSortedTypes(expectedTypes, false)) { | |
272 if (!typeSystem.hasType(type)) { | |
273 clazz.addOptional(TypeSystemCodeGenerator.createExpectMethod(PRIVATE, typeSystem, context.getType(Object.class), type)); | |
274 } | |
275 } | |
276 | |
277 return clazz; | |
278 } | |
279 | |
280 private void avoidFindbugsProblems(CodeTypeElement clazz) { | |
281 TypeElement type = context.getEnvironment().getElementUtils().getTypeElement("edu.umd.cs.findbugs.annotations.SuppressFBWarnings"); | |
282 if (type == null) { | |
283 return; | |
284 } | |
285 boolean foundComparison = false; | |
286 outer: for (SpecializationData specialization : node.getSpecializations()) { | |
287 for (GuardExpression guard : specialization.getGuards()) { | |
288 if (guard.getExpression().containsComparisons()) { | |
289 foundComparison = true; | |
290 break outer; | |
291 } | |
292 } | |
293 } | |
294 | |
295 if (foundComparison) { | |
296 CodeAnnotationMirror annotation = new CodeAnnotationMirror((DeclaredType) type.asType()); | |
297 annotation.setElementValue(annotation.findExecutableElement("value"), new CodeAnnotationValue("SA_LOCAL_SELF_COMPARISON")); | |
298 clazz.addAnnotationMirror(annotation); | |
299 } | |
300 } | |
301 | |
302 private void addUnsupportedMethod(CodeTypeElement clazz) { | |
303 CodeVariableElement seenUnsupportedField = new CodeVariableElement(modifiers(PRIVATE), getType(boolean.class), "seenUnsupported0"); | |
304 seenUnsupportedField.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class))); | |
305 clazz.add(seenUnsupportedField); | |
306 LocalContext locals = LocalContext.load(this); | |
307 CodeExecutableElement method = locals.createMethod(modifiers(PRIVATE), getType(UnsupportedSpecializationException.class), "unsupported", varArgsThreshold); | |
308 CodeTreeBuilder builder = method.createBuilder(); | |
309 builder.startIf().string("!").string(seenUnsupportedField.getName()).end().startBlock(); | |
310 builder.startStatement().startStaticCall(getType(CompilerDirectives.class), "transferToInterpreterAndInvalidate").end().end(); | |
311 builder.startStatement().string(seenUnsupportedField.getName()).string(" = true").end(); | |
312 builder.end(); | |
313 | |
314 builder.startReturn(); | |
315 builder.startNew(getType(UnsupportedSpecializationException.class)); | |
316 builder.string("this"); | |
317 builder.tree(createGetSuppliedChildren()); | |
318 locals.addReferencesTo(builder); | |
319 builder.end(); | |
320 builder.end(); | |
321 clazz.add(method); | |
322 } | |
323 | |
324 private CodeExecutableElement createNodeConstructor(CodeTypeElement clazz, ExecutableElement superConstructor) { | |
325 CodeExecutableElement constructor = GeneratorUtils.createConstructorUsingFields(modifiers(), clazz, superConstructor); | |
326 ElementUtils.setVisibility(constructor.getModifiers(), ElementUtils.getVisibility(superConstructor.getModifiers())); | |
327 | |
328 List<CodeVariableElement> childParameters = new ArrayList<>(); | |
329 for (NodeChildData child : node.getChildren()) { | |
330 childParameters.add(new CodeVariableElement(child.getOriginalType(), child.getName())); | |
331 } | |
332 constructor.getParameters().addAll(superConstructor.getParameters().size(), childParameters); | |
333 | |
334 CodeTreeBuilder builder = constructor.appendBuilder(); | |
335 List<String> childValues = new ArrayList<>(node.getChildren().size()); | |
336 for (NodeChildData child : node.getChildren()) { | |
337 String name = child.getName(); | |
338 if (child.getCardinality().isMany()) { | |
339 CreateCastData createCast = node.findCast(child.getName()); | |
340 if (createCast != null) { | |
341 CodeTree nameTree = CodeTreeBuilder.singleString(name); | |
342 CodeTreeBuilder callBuilder = builder.create(); | |
343 callBuilder.string(name).string(" != null ? "); | |
344 callBuilder.tree(callMethod(null, createCast.getMethod(), nameTree)); | |
345 callBuilder.string(" : null"); | |
346 name += "_"; | |
347 builder.declaration(child.getNodeType(), name, callBuilder.build()); | |
348 } | |
349 } | |
350 childValues.add(name); | |
351 } | |
352 | |
353 for (NodeExecutionData execution : node.getChildExecutions()) { | |
354 if (execution.getChild() == null) { | |
355 continue; | |
356 } | |
357 CreateCastData createCast = node.findCast(execution.getChild().getName()); | |
358 | |
359 builder.startStatement(); | |
360 builder.string("this.").string(nodeFieldName(execution)).string(" = "); | |
361 | |
362 String name = childValues.get(node.getChildren().indexOf(execution.getChild())); | |
363 CodeTreeBuilder accessorBuilder = builder.create(); | |
364 accessorBuilder.string(name); | |
365 | |
366 if (execution.isIndexed()) { | |
367 accessorBuilder.string("[").string(String.valueOf(execution.getChildIndex())).string("]"); | |
368 } | |
369 | |
370 CodeTree accessor = accessorBuilder.build(); | |
371 | |
372 if (createCast != null && execution.getChild().getCardinality().isOne()) { | |
373 accessor = callMethod(null, createCast.getMethod(), accessor); | |
374 } | |
375 | |
376 if (execution.isIndexed()) { | |
377 CodeTreeBuilder nullCheck = builder.create(); | |
378 nullCheck.string(name).string(" != null && ").string(String.valueOf(execution.getChildIndex())).string(" < ").string(name).string(".length").string(" ? "); | |
379 nullCheck.tree(accessor); | |
380 nullCheck.string(" : null"); | |
381 accessor = nullCheck.build(); | |
382 } | |
383 | |
384 builder.tree(accessor); | |
385 | |
386 builder.end(); | |
387 } | |
388 | |
389 return constructor; | |
390 } | |
391 | |
392 private static boolean mayBeExcluded(SpecializationData specialization) { | |
393 return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); | |
394 } | |
395 | |
396 private SpecializationData createSpecializations(CodeTypeElement clazz) { | |
397 CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization()); | |
398 TypeMirror baseSpecializationType = baseSpecialization.asType(); | |
399 | |
400 Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>(); | |
401 | |
402 List<SpecializationData> generateSpecializations = new ArrayList<>(); | |
403 generateSpecializations.add(node.getUninitializedSpecialization()); | |
404 if (needsPolymorphic()) { | |
405 generateSpecializations.add(node.getPolymorphicSpecialization()); | |
406 } | |
407 generateSpecializations.addAll(reachableSpecializations); | |
408 | |
409 for (SpecializationData specialization : generateSpecializations) { | |
410 generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType))); | |
411 } | |
412 | |
413 baseSpecialization.addOptional(createCreateNext(generated)); | |
414 baseSpecialization.addOptional(createCreateFallback(generated)); | |
415 baseSpecialization.addOptional(createCreatePolymorphic(generated)); | |
416 baseSpecialization.addOptional(createGetNext(baseSpecialization)); | |
417 | |
418 for (NodeExecutionData execution : node.getChildExecutions()) { | |
419 Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution); | |
420 specializedTypes.add(genericType); | |
421 for (TypeMirror specializedType : specializedTypes) { | |
422 if (isExecuteChildShared(execution, specializedType)) { | |
423 baseSpecialization.addOptional(createExecuteChildMethod(execution, specializedType)); | |
424 } | |
425 } | |
426 } | |
427 | |
428 return node.getUninitializedSpecialization(); | |
429 } | |
430 | |
431 private boolean needsPolymorphic() { | |
432 int signatureSize = node.getSignatureSize(); | |
433 boolean allEvaluated = true; | |
434 for (ExecutableTypeData type : usedTypes) { | |
435 if (type.getEvaluatedCount() != signatureSize) { | |
436 allEvaluated = false; | |
437 } | |
438 } | |
439 if (allEvaluated) { | |
440 return false; | |
441 } | |
442 | |
443 if (reachableSpecializations.size() != 1) { | |
444 return true; | |
445 } | |
446 | |
447 SpecializationData specialization = reachableSpecializations.get(0); | |
448 for (Parameter parameter : specialization.getSignatureParameters()) { | |
449 TypeMirror type = parameter.getType(); | |
450 if (type != null && typeSystem.hasImplicitSourceTypes(type)) { | |
451 return true; | |
452 } | |
453 } | |
454 if (specialization.hasMultipleInstances()) { | |
455 return true; | |
456 } | |
457 return false; | |
458 | |
459 } | |
460 | |
461 // create specialization | |
462 | |
463 private CodeTypeElement createBaseSpecialization() { | |
464 CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), typeSystem.getContext().getType(SpecializationNode.class)); | |
465 | |
466 clazz.addOptional(createSpecializationConstructor(clazz, null, null)); | |
467 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); | |
468 | |
469 clazz.addOptional(createUnsupported()); | |
470 clazz.add(createGetSuppliedChildrenMethod()); | |
471 clazz.add(createAcceptAndExecute()); | |
472 | |
473 for (ExecutableTypeData type : usedTypes) { | |
474 clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); | |
475 } | |
476 | |
477 return clazz; | |
478 } | |
479 | |
480 private Element createAcceptAndExecute() { | |
481 ExecutableTypeData executableElement = createSpecializationNodeSignature(node.getSignatureSize()); | |
482 LocalContext currentLocals = LocalContext.load(this, executableElement, varArgsThreshold); | |
483 CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false, varArgsThreshold); | |
484 | |
485 executable.getModifiers().add(FINAL); | |
486 CodeTreeBuilder builder = executable.createBuilder(); | |
487 | |
488 CodeTree receiver = CodeTreeBuilder.singleString("this"); | |
489 | |
490 builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null))); | |
491 | |
492 return executable; | |
493 } | |
494 | |
495 private ExecutableTypeData createSpecializationNodeSignature(int argumentCount) { | |
496 TypeMirror[] parameters = new TypeMirror[argumentCount]; | |
497 Arrays.fill(parameters, genericType); | |
498 return new ExecutableTypeData(node, genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters)); | |
499 } | |
500 | |
501 private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) { | |
502 // always implement the root execute method. they are declared abstract in the base node. | |
503 if (executableType.getDelegatedTo() == null) { | |
504 return true; | |
505 } | |
506 | |
507 // specializations with more parameters are just ignored | |
508 if (executableType.getEvaluatedCount() > node.getExecutionCount()) { | |
509 return false; | |
510 } | |
511 | |
512 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) { | |
513 return false; | |
514 } | |
515 | |
516 // the evaluated signature might be compatible to the specialization | |
517 boolean specializationCompatible = true; | |
518 List<TypeMirror> signatureParameters = executableType.getSignatureParameters(); | |
519 for (int i = 0; i < signatureParameters.size(); i++) { | |
520 TypeMirror evaluatedType = signatureParameters.get(i); | |
521 TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType(); | |
522 | |
523 if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) { | |
524 specializationCompatible = false; | |
525 break; | |
526 } | |
527 } | |
528 if (!specializationCompatible) { | |
529 return false; | |
530 } | |
531 | |
532 // possibly trigger void optimization for a specialization if it is enabled | |
533 if (isVoid(executableType.getReturnType())) { | |
534 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specialization.getReturnType().getType())) { | |
535 return true; | |
536 } | |
537 } | |
538 | |
539 // trigger type boxing elimination for unevaluated arguments | |
540 for (int i = executableType.getEvaluatedCount(); i < node.getExecutionCount(); i++) { | |
541 NodeExecutionData execution = node.getChildExecutions().get(i); | |
542 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); | |
543 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) { | |
544 // it does not make sense to do type boxing elimination for children with | |
545 // no type specialized execute method | |
546 if (execution.getChild() != null) { | |
547 ExecutableTypeData executedType = execution.getChild().findExecutableType(specializedType); | |
548 if (executedType != null) { | |
549 return true; | |
550 } | |
551 } | |
552 } | |
553 } | |
554 | |
555 // trigger type boxing elimination for return types | |
556 if (typeEquals(executableType.getReturnType(), specialization.getReturnType().getType())) { | |
557 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), executableType.getReturnType())) { | |
558 return true; | |
559 } | |
560 } | |
561 | |
562 // trigger generation for evaluated assignable type matches other than generic | |
563 for (int i = 0; i < signatureParameters.size(); i++) { | |
564 TypeMirror evaluatedType = signatureParameters.get(i); | |
565 NodeExecutionData execution = node.getChildExecutions().get(i); | |
566 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); | |
567 | |
568 if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) { | |
569 return true; | |
570 } | |
571 } | |
572 | |
573 return false; | |
574 } | |
575 | |
576 private List<ExecutableTypeData> filterBaseExecutableTypes(List<ExecutableTypeData> executableTypes, List<SpecializationData> specializations) { | |
577 Set<TypeMirror> returnTypes = new HashSet<>(); | |
578 for (SpecializationData specialization : node.getSpecializations()) { | |
579 returnTypes.add(specialization.getReturnType().getType()); | |
580 } | |
581 | |
582 List<ExecutableTypeData> prefilteredTypes = new ArrayList<>(); | |
583 for (ExecutableTypeData type : executableTypes) { | |
584 if (type.getDelegatedTo() == null || shouldAlwaysImplementExecutableType(type)) { | |
585 prefilteredTypes.add(type); | |
586 } else { | |
587 boolean foundSubtype = false; | |
588 for (TypeMirror returnType : returnTypes) { | |
589 if (isSubtypeBoxed(context, returnType, type.getReturnType())) { | |
590 foundSubtype = true; | |
591 } | |
592 } | |
593 if (foundSubtype) { | |
594 prefilteredTypes.add(type); | |
595 } | |
596 } | |
597 } | |
598 | |
599 Set<ExecutableTypeData> types = new HashSet<>(); | |
600 type: for (ExecutableTypeData type : prefilteredTypes) { | |
601 for (SpecializationData specialization : specializations) { | |
602 if (shouldImplementExecutableType(specialization, type) || shouldAlwaysImplementExecutableType(type)) { | |
603 types.add(type); | |
604 continue type; | |
605 } | |
606 } | |
607 } | |
608 Set<ExecutableTypeData> delegatesToAdd = new HashSet<>(); | |
609 do { | |
610 delegatesToAdd.clear(); | |
611 for (ExecutableTypeData type : types) { | |
612 ExecutableTypeData delegate = type.getDelegatedTo(); | |
613 if (delegate != null && !types.contains(delegate)) { | |
614 delegatesToAdd.add(delegate); | |
615 } | |
616 } | |
617 types.addAll(delegatesToAdd); | |
618 } while (!delegatesToAdd.isEmpty()); | |
619 List<ExecutableTypeData> newUsedTypes = new ArrayList<>(types); | |
620 Collections.sort(newUsedTypes); | |
621 return newUsedTypes; | |
622 } | |
623 | |
624 private boolean shouldAlwaysImplementExecutableType(ExecutableTypeData type) { | |
625 return type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null); | |
626 } | |
627 | |
628 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { | |
629 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); | |
630 | |
631 CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null)); | |
632 | |
633 for (Parameter p : specialization.getSignatureParameters()) { | |
634 TypeMirror targetType = p.getType(); | |
635 if (typeSystem.hasImplicitSourceTypes(targetType)) { | |
636 NodeExecutionData execution = p.getSpecification().getExecution(); | |
637 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType()); | |
638 if (implicitProfile != null) { | |
639 implicitProfile.getModifiers().add(PRIVATE); | |
640 implicitProfile.getModifiers().add(FINAL); | |
641 clazz.add(implicitProfile); | |
642 } | |
643 } | |
644 } | |
645 | |
646 if (specialization.isFallback()) { | |
647 clazz.add(createFallbackGuardMethod()); | |
648 } | |
649 | |
650 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); | |
651 clazz.addOptional(createMergeMethod(specialization)); | |
652 clazz.addOptional(createIsSameMethod(specialization)); | |
653 clazz.addOptional(createIsIdenticalMethod(specialization)); | |
654 | |
655 // get types that should get implemented | |
656 List<ExecutableTypeData> types = new ArrayList<>(); | |
657 for (ExecutableTypeData type : node.getExecutableTypes()) { | |
658 if (shouldImplementExecutableType(specialization, type)) { | |
659 types.add(type); | |
660 } | |
661 } | |
662 for (ExecutableTypeData type : types) { | |
663 clazz.add(createFastPathExecuteMethod(specialization, type, types)); | |
664 } | |
665 | |
666 return clazz; | |
667 } | |
668 | |
669 public static List<Parameter> getDynamicParameters(TemplateMethod method) { | |
670 List<Parameter> parameters = new ArrayList<>(); | |
671 for (Parameter param : method.getReturnTypeAndParameters()) { | |
672 if (param.getSpecification().isLocal()) { | |
673 // ignore parameters passed by locals | |
674 continue; | |
675 } else if (param.getVariableElement() != null && param.getVariableElement().getAnnotation(Cached.class) != null) { | |
676 // ignore cached parameters | |
677 continue; | |
678 } | |
679 parameters.add(param); | |
680 } | |
681 return parameters; | |
682 } | |
683 | |
684 private Element createDeepCopyMethod() { | |
685 if (singleSpecializable) { | |
686 return null; | |
687 } | |
688 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), getType(Node.class), "deepCopy"); | |
689 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
690 CodeTreeBuilder builder = executable.createBuilder(); | |
691 builder.startReturn().startStaticCall(getType(SpecializationNode.class), "updateRoot").string("super.deepCopy()").end().end(); | |
692 return executable; | |
693 } | |
694 | |
695 private Element createGetCostMethod() { | |
696 TypeMirror returnType = getType(NodeCost.class); | |
697 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost"); | |
698 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
699 CodeTreeBuilder builder = executable.createBuilder(); | |
700 if (singleSpecializable) { | |
701 builder.startReturn().staticReference(getType(NodeCost.class), "MONOMORPHIC").end().end(); | |
702 } else { | |
703 builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end(); | |
704 } | |
705 return executable; | |
706 | |
707 } | |
708 | |
709 private Element createIsIdenticalMethod(SpecializationData specialization) { | |
710 boolean cacheBoundGuard = specialization.hasMultipleInstances(); | |
711 if (!cacheBoundGuard) { | |
712 return null; | |
713 } | |
714 | |
715 LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold); | |
716 currentLocals.loadFastPathState(specialization); | |
717 | |
718 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical"); | |
719 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); | |
720 currentLocals.addParametersTo(method, varArgsThreshold, FRAME_VALUE); | |
721 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
722 final CodeTreeBuilder builder = method.createBuilder(); | |
723 | |
724 SpecializationGroup group = SpecializationGroup.create(specialization); | |
725 SpecializationBody executionFactory = new SpecializationBody(true, false) { | |
726 @Override | |
727 public CodeTree createBody(SpecializationData s, LocalContext values) { | |
728 return builder.create().returnTrue().build(); | |
729 } | |
730 }; | |
731 | |
732 builder.tree(createGuardAndCast(group, genericType, currentLocals, executionFactory)); | |
733 builder.returnFalse(); | |
734 return method; | |
735 } | |
736 | |
737 private CodeExecutableElement createIsSameMethod(SpecializationData specialization) { | |
738 if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) { | |
739 return null; | |
740 } | |
741 | |
742 List<CodeVariableElement> profiles = new ArrayList<>(); | |
743 for (Parameter parameter : specialization.getSignatureParameters()) { | |
744 NodeExecutionData execution = parameter.getSpecification().getExecution(); | |
745 if (execution == null) { | |
746 continue; | |
747 } | |
748 CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getType()); | |
749 if (var != null) { | |
750 profiles.add(var); | |
751 } | |
752 } | |
753 | |
754 if (profiles.isEmpty()) { | |
755 return null; | |
756 } | |
757 | |
758 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isSame"); | |
759 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); | |
760 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
761 CodeTreeBuilder builder = method.createBuilder(); | |
762 | |
763 builder.startReturn(); | |
764 builder.string("super.isSame(other)"); | |
765 | |
766 for (CodeVariableElement profile : profiles) { | |
767 builder.string(" && "); | |
768 builder.string("this.").string(profile.getName()).string(" == ").string("(").cast(specializationType(specialization)).string("other).").string(profile.getName()); | |
769 } | |
770 | |
771 builder.end(); | |
772 return method; | |
773 } | |
774 | |
775 private Element createMergeMethod(SpecializationData specialization) { | |
776 if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { | |
777 return null; | |
778 } | |
779 TypeMirror specializationNodeType = getType(SpecializationNode.class); | |
780 LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold); | |
781 | |
782 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); | |
783 executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); | |
784 currentLocals.addParametersTo(executable, varArgsThreshold, FRAME_VALUE); | |
785 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
786 CodeTreeBuilder builder = executable.createBuilder(); | |
787 | |
788 if (specialization.isPolymorphic()) { | |
789 builder.startReturn(); | |
790 builder.startCall("polymorphicMerge"); | |
791 builder.string("newNode"); | |
792 builder.startCall("super", "merge"); | |
793 builder.string("newNode"); | |
794 currentLocals.addReferencesTo(builder, FRAME_VALUE); | |
795 builder.end(); | |
796 builder.end(); | |
797 builder.end(); | |
798 | |
799 } else { | |
800 boolean elseIf = false; | |
801 for (SpecializationData containedSpecialization : specialization.getExcludedBy()) { | |
802 elseIf = builder.startIf(elseIf); | |
803 builder.string("newNode.getClass() == ").typeLiteral(specializationType(containedSpecialization)); | |
804 builder.end(); | |
805 builder.startBlock(); | |
806 builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")"); | |
807 builder.end(); | |
808 } | |
809 builder.startReturn(); | |
810 builder.startCall("super", "merge"); | |
811 builder.string("newNode"); | |
812 currentLocals.addReferencesTo(builder, FRAME_VALUE); | |
813 builder.end(); | |
814 builder.end(); | |
815 } | |
816 | |
817 return executable; | |
818 } | |
819 | |
820 private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) { | |
821 SpecializationData fallback = node.getGenericSpecialization(); | |
822 if (fallback == null) { | |
823 return null; | |
824 } | |
825 CodeTypeElement generatedType = generatedSpecializationClasses.get(fallback); | |
826 if (generatedType == null) { | |
827 return null; | |
828 } | |
829 | |
830 TypeMirror returnType = getType(SpecializationNode.class); | |
831 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createFallback"); | |
832 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
833 method.createBuilder().startReturn().tree(createCallCreateMethod(fallback, null, null)).end(); | |
834 return method; | |
835 } | |
836 | |
837 private Element createCreatePolymorphic(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) { | |
838 SpecializationData polymorphic = node.getPolymorphicSpecialization(); | |
839 CodeTypeElement generatedPolymorphic = generatedSpecializationClasses.get(polymorphic); | |
840 if (generatedPolymorphic == null) { | |
841 return null; | |
842 } | |
843 TypeMirror returnType = getType(SpecializationNode.class); | |
844 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createPolymorphic"); | |
845 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
846 method.createBuilder().startReturn().tree(createCallCreateMethod(polymorphic, null, null)).end(); | |
847 return method; | |
848 } | |
849 | |
850 private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) { | |
851 final LocalContext locals = LocalContext.load(this); | |
852 | |
853 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", varArgsThreshold, FRAME_VALUE); | |
854 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
855 | |
856 CodeTreeBuilder builder = method.createBuilder(); | |
857 SpecializationGroup group = createSpecializationGroups(); | |
858 CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) { | |
859 @Override | |
860 public CodeTree createBody(SpecializationData specialization, LocalContext values) { | |
861 CodeTypeElement generatedType = specializationClasses.get(specialization); | |
862 if (generatedType == null) { | |
863 throw new AssertionError("No generated type for " + specialization); | |
864 } | |
865 return createSlowPathExecute(specialization, values); | |
866 } | |
867 }); | |
868 | |
869 builder.tree(execution); | |
870 | |
871 if (hasFallthrough(group, genericType, locals, false, null)) { | |
872 builder.returnNull(); | |
873 } | |
874 return method; | |
875 } | |
876 | |
877 private CodeExecutableElement createFallbackGuardMethod() { | |
878 boolean frameUsed = node.isFrameUsedByAnyGuard(); | |
879 LocalContext locals = LocalContext.load(this); | |
880 | |
881 if (!frameUsed) { | |
882 locals.removeValue(FRAME_VALUE); | |
883 } | |
884 | |
885 CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", varArgsThreshold, FRAME_VALUE); | |
886 if (!frameUsed) { | |
887 boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class))); | |
888 } | |
889 | |
890 CodeTreeBuilder builder = boundaryMethod.createBuilder(); | |
891 builder.startReturn(); | |
892 builder.startCall("createNext"); | |
893 locals.addReferencesTo(builder, FRAME_VALUE); | |
894 builder.end(); | |
895 builder.string(" == null"); | |
896 builder.end(); | |
897 return boundaryMethod; | |
898 } | |
899 | |
900 private ExecutableElement createAccessChildMethod(NodeChildData child) { | |
901 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { | |
902 ExecutableElement getter = (ExecutableElement) child.getAccessElement(); | |
903 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), getter); | |
904 method.getModifiers().remove(Modifier.ABSTRACT); | |
905 | |
906 List<NodeExecutionData> executions = new ArrayList<>(); | |
907 for (NodeExecutionData execution : node.getChildExecutions()) { | |
908 if (execution.getChild() == child) { | |
909 executions.add(execution); | |
910 } | |
911 } | |
912 | |
913 CodeTreeBuilder builder = method.createBuilder(); | |
914 if (child.getCardinality().isMany()) { | |
915 builder.startReturn().startNewArray((ArrayType) child.getOriginalType(), null); | |
916 for (NodeExecutionData execution : executions) { | |
917 builder.string(nodeFieldName(execution)); | |
918 } | |
919 builder.end().end(); | |
920 } else { | |
921 for (NodeExecutionData execution : executions) { | |
922 builder.startReturn().string("this.").string(nodeFieldName(execution)).end(); | |
923 break; | |
924 } | |
925 } | |
926 return method; | |
927 } | |
928 return null; | |
929 } | |
930 | |
931 private Element createUnsupported() { | |
932 SpecializationData fallback = node.getGenericSpecialization(); | |
933 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { | |
934 return null; | |
935 } | |
936 LocalContext locals = LocalContext.load(this); | |
937 | |
938 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", varArgsThreshold, FRAME_VALUE); | |
939 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
940 | |
941 CodeTreeBuilder builder = method.createBuilder(); | |
942 builder.startReturn(); | |
943 builder.tree(callTemplateMethod(accessParent(null), fallback, locals)); | |
944 builder.end(); | |
945 | |
946 return method; | |
947 } | |
948 | |
949 private boolean isSingleSpecializableImpl() { | |
950 if (reachableSpecializations.size() != 1) { | |
951 return false; | |
952 } | |
953 | |
954 SpecializationData specialization = reachableSpecializations.get(0); | |
955 | |
956 for (Parameter parameter : specialization.getSignatureParameters()) { | |
957 TypeMirror type = parameter.getType(); | |
958 if (type != null && typeSystem.hasImplicitSourceTypes(type)) { | |
959 return false; | |
960 } | |
961 } | |
962 | |
963 if (!specialization.getAssumptionExpressions().isEmpty()) { | |
964 return false; | |
965 } | |
966 | |
967 if (specialization.getCaches().size() > 0) { | |
968 // TODO chumer: caches do not yet support single specialization. | |
969 // it could be worthwhile to explore if this is possible | |
970 return false; | |
971 } | |
972 return true; | |
973 } | |
974 | |
975 private List<SpecializationData> calculateReachableSpecializations() { | |
976 List<SpecializationData> specializations = new ArrayList<>(); | |
977 for (SpecializationData specialization : node.getSpecializations()) { | |
978 if (specialization.isReachable() && // | |
979 (specialization.isSpecialized() // | |
980 || (specialization.isFallback() && optimizeFallback(specialization)))) { | |
981 specializations.add(specialization); | |
982 } | |
983 } | |
984 return specializations; | |
985 } | |
986 | |
987 private boolean optimizeFallback(SpecializationData specialization) { | |
988 switch (options.optimizeFallback()) { | |
989 case NEVER: | |
990 return false; | |
991 case DECLARED: | |
992 return specialization.getMethod() != null; | |
993 case ALWAYS: | |
994 return true; | |
995 default: | |
996 throw new AssertionError(); | |
997 } | |
998 } | |
999 | |
1000 private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) { | |
1001 LocalContext locals = LocalContext.load(this, execType, Integer.MAX_VALUE); | |
1002 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true, Integer.MAX_VALUE); | |
1003 | |
1004 CodeTreeBuilder builder = method.createBuilder(); | |
1005 if (singleSpecializable) { | |
1006 SpecializationData specialization = reachableSpecializations.iterator().next(); | |
1007 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals)); | |
1008 } else { | |
1009 // create acceptAndExecute | |
1010 ExecutableTypeData delegate = execType; | |
1011 CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName()); | |
1012 builder.tree(createCallDelegateExecute(builder, receiver, locals, execType, delegate)); | |
1013 } | |
1014 return method; | |
1015 } | |
1016 | |
1017 private Element createMethodGetSpecializationNode() { | |
1018 TypeMirror returntype = getType(SpecializationNode.class); | |
1019 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode"); | |
1020 method.createBuilder().startReturn().string(specializationStartFieldName()).end(); | |
1021 return method; | |
1022 } | |
1023 | |
1024 private TypeMirror getType(Class<?> clazz) { | |
1025 return context.getType(clazz); | |
1026 } | |
1027 | |
1028 private CodeVariableElement createNodeField(Modifier visibility, TypeMirror type, String name, Class<?> annotationType) { | |
1029 CodeVariableElement childField = new CodeVariableElement(modifiers(), type, name); | |
1030 childField.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(annotationType))); | |
1031 setVisibility(childField.getModifiers(), visibility); | |
1032 return childField; | |
1033 } | |
1034 | |
1035 private static List<ExecutableTypeData> resolveSpecializedExecutables(NodeExecutionData execution, Collection<TypeMirror> types, TypeBoxingOptimization optimization) { | |
1036 if (optimization == TypeBoxingOptimization.NONE) { | |
1037 return Collections.emptyList(); | |
1038 } else if (types.isEmpty()) { | |
1039 return Collections.emptyList(); | |
1040 } | |
1041 | |
1042 List<ExecutableTypeData> executables = new ArrayList<>(); | |
1043 for (TypeMirror type : types) { | |
1044 if (!isTypeBoxingOptimized(optimization, type)) { | |
1045 continue; | |
1046 } | |
1047 if (execution.getChild() == null) { | |
1048 continue; | |
1049 } | |
1050 ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size()); | |
1051 if (foundType != null) { | |
1052 executables.add(foundType); | |
1053 } | |
1054 } | |
1055 return executables; | |
1056 } | |
1057 | |
1058 private static CodeTree callMethod(CodeTree receiver, ExecutableElement method, CodeTree... boundValues) { | |
1059 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1060 if (method.getModifiers().contains(STATIC)) { | |
1061 builder.startStaticCall(method.getEnclosingElement().asType(), method.getSimpleName().toString()); | |
1062 } else { | |
1063 builder.startCall(receiver, method.getSimpleName().toString()); | |
1064 } | |
1065 int index = -1; | |
1066 for (VariableElement parameter : method.getParameters()) { | |
1067 index++; | |
1068 if (index < boundValues.length) { | |
1069 CodeTree tree = boundValues[index]; | |
1070 if (tree != null) { | |
1071 builder.tree(tree); | |
1072 continue; | |
1073 } | |
1074 } | |
1075 | |
1076 builder.defaultValue(parameter.asType()); | |
1077 } | |
1078 builder.end(); | |
1079 return builder.build(); | |
1080 } | |
1081 | |
1082 private CodeTree[] bindExecuteMethodParameters(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { | |
1083 List<NodeExecutionData> executeWith = execution != null ? execution.getChild().getExecuteWith() : null; | |
1084 | |
1085 List<CodeTree> values = new ArrayList<>(); | |
1086 if (method.getFrameParameter() != null) { | |
1087 LocalVariable frameLocal = currentValues.get(FRAME_VALUE); | |
1088 if (frameLocal == null) { | |
1089 values.add(CodeTreeBuilder.singleString("null")); | |
1090 } else { | |
1091 values.add(createTypeSafeReference(frameLocal, method.getFrameParameter())); | |
1092 } | |
1093 } | |
1094 | |
1095 int evaluatedIndex = 0; | |
1096 for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) { | |
1097 NodeExecutionData parameterExecution; | |
1098 if (executeWith != null && executionIndex < executeWith.size()) { | |
1099 parameterExecution = executeWith.get(executionIndex); | |
1100 } else { | |
1101 parameterExecution = node.getChildExecutions().get(executionIndex); | |
1102 } | |
1103 if (parameterExecution.isShortCircuit()) { | |
1104 if (evaluatedIndex < method.getEvaluatedCount()) { | |
1105 TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex); | |
1106 LocalVariable shortCircuit = currentValues.getShortCircuit(parameterExecution); | |
1107 if (shortCircuit != null) { | |
1108 values.add(createTypeSafeReference(shortCircuit, targetType)); | |
1109 } else { | |
1110 values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build()); | |
1111 } | |
1112 evaluatedIndex++; | |
1113 } | |
1114 } | |
1115 if (evaluatedIndex < method.getEvaluatedCount()) { | |
1116 TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex); | |
1117 LocalVariable value = currentValues.getValue(parameterExecution); | |
1118 if (value != null) { | |
1119 values.add(createTypeSafeReference(value, targetType)); | |
1120 } else { | |
1121 values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build()); | |
1122 } | |
1123 evaluatedIndex++; | |
1124 } | |
1125 } | |
1126 return values.toArray(new CodeTree[values.size()]); | |
1127 } | |
1128 | |
1129 private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { | |
1130 CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null; | |
1131 return callMethod(receiver, method.getMethod(), bindExecuteMethodParameters(execution, method, currentValues)); | |
1132 } | |
1133 | |
1134 private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) { | |
1135 CodeTree[] bindings = new CodeTree[method.getParameters().size()]; | |
1136 | |
1137 int signatureIndex = 0; | |
1138 for (int i = 0; i < bindings.length; i++) { | |
1139 Parameter parameter = method.getParameters().get(i); | |
1140 | |
1141 LocalVariable var = currentValues.get(parameter, signatureIndex); | |
1142 if (var == null) { | |
1143 var = currentValues.get(parameter.getLocalName()); | |
1144 } | |
1145 | |
1146 if (var != null) { | |
1147 bindings[i] = createTypeSafeReference(var, parameter.getType()); | |
1148 } | |
1149 | |
1150 if (parameter.getSpecification().isSignature()) { | |
1151 signatureIndex++; | |
1152 } | |
1153 } | |
1154 return callMethod(receiver, method.getMethod(), bindings); | |
1155 } | |
1156 | |
1157 private CodeTree createTypeSafeReference(LocalVariable var, TypeMirror targetType) { | |
1158 CodeTree valueReference = var.createReference(); | |
1159 TypeMirror sourceType = var.getTypeMirror(); | |
1160 if (targetType == null || sourceType == null) { | |
1161 return valueReference; | |
1162 } | |
1163 if (needsCastTo(sourceType, targetType)) { | |
1164 valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference); | |
1165 } | |
1166 return valueReference; | |
1167 } | |
1168 | |
1169 private SpecializationGroup createSpecializationGroups() { | |
1170 return SpecializationGroup.create(reachableSpecializations); | |
1171 } | |
1172 | |
1173 private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { | |
1174 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1175 if (specialization.isFallback()) { | |
1176 return builder.returnNull().build(); | |
1177 } | |
1178 | |
1179 if (node.isFrameUsedByAnyGuard()) { | |
1180 builder.tree(createTransferToInterpreterAndInvalidate()); | |
1181 } | |
1182 | |
1183 // caches unbound to guards are invoked after all guards | |
1184 for (CacheExpression cache : specialization.getCaches()) { | |
1185 if (!specialization.isCacheBoundByGuard(cache)) { | |
1186 initializeCache(builder, specialization, cache, currentValues); | |
1187 } | |
1188 } | |
1189 boolean hasAssumptions = !specialization.getAssumptionExpressions().isEmpty(); | |
1190 if (hasAssumptions) { | |
1191 | |
1192 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1193 CodeTree assumptions = DSLExpressionGenerator.write(assumption.getExpression(), accessParent(null), | |
1194 castBoundTypes(bindExpressionValues(assumption.getExpression(), specialization, currentValues))); | |
1195 String name = assumptionName(assumption); | |
1196 // needs specialization index for assumption to make unique | |
1197 String varName = name + specialization.getIndex(); | |
1198 TypeMirror type = assumption.getExpression().getResolvedType(); | |
1199 builder.declaration(type, varName, assumptions); | |
1200 currentValues.set(name, new LocalVariable(type, varName, null, null)); | |
1201 } | |
1202 | |
1203 builder.startIf(); | |
1204 String sep = ""; | |
1205 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1206 LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); | |
1207 if (assumptionVar == null) { | |
1208 throw new AssertionError("assumption var not resolved"); | |
1209 } | |
1210 builder.string(sep); | |
1211 builder.startCall("isValid").tree(assumptionVar.createReference()).end(); | |
1212 sep = " && "; | |
1213 } | |
1214 builder.end(); | |
1215 builder.startBlock(); | |
1216 } | |
1217 | |
1218 for (SpecializationData otherSpeciailzation : node.getSpecializations()) { | |
1219 if (otherSpeciailzation == specialization) { | |
1220 continue; | |
1221 } | |
1222 if (otherSpeciailzation.getExcludedBy().contains(specialization)) { | |
1223 builder.startStatement(); | |
1224 builder.tree(accessParent(excludedFieldName(otherSpeciailzation))); | |
1225 builder.string(" = true"); | |
1226 builder.end(); | |
1227 } | |
1228 } | |
1229 | |
1230 CodeTree create = createCallCreateMethod(specialization, null, currentValues); | |
1231 | |
1232 if (specialization.hasMultipleInstances()) { | |
1233 builder.declaration(getType(SpecializationNode.class), "s", create); | |
1234 DSLExpression limitExpression = specialization.getLimitExpression(); | |
1235 CodeTree limitExpressionTree; | |
1236 if (limitExpression == null) { | |
1237 limitExpressionTree = CodeTreeBuilder.singleString("3"); | |
1238 } else { | |
1239 limitExpressionTree = DSLExpressionGenerator.write(limitExpression, accessParent(null), // | |
1240 castBoundTypes(bindExpressionValues(limitExpression, specialization, currentValues))); | |
1241 } | |
1242 | |
1243 builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock(); | |
1244 builder.statement("return s"); | |
1245 builder.end(); | |
1246 } else { | |
1247 builder.startReturn().tree(create).end(); | |
1248 } | |
1249 | |
1250 if (hasAssumptions) { | |
1251 builder.end(); | |
1252 } | |
1253 | |
1254 if (mayBeExcluded(specialization)) { | |
1255 CodeTreeBuilder checkHasSeenBuilder = builder.create(); | |
1256 checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); | |
1257 checkHasSeenBuilder.tree(builder.build()); | |
1258 checkHasSeenBuilder.end(); | |
1259 return checkHasSeenBuilder.build(); | |
1260 } | |
1261 return builder.build(); | |
1262 } | |
1263 | |
1264 private boolean hasFallthrough(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, boolean fastPath, List<GuardExpression> ignoreGuards) { | |
1265 for (TypeGuard guard : group.getTypeGuards()) { | |
1266 if (currentValues.getValue(guard.getSignatureIndex()) == null) { | |
1267 // not evaluated | |
1268 return true; | |
1269 } | |
1270 LocalVariable value = currentValues.getValue(guard.getSignatureIndex()); | |
1271 if (needsCastTo(value.getTypeMirror(), guard.getType())) { | |
1272 return true; | |
1273 } | |
1274 } | |
1275 | |
1276 List<GuardExpression> guards = new ArrayList<>(group.getGuards()); | |
1277 List<GuardExpression> elseConnectable = group.findElseConnectableGuards(); | |
1278 guards.removeAll(elseConnectable); | |
1279 if (ignoreGuards != null) { | |
1280 guards.removeAll(ignoreGuards); | |
1281 } | |
1282 SpecializationData specialization = group.getSpecialization(); | |
1283 if (specialization != null && fastPath) { | |
1284 for (ListIterator<GuardExpression> iterator = guards.listIterator(); iterator.hasNext();) { | |
1285 GuardExpression guard = iterator.next(); | |
1286 if (!specialization.isDynamicParameterBound(guard.getExpression())) { | |
1287 iterator.remove(); | |
1288 } | |
1289 } | |
1290 } | |
1291 | |
1292 if (!guards.isEmpty()) { | |
1293 return true; | |
1294 } | |
1295 | |
1296 if (!fastPath && specialization != null && !specialization.getAssumptionExpressions().isEmpty()) { | |
1297 return true; | |
1298 } | |
1299 | |
1300 if (!fastPath && specialization != null && mayBeExcluded(specialization)) { | |
1301 return true; | |
1302 } | |
1303 | |
1304 if (!elseConnectable.isEmpty()) { | |
1305 SpecializationGroup previous = group.getPrevious(); | |
1306 if (previous != null && hasFallthrough(previous, forType, currentValues, fastPath, previous.getGuards())) { | |
1307 return true; | |
1308 } | |
1309 } | |
1310 | |
1311 List<SpecializationGroup> groupChildren = group.getChildren(); | |
1312 if (!groupChildren.isEmpty()) { | |
1313 return hasFallthrough(groupChildren.get(groupChildren.size() - 1), forType, currentValues, fastPath, ignoreGuards); | |
1314 } | |
1315 | |
1316 return false; | |
1317 } | |
1318 | |
1319 private Element createGetNext(CodeTypeElement type) { | |
1320 if (!nextUsed) { | |
1321 return null; | |
1322 } | |
1323 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), type.asType(), "getNext"); | |
1324 CodeTreeBuilder builder = method.createBuilder(); | |
1325 builder.startReturn().cast(type.asType(), CodeTreeBuilder.singleString("this.next")).end(); | |
1326 return method; | |
1327 } | |
1328 | |
1329 private Element createGetSuppliedChildrenMethod() { | |
1330 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); | |
1331 | |
1332 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), nodeArray, "getSuppliedChildren"); | |
1333 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
1334 | |
1335 CodeTreeBuilder builder = method.createBuilder(); | |
1336 builder.startReturn().tree(createGetSuppliedChildren()).end(); | |
1337 | |
1338 return method; | |
1339 } | |
1340 | |
1341 private CodeTree createGetSuppliedChildren() { | |
1342 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); | |
1343 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1344 builder.startNewArray(nodeArray, null); | |
1345 for (int i = 0; i < node.getChildExecutions().size(); i++) { | |
1346 NodeExecutionData execution = node.getChildExecutions().get(i); | |
1347 if (execution.isShortCircuit()) { | |
1348 builder.nullLiteral(); | |
1349 } | |
1350 if (execution.getChild() == null) { | |
1351 builder.nullLiteral(); | |
1352 } else { | |
1353 builder.tree(accessParent(nodeFieldName(execution))); | |
1354 } | |
1355 } | |
1356 builder.end(); | |
1357 return builder.build(); | |
1358 } | |
1359 | |
1360 // create specialization | |
1361 | |
1362 private CodeTree createCallCreateMethod(SpecializationData specialization, String rootName, LocalContext currentValues) { | |
1363 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1364 | |
1365 TypeMirror specializationType = specializationType(specialization); | |
1366 if (useLazyClassLoading()) { | |
1367 builder.startStaticCall(specializationType(specialization), "create"); | |
1368 } else { | |
1369 builder.startNew(specializationType); | |
1370 } | |
1371 if (rootName != null) { | |
1372 builder.string(rootName); | |
1373 } else { | |
1374 builder.string("root"); | |
1375 } | |
1376 if (currentValues != null) { | |
1377 for (Parameter p : specialization.getSignatureParameters()) { | |
1378 CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getType()); | |
1379 if (var != null) { | |
1380 LocalVariable variable = currentValues.get(p.getLocalName()); | |
1381 if (variable == null) { | |
1382 throw new AssertionError("Could not bind cached value " + p.getLocalName() + ": " + currentValues); | |
1383 } | |
1384 builder.tree(variable.original().createReference()); | |
1385 } | |
1386 } | |
1387 for (CacheExpression cache : specialization.getCaches()) { | |
1388 LocalVariable variable = currentValues.get(cache.getParameter().getLocalName()); | |
1389 if (variable == null) { | |
1390 throw new AssertionError("Could not bind cached value " + cache.getParameter().getLocalName() + ": " + currentValues); | |
1391 } | |
1392 builder.tree(variable.createReference()); | |
1393 } | |
1394 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1395 LocalVariable variable = currentValues.get(assumptionName(assumption)); | |
1396 if (variable == null) { | |
1397 throw new AssertionError("Could not bind assumption value " + assumption.getId() + ": " + currentValues); | |
1398 } | |
1399 builder.tree(variable.createReference()); | |
1400 } | |
1401 } | |
1402 builder.end(); | |
1403 | |
1404 return builder.build(); | |
1405 } | |
1406 | |
1407 private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) { | |
1408 if (!useLazyClassLoading()) { | |
1409 return null; | |
1410 } | |
1411 | |
1412 CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor); | |
1413 executable.setReturnType(specializationType(null)); | |
1414 executable.setSimpleName(CodeNames.of("create")); | |
1415 executable.getModifiers().add(STATIC); | |
1416 | |
1417 CodeTreeBuilder builder = executable.createBuilder(); | |
1418 builder.startReturn().startNew(specializationType(specialization)); | |
1419 for (VariableElement parameter : executable.getParameters()) { | |
1420 builder.string(parameter.getSimpleName().toString()); | |
1421 } | |
1422 builder.end().end(); | |
1423 return executable; | |
1424 } | |
1425 | |
1426 private boolean useLazyClassLoading() { | |
1427 return options.useLazyClassLoading() && !singleSpecializable; | |
1428 } | |
1429 | |
1430 private static String implicitClassFieldName(NodeExecutionData execution) { | |
1431 return execution.getName() + "ImplicitType"; | |
1432 } | |
1433 | |
1434 private static String implicitNodeFieldName(NodeExecutionData execution) { | |
1435 return execution.getName() + "Cast"; | |
1436 } | |
1437 | |
1438 private CodeExecutableElement createSpecializationConstructor(CodeTypeElement clazz, SpecializationData specialization, String constantIndex) { | |
1439 CodeExecutableElement constructor = new CodeExecutableElement(modifiers(), null, clazz.getSimpleName().toString()); | |
1440 | |
1441 constructor.addParameter(new CodeVariableElement(nodeType(node), "root")); | |
1442 CodeTreeBuilder builder = constructor.createBuilder(); | |
1443 | |
1444 if (specialization == null) { | |
1445 if (constantIndex == null) { | |
1446 builder.statement("super(index)"); | |
1447 constructor.addParameter(new CodeVariableElement(getType(int.class), "index")); | |
1448 } else { | |
1449 builder.startStatement().startSuperCall().string(constantIndex).end().end(); | |
1450 } | |
1451 builder.statement("this.root = root"); | |
1452 } else { | |
1453 int index = resolveSpecializationIndex(specialization); | |
1454 builder.startStatement().startSuperCall().string("root").string(String.valueOf(index)).end().end(); | |
1455 | |
1456 for (Parameter p : specialization.getSignatureParameters()) { | |
1457 NodeExecutionData execution = p.getSpecification().getExecution(); | |
1458 | |
1459 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getType()); | |
1460 if (implicitProfile != null) { | |
1461 LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(context); | |
1462 | |
1463 String implicitFieldName = implicitProfile.getName(); | |
1464 if (options.implicitCastOptimization().isDuplicateTail()) { | |
1465 constructor.addParameter(var.createParameter()); | |
1466 CodeTree implicitType = TypeSystemCodeGenerator.implicitType(typeSystem, p.getType(), var.createReference()); | |
1467 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end(); | |
1468 } else if (options.implicitCastOptimization().isMergeCasts()) { | |
1469 // use node that supports polymorphism | |
1470 constructor.addParameter(var.createParameter()); | |
1471 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(typeSystem, p.getType(), var.createReference())).end(); | |
1472 } else { | |
1473 throw new AssertionError(); | |
1474 } | |
1475 } | |
1476 } | |
1477 for (CacheExpression cache : specialization.getCaches()) { | |
1478 String name = cache.getParameter().getLocalName(); | |
1479 TypeMirror type = cache.getParameter().getType(); | |
1480 | |
1481 if (ElementUtils.isAssignable(type, new ArrayCodeTypeMirror(getType(Node.class)))) { | |
1482 CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); | |
1483 var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Children.class))); | |
1484 } else if (ElementUtils.isAssignable(type, getType(Node.class))) { | |
1485 CodeVariableElement var = clazz.add(new CodeVariableElement(modifiers(PRIVATE), type, name)); | |
1486 var.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(Child.class))); | |
1487 } else { | |
1488 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); | |
1489 } | |
1490 constructor.addParameter(new CodeVariableElement(type, name)); | |
1491 builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); | |
1492 } | |
1493 | |
1494 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1495 String name = assumptionName(assumption); | |
1496 TypeMirror type = assumption.getExpression().getResolvedType(); | |
1497 CodeVariableElement field = clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); | |
1498 field.addAnnotationMirror(new CodeAnnotationMirror(context.getDeclaredType(CompilationFinal.class))); | |
1499 constructor.addParameter(new CodeVariableElement(type, name)); | |
1500 builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); | |
1501 } | |
1502 } | |
1503 | |
1504 if (constructor.getParameters().isEmpty()) { | |
1505 // do not generate default constructor | |
1506 return null; | |
1507 } | |
1508 return constructor; | |
1509 } | |
1510 | |
1511 // TODO this logic can be inlined to the parser as soon as the old NodeGen layout is gone | |
1512 private static int resolveSpecializationIndex(SpecializationData specialization) { | |
1513 if (specialization.isFallback()) { | |
1514 return Integer.MAX_VALUE - 1; | |
1515 } else if (specialization.isUninitialized()) { | |
1516 return Integer.MAX_VALUE; | |
1517 } else if (specialization.isPolymorphic()) { | |
1518 return 0; | |
1519 } else { | |
1520 return specialization.getIndex(); | |
1521 } | |
1522 } | |
1523 | |
1524 private CodeTree createThrowUnsupported(LocalContext currentValues) { | |
1525 singleSpecializableUnsupportedUsed = true; | |
1526 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1527 builder.startThrow().startCall("unsupported"); | |
1528 currentValues.addReferencesTo(builder); | |
1529 builder.end().end(); | |
1530 return builder.build(); | |
1531 } | |
1532 | |
1533 private CodeTree createCallNext(CodeTreeBuilder parent, ExecutableTypeData currentType, ExecutableTypeData callType, LocalContext currentValues) { | |
1534 if (singleSpecializable) { | |
1535 return createThrowUnsupported(currentValues); | |
1536 } | |
1537 CodeTreeBuilder callBuilder = parent.create(); | |
1538 callBuilder.tree(createCallDelegateExecute(callBuilder, CodeTreeBuilder.singleString("getNext()"), currentValues, currentType, callType)); | |
1539 nextUsed = true; | |
1540 return callBuilder.build(); | |
1541 } | |
1542 | |
1543 private CodeTree createCallRemove(String reason, ExecutableTypeData forType, LocalContext currentValues) { | |
1544 if (singleSpecializable) { | |
1545 return createThrowUnsupported(currentValues); | |
1546 } | |
1547 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1548 builder.startCall("remove"); | |
1549 builder.doubleQuote(reason); | |
1550 currentValues.addReferencesTo(builder, FRAME_VALUE); | |
1551 builder.end(); | |
1552 CodeTree call = builder.build(); | |
1553 | |
1554 builder = builder.create(); | |
1555 builder.startReturn(); | |
1556 builder.tree(expectOrCast(genericType, forType, call)); | |
1557 builder.end(); | |
1558 return builder.build(); | |
1559 } | |
1560 | |
1561 private CodeTree createCallDelegate(String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) { | |
1562 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1563 builder.startCall(methodName); | |
1564 if (reason != null) { | |
1565 builder.doubleQuote(reason); | |
1566 } | |
1567 currentValues.addReferencesTo(builder, FRAME_VALUE); | |
1568 builder.end(); | |
1569 | |
1570 CodeTree expectOrCast = expectOrCast(genericType, forType, builder.build()); | |
1571 return expectOrCast; | |
1572 } | |
1573 | |
1574 private CodeTree expectOrCast(TypeMirror sourceType, ExecutableTypeData targetType, CodeTree content) { | |
1575 if (needsUnexpectedResultException(targetType)) { | |
1576 return expect(sourceType, targetType.getReturnType(), content); | |
1577 } else { | |
1578 return cast(sourceType, targetType.getReturnType(), content); | |
1579 } | |
1580 } | |
1581 | |
1582 private CodeTree cast(TypeMirror sourceType, TypeMirror targetType, CodeTree content) { | |
1583 if (ElementUtils.needsCastTo(sourceType, targetType) && !isVoid(sourceType)) { | |
1584 return TypeSystemCodeGenerator.cast(typeSystem, targetType, content); | |
1585 } else { | |
1586 return content; | |
1587 } | |
1588 } | |
1589 | |
1590 private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) { | |
1591 if (sourceType == null || ElementUtils.needsCastTo(sourceType, forType)) { | |
1592 expectedTypes.add(forType); | |
1593 return TypeSystemCodeGenerator.expect(typeSystem, forType, tree); | |
1594 } | |
1595 return tree; | |
1596 } | |
1597 | |
1598 private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) { | |
1599 if (execution.getChild() == null) { | |
1600 return Collections.emptySet(); | |
1601 } | |
1602 ExecutableTypeData executableType = resolveExecutableType(execution.getChild(), type); | |
1603 Set<ExecutableTypeData> executedTypes = new HashSet<>(); | |
1604 executedTypes.add(executableType); | |
1605 if (typeSystem.hasImplicitSourceTypes(type)) { | |
1606 executedTypes.addAll(resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(type), options.implicitTypeBoxingOptimization())); | |
1607 } | |
1608 return executedTypes; | |
1609 } | |
1610 | |
1611 private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeMirror type) { | |
1612 int executeWithCount = child.getExecuteWith().size(); | |
1613 ExecutableTypeData executableType = child.getNodeData().findExecutableType(type, executeWithCount); | |
1614 if (executableType == null) { | |
1615 executableType = child.getNodeData().findAnyGenericExecutableType(context, executeWithCount); | |
1616 } | |
1617 return executableType; | |
1618 } | |
1619 | |
1620 private boolean hasChildUnexpectedResult(NodeExecutionData execution, TypeMirror type) { | |
1621 for (ExecutableTypeData executableType : findSpecializedExecutableTypes(execution, type)) { | |
1622 if (executableType != null && (executableType.hasUnexpectedValue(context) || needsCastTo(executableType.getReturnType(), type))) { | |
1623 return true; | |
1624 } | |
1625 } | |
1626 return false; | |
1627 } | |
1628 | |
1629 private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) { | |
1630 LocalContext currentLocals = LocalContext.load(this, executedType, Integer.MAX_VALUE); | |
1631 CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false, Integer.MAX_VALUE); | |
1632 CodeTreeBuilder builder = executable.createBuilder(); | |
1633 if (specialization == null) { | |
1634 if (executedType.getDelegatedTo() == null) { | |
1635 executable.getModifiers().add(ABSTRACT); | |
1636 } | |
1637 } else { | |
1638 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
1639 } | |
1640 builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals)); | |
1641 | |
1642 return executable; | |
1643 } | |
1644 | |
1645 private static final String VARARGS_NAME = "args"; | |
1646 | |
1647 private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride, int varArgs) { | |
1648 TypeMirror returnType = executedType.getReturnType(); | |
1649 | |
1650 if (specialization != null) { | |
1651 currentLocals.loadFastPathState(specialization); | |
1652 } | |
1653 | |
1654 String methodName; | |
1655 if (originalOverride && executedType.getMethod() != null) { | |
1656 methodName = executedType.getMethod().getSimpleName().toString(); | |
1657 } else { | |
1658 methodName = executedType.getUniqueName(); | |
1659 } | |
1660 | |
1661 CodeExecutableElement executable; | |
1662 if (originalOverride && executedType.getMethod() != null) { | |
1663 executable = CodeExecutableElement.clone(context.getEnvironment(), executedType.getMethod()); | |
1664 executable.getAnnotationMirrors().clear(); | |
1665 executable.getModifiers().remove(ABSTRACT); | |
1666 for (VariableElement var : executable.getParameters()) { | |
1667 ((CodeVariableElement) var).getAnnotationMirrors().clear(); | |
1668 } | |
1669 if (executedType.getFrameParameter() != null) { | |
1670 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE); | |
1671 } | |
1672 | |
1673 if (executable.isVarArgs()) { | |
1674 ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(VARARGS_NAME); | |
1675 } | |
1676 | |
1677 renameOriginalParameters(executedType, executable, currentLocals); | |
1678 } else { | |
1679 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, varArgs, FRAME_VALUE); | |
1680 } | |
1681 executable.getThrownTypes().clear(); | |
1682 | |
1683 if (needsUnexpectedResultException(executedType)) { | |
1684 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class)); | |
1685 } | |
1686 | |
1687 return executable; | |
1688 } | |
1689 | |
1690 private void renameOriginalParameters(ExecutableTypeData executedType, CodeExecutableElement executable, LocalContext currentLocals) { | |
1691 // rename varargs parameter | |
1692 int evaluatedIndex = 0; | |
1693 for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) { | |
1694 NodeExecutionData execution = node.getChildExecutions().get(executionIndex); | |
1695 if (execution.isShortCircuit()) { | |
1696 if (evaluatedIndex < executedType.getEvaluatedCount()) { | |
1697 TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex); | |
1698 LocalVariable shortCircuit = currentLocals.getShortCircuit(execution); | |
1699 if (shortCircuit != null) { | |
1700 currentLocals.setShortCircuitValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, shortCircuit)); | |
1701 } | |
1702 evaluatedIndex++; | |
1703 } | |
1704 } | |
1705 if (evaluatedIndex < executedType.getEvaluatedCount()) { | |
1706 TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex); | |
1707 LocalVariable value = currentLocals.getValue(execution); | |
1708 if (value != null) { | |
1709 currentLocals.setValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, value)); | |
1710 } | |
1711 evaluatedIndex++; | |
1712 } | |
1713 } | |
1714 } | |
1715 | |
1716 private static LocalVariable renameExecutableTypeParameter(CodeExecutableElement method, ExecutableTypeData executedType, int evaluatedIndex, TypeMirror targetType, LocalVariable var) { | |
1717 int parameterIndex = executedType.getParameterIndex(evaluatedIndex); | |
1718 int varArgsIndex = executedType.getVarArgsIndex(parameterIndex); | |
1719 LocalVariable returnVar = var; | |
1720 if (varArgsIndex >= 0) { | |
1721 returnVar = returnVar.accessWith(CodeTreeBuilder.singleString(VARARGS_NAME + "[" + varArgsIndex + "]")); | |
1722 } else { | |
1723 ((CodeVariableElement) method.getParameters().get(parameterIndex)).setName(returnVar.getName()); | |
1724 } | |
1725 if (!isObject(targetType)) { | |
1726 returnVar = returnVar.newType(targetType); | |
1727 } | |
1728 return returnVar; | |
1729 } | |
1730 | |
1731 private boolean needsUnexpectedResultException(ExecutableTypeData executedType) { | |
1732 if (!executedType.hasUnexpectedValue(context)) { | |
1733 return false; | |
1734 } | |
1735 | |
1736 SpecializationData polymorphicSpecialization = node.getPolymorphicSpecialization(); | |
1737 if (polymorphicSpecialization != null && isSubtypeBoxed(context, polymorphicSpecialization.getReturnType().getType(), executedType.getReturnType())) { | |
1738 return false; | |
1739 } else { | |
1740 return true; | |
1741 } | |
1742 } | |
1743 | |
1744 private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, final ExecutableTypeData executableType, List<ExecutableTypeData> allTypes, LocalContext currentLocals) { | |
1745 final CodeTreeBuilder builder = parent.create(); | |
1746 TypeMirror returnType = executableType.getReturnType(); | |
1747 | |
1748 ExecutableTypeData delegate = null; | |
1749 if (specialization == null) { | |
1750 delegate = executableType.getDelegatedTo(); | |
1751 } | |
1752 | |
1753 if (delegate == null) { | |
1754 delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes); | |
1755 } | |
1756 | |
1757 int delegateSignatureCount = delegate != null ? delegate.getSignatureParameters().size() : 0; | |
1758 for (NodeExecutionData execution : node.getChildExecutions()) { | |
1759 if (specialization == null && delegate != null && execution.getIndex() >= delegateSignatureCount) { | |
1760 // we just evaluate children for the next delegate | |
1761 continue; | |
1762 } else if (specialization != null && delegate != null) { | |
1763 // skip if already delegated | |
1764 break; | |
1765 } | |
1766 | |
1767 LocalVariable var = currentLocals.getValue(execution); | |
1768 if (var == null) { | |
1769 TypeMirror targetType; | |
1770 if (specialization == null) { | |
1771 targetType = node.getGenericType(execution); | |
1772 } else { | |
1773 targetType = specialization.findParameterOrDie(execution).getType(); | |
1774 } | |
1775 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals); | |
1776 var = currentLocals.createValue(execution, targetType).nextName(); | |
1777 builder.tree(createAssignExecuteChild(builder, execution, executableType, var, shortCircuit, currentLocals)); | |
1778 currentLocals.setValue(execution, var); | |
1779 } | |
1780 } | |
1781 | |
1782 LocalContext originalValues = currentLocals.copy(); | |
1783 if (delegate != null) { | |
1784 builder.tree(createCallDelegateExecute(builder, null, currentLocals, executableType, delegate)); | |
1785 } else if (specialization == null) { | |
1786 // nothing to do. abstract anyway | |
1787 } else if (specialization.isPolymorphic()) { | |
1788 builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), currentLocals)); | |
1789 } else if (specialization.isUninitialized()) { | |
1790 builder.startReturn().tree(createCallDelegate("uninitialized", null, executableType, currentLocals)).end(); | |
1791 } else { | |
1792 SpecializationGroup group = SpecializationGroup.create(specialization); | |
1793 SpecializationBody executionFactory = new SpecializationBody(true, true) { | |
1794 @Override | |
1795 public CodeTree createBody(SpecializationData s, LocalContext values) { | |
1796 return createFastPathExecute(builder, executableType, s, values); | |
1797 } | |
1798 }; | |
1799 builder.tree(createGuardAndCast(group, returnType, currentLocals, executionFactory)); | |
1800 if (hasFallthrough(group, returnType, originalValues, true, null) || group.getSpecialization().isFallback()) { | |
1801 builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), originalValues)); | |
1802 } | |
1803 } | |
1804 return builder.build(); | |
1805 } | |
1806 | |
1807 private CodeTree createCallDelegateExecute(final CodeTreeBuilder parent, CodeTree receiver, LocalContext currentLocals, ExecutableTypeData source, ExecutableTypeData delegate) { | |
1808 CodeTreeBuilder callBuilder = parent.create(); | |
1809 | |
1810 if (singleSpecializable && delegate.getMethod() != null) { | |
1811 callBuilder.startCall(receiver, delegate.getMethod().getSimpleName().toString()); | |
1812 } else { | |
1813 callBuilder.startCall(receiver, delegate.getUniqueName()); | |
1814 } | |
1815 callBuilder.trees(bindExecuteMethodParameters(null, delegate, currentLocals)); | |
1816 callBuilder.end(); | |
1817 CodeTree call = expectOrCast(delegate.getReturnType(), source, callBuilder.build()); | |
1818 | |
1819 CodeTreeBuilder returnBuilder = parent.create(); | |
1820 if (isVoid(source.getReturnType())) { | |
1821 returnBuilder.statement(call); | |
1822 returnBuilder.returnStatement(); | |
1823 } else if (isVoid(delegate.getReturnType())) { | |
1824 returnBuilder.statement(call); | |
1825 returnBuilder.returnDefault(); | |
1826 } else { | |
1827 returnBuilder.startReturn().tree(call).end(); | |
1828 } | |
1829 | |
1830 CodeTreeBuilder builder = parent.create(); | |
1831 | |
1832 if (!needsUnexpectedResultException(source) && needsUnexpectedResultException(delegate)) { | |
1833 builder.startTryBlock(); | |
1834 builder.tree(returnBuilder.build()); | |
1835 builder.end().startCatchBlock(context.getType(UnexpectedResultException.class), "ex"); | |
1836 if (!isVoid(source.getReturnType())) { | |
1837 builder.startReturn().tree(cast(context.getType(Object.class), source.getReturnType(), CodeTreeBuilder.singleString("ex.getResult()"))).end(); | |
1838 } | |
1839 builder.end(); | |
1840 } else { | |
1841 builder.tree(returnBuilder.build()); | |
1842 } | |
1843 return builder.build(); | |
1844 } | |
1845 | |
1846 private ExecutableTypeData findFastPathDelegate(TypeMirror targetType, ExecutableTypeData executableType, List<ExecutableTypeData> allTypes) { | |
1847 if (typeEquals(executableType.getReturnType(), targetType)) { | |
1848 // type matches look for even better delegates | |
1849 for (ExecutableTypeData type : allTypes) { | |
1850 if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) { | |
1851 if (type != executableType) { | |
1852 return type; | |
1853 } | |
1854 } | |
1855 } | |
1856 return null; | |
1857 } else { | |
1858 for (ExecutableTypeData type : allTypes) { | |
1859 if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) { | |
1860 return type; | |
1861 } | |
1862 } | |
1863 int executableIndex = allTypes.indexOf(executableType); | |
1864 int compareIndex = 0; | |
1865 for (ExecutableTypeData type : allTypes) { | |
1866 if (executableIndex != compareIndex && executableType.sameParameters(type)) { | |
1867 int result = ExecutableTypeData.compareType(context, type.getReturnType(), executableType.getReturnType()); | |
1868 if (result < 0) { | |
1869 return type; | |
1870 } else if (result == 0 && executableIndex < compareIndex) { | |
1871 return type; | |
1872 } | |
1873 } | |
1874 compareIndex++; | |
1875 } | |
1876 return null; | |
1877 } | |
1878 } | |
1879 | |
1880 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { | |
1881 LocalVariable shortCircuit = null; | |
1882 if (execution.isShortCircuit()) { | |
1883 shortCircuit = currentLocals.getShortCircuit(execution); | |
1884 | |
1885 if (shortCircuit == null) { | |
1886 SpecializationData resolvedSpecialization = specialization; | |
1887 if (specialization == null) { | |
1888 resolvedSpecialization = node.getGenericSpecialization(); | |
1889 } | |
1890 ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); | |
1891 CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals); | |
1892 shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); | |
1893 } else { | |
1894 CodeTree access = shortCircuit.createReference(); | |
1895 shortCircuit = shortCircuit.nextName().accessWith(access); | |
1896 } | |
1897 } | |
1898 return shortCircuit; | |
1899 } | |
1900 | |
1901 private int calculateShortCircuitIndex(NodeExecutionData execution) { | |
1902 int shortCircuitIndex = 0; | |
1903 for (NodeExecutionData otherExectuion : node.getChildExecutions()) { | |
1904 if (otherExectuion.isShortCircuit()) { | |
1905 if (otherExectuion == execution) { | |
1906 break; | |
1907 } | |
1908 shortCircuitIndex++; | |
1909 } | |
1910 } | |
1911 return shortCircuitIndex; | |
1912 } | |
1913 | |
1914 private CodeTree createFastPathExecute(CodeTreeBuilder parent, final ExecutableTypeData forType, SpecializationData specialization, LocalContext currentValues) { | |
1915 CodeTreeBuilder builder = parent.create(); | |
1916 int ifCount = 0; | |
1917 if (specialization.isFallback()) { | |
1918 builder.startIf().startCall("guardFallback"); | |
1919 if (node.isFrameUsedByAnyGuard()) { | |
1920 if (currentValues.get(FRAME_VALUE) != null) { | |
1921 builder.string(FRAME_VALUE); | |
1922 } else { | |
1923 builder.nullLiteral(); | |
1924 } | |
1925 } | |
1926 currentValues.addReferencesTo(builder); | |
1927 | |
1928 builder.end(); | |
1929 builder.end(); | |
1930 builder.startBlock(); | |
1931 ifCount++; | |
1932 } | |
1933 CodeTreeBuilder execute = builder.create(); | |
1934 | |
1935 if (!specialization.getAssumptionExpressions().isEmpty()) { | |
1936 builder.startTryBlock(); | |
1937 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1938 LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); | |
1939 if (assumptionVar == null) { | |
1940 throw new AssertionError("Could not resolve assumption var " + currentValues); | |
1941 } | |
1942 builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end(); | |
1943 } | |
1944 builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); | |
1945 builder.startReturn(); | |
1946 List<String> assumptionIds = new ArrayList<>(); | |
1947 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1948 assumptionIds.add(assumption.getId()); | |
1949 } | |
1950 builder.tree(createCallDelegate("removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues)); | |
1951 builder.end(); | |
1952 builder.end(); | |
1953 } | |
1954 | |
1955 if (specialization.getMethod() == null) { | |
1956 execute.startReturn(); | |
1957 execute.startCall("unsupported"); | |
1958 currentValues.addReferencesTo(execute, FRAME_VALUE); | |
1959 execute.end(); | |
1960 execute.end(); | |
1961 } else { | |
1962 boolean doReturn = !isVoid(specialization.getMethod().getReturnType()); | |
1963 if (doReturn) { | |
1964 execute.startReturn(); | |
1965 } else { | |
1966 execute.startStatement(); | |
1967 } | |
1968 execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues)); | |
1969 execute.end(); | |
1970 if (!doReturn) { | |
1971 if (isVoid(forType.getReturnType())) { | |
1972 execute.returnStatement(); | |
1973 } else { | |
1974 execute.startReturn(); | |
1975 execute.defaultValue(forType.getReturnType()); | |
1976 execute.end(); | |
1977 } | |
1978 } | |
1979 } | |
1980 builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build())); | |
1981 builder.end(ifCount); | |
1982 return builder.build(); | |
1983 } | |
1984 | |
1985 private CodeTree createGuardAndCast(SpecializationGroup group, TypeMirror forType, LocalContext currentValues, SpecializationBody execution) { | |
1986 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1987 | |
1988 Set<TypeGuard> castGuards; | |
1989 if (execution.needsCastedValues()) { | |
1990 castGuards = null; // cast all | |
1991 } else { | |
1992 castGuards = new HashSet<>(); | |
1993 for (TypeGuard castGuard : group.getTypeGuards()) { | |
1994 if (isTypeGuardUsedInAnyGuardOrCacheBelow(group, currentValues, castGuard, execution.isFastPath())) { | |
1995 castGuards.add(castGuard); | |
1996 } | |
1997 } | |
1998 } | |
1999 | |
2000 SpecializationData specialization = group.getSpecialization(); | |
2001 CodeTree[] checkAndCast = createTypeCheckAndLocals(specialization, group.getTypeGuards(), castGuards, currentValues, execution); | |
2002 | |
2003 CodeTree check = checkAndCast[0]; | |
2004 CodeTree cast = checkAndCast[1]; | |
2005 | |
2006 List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards(); | |
2007 List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards()); | |
2008 guardExpressions.removeAll(elseGuardExpressions); | |
2009 CodeTree[] methodGuardAndAssertions = createMethodGuardCheck(guardExpressions, specialization, currentValues, execution.isFastPath()); | |
2010 CodeTree methodGuards = methodGuardAndAssertions[0]; | |
2011 CodeTree guardAssertions = methodGuardAndAssertions[1]; | |
2012 | |
2013 int ifCount = 0; | |
2014 if (!check.isEmpty()) { | |
2015 builder.startIf(); | |
2016 builder.tree(check).end(); | |
2017 builder.startBlock(); | |
2018 ifCount++; | |
2019 } | |
2020 if (!cast.isEmpty()) { | |
2021 builder.tree(cast); | |
2022 } | |
2023 boolean elseIf = !elseGuardExpressions.isEmpty(); | |
2024 if (!methodGuards.isEmpty()) { | |
2025 builder.startIf(elseIf); | |
2026 builder.tree(methodGuards).end(); | |
2027 builder.startBlock(); | |
2028 ifCount++; | |
2029 } else if (elseIf) { | |
2030 builder.startElseBlock(); | |
2031 ifCount++; | |
2032 } | |
2033 if (!guardAssertions.isEmpty()) { | |
2034 builder.tree(guardAssertions); | |
2035 } | |
2036 | |
2037 boolean reachable = isReachableGroup(group, ifCount); | |
2038 if (reachable) { | |
2039 for (SpecializationGroup child : group.getChildren()) { | |
2040 builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution)); | |
2041 } | |
2042 if (specialization != null) { | |
2043 builder.tree(execution.createBody(specialization, currentValues)); | |
2044 } | |
2045 } | |
2046 builder.end(ifCount); | |
2047 | |
2048 return builder.build(); | |
2049 } | |
2050 | |
2051 private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { | |
2052 if (ifCount != 0) { | |
2053 return true; | |
2054 } | |
2055 SpecializationGroup previous = group.getPreviousGroup(); | |
2056 if (previous == null || previous.findElseConnectableGuards().isEmpty()) { | |
2057 return true; | |
2058 } | |
2059 | |
2060 /* | |
2061 * Hacky else case. In this case the specialization is not reachable due to previous else | |
2062 * branch. This is only true if the minimum state is not checked. | |
2063 */ | |
2064 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && | |
2065 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { | |
2066 return false; | |
2067 } | |
2068 | |
2069 return true; | |
2070 } | |
2071 | |
2072 private boolean isTypeGuardUsedInAnyGuardOrCacheBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard, boolean fastPath) { | |
2073 String localName = currentValues.getValue(typeGuard.getSignatureIndex()).getName(); | |
2074 | |
2075 SpecializationData specialization = group.getSpecialization(); | |
2076 for (GuardExpression guard : group.getGuards()) { | |
2077 if (isVariableBoundIn(specialization, guard.getExpression(), localName, currentValues)) { | |
2078 return true; | |
2079 } | |
2080 } | |
2081 if (!fastPath && specialization != null) { | |
2082 for (CacheExpression cache : specialization.getCaches()) { | |
2083 if (isVariableBoundIn(specialization, cache.getExpression(), localName, currentValues)) { | |
2084 return true; | |
2085 } | |
2086 } | |
2087 } | |
2088 | |
2089 for (SpecializationGroup child : group.getChildren()) { | |
2090 if (isTypeGuardUsedInAnyGuardOrCacheBelow(child, currentValues, typeGuard, fastPath)) { | |
2091 return true; | |
2092 } | |
2093 } | |
2094 | |
2095 return false; | |
2096 } | |
2097 | |
2098 private static boolean isVariableBoundIn(SpecializationData specialization, DSLExpression expression, String localName, LocalContext currentValues) throws AssertionError { | |
2099 Map<Variable, LocalVariable> boundValues = bindExpressionValues(expression, specialization, currentValues); | |
2100 for (Variable var : expression.findBoundVariables()) { | |
2101 LocalVariable target = boundValues.get(var); | |
2102 if (target != null && localName.equals(target.getName())) { | |
2103 return true; | |
2104 } | |
2105 } | |
2106 return false; | |
2107 } | |
2108 | |
2109 private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) { | |
2110 if (!usedExecuteChildMethods.contains(execution)) { | |
2111 return null; | |
2112 } | |
2113 | |
2114 LocalContext locals = LocalContext.load(this, createSpecializationNodeSignature(0), Integer.MAX_VALUE); | |
2115 | |
2116 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), Integer.MAX_VALUE, FRAME_VALUE); | |
2117 if (hasChildUnexpectedResult(execution, targetType)) { | |
2118 method.getThrownTypes().add(getType(UnexpectedResultException.class)); | |
2119 } | |
2120 | |
2121 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType); | |
2122 if (implicitProfile != null) { | |
2123 method.addParameter(implicitProfile); | |
2124 } | |
2125 | |
2126 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { | |
2127 NodeExecutionData executeWith = node.getChildExecutions().get(i); | |
2128 LocalVariable var = locals.createValue(executeWith, genericType); | |
2129 method.addParameter(var.createParameter()); | |
2130 locals.setValue(executeWith, var); | |
2131 } | |
2132 | |
2133 CodeTreeBuilder builder = method.createBuilder(); | |
2134 CodeTree executeChild = createExecuteChild(execution, locals.createValue(execution, targetType), locals, true); | |
2135 if (executeChild.isSingleLine()) { | |
2136 builder.statement(executeChild); | |
2137 } else { | |
2138 builder.tree(executeChild); | |
2139 } | |
2140 return method; | |
2141 } | |
2142 | |
2143 private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) { | |
2144 if (typeSystem.hasImplicitSourceTypes(targetType)) { | |
2145 if (typeEquals(node.getGenericType(execution), targetType)) { | |
2146 return null; | |
2147 } | |
2148 | |
2149 switch (options.implicitCastOptimization()) { | |
2150 case NONE: | |
2151 return null; | |
2152 case DUPLICATE_TAIL: | |
2153 return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution)); | |
2154 case MERGE_CASTS: | |
2155 return new CodeVariableElement(ImplicitCastNodeFactory.type(typeSystem, targetType), implicitNodeFieldName(execution)); | |
2156 } | |
2157 } | |
2158 return null; | |
2159 } | |
2160 | |
2161 private boolean isExecuteChildShared(NodeExecutionData execution, TypeMirror targetType) { | |
2162 if (isVoid(targetType)) { | |
2163 return false; | |
2164 } else if (isObject(targetType)) { | |
2165 return resolvePolymorphicExecutables(execution).size() >= 1; | |
2166 } else { | |
2167 if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) { | |
2168 return false; | |
2169 } | |
2170 if (!typeSystem.hasImplicitSourceTypes(targetType)) { | |
2171 return false; | |
2172 } | |
2173 | |
2174 int uses = 0; | |
2175 for (SpecializationData specialization : node.getSpecializations()) { | |
2176 List<Parameter> parameters = specialization.findByExecutionData(execution); | |
2177 for (Parameter parameter : parameters) { | |
2178 if (targetType.equals(parameter.getType())) { | |
2179 uses++; | |
2180 } | |
2181 } | |
2182 } | |
2183 if (uses > 1) { | |
2184 return resolveSpecializedExecutables(execution, typeSystem.lookupSourceTypes(targetType), options.implicitTypeBoxingOptimization()).size() > 1; | |
2185 } else { | |
2186 return false; | |
2187 } | |
2188 } | |
2189 } | |
2190 | |
2191 private CodeTree createAssignExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData type, LocalVariable targetValue, LocalVariable shortCircuit, | |
2192 LocalContext currentValues) { | |
2193 CodeTreeBuilder builder = parent.create(); | |
2194 boolean hasUnexpected = hasChildUnexpectedResult(execution, targetValue.getTypeMirror()); | |
2195 | |
2196 CodeTree executeChild; | |
2197 if (isExecuteChildShared(execution, targetValue.getTypeMirror())) { | |
2198 executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues); | |
2199 } else { | |
2200 executeChild = createExecuteChild(execution, targetValue, currentValues, false); | |
2201 } | |
2202 | |
2203 builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected)); | |
2204 | |
2205 if (shortCircuit != null) { | |
2206 currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null)); | |
2207 } | |
2208 | |
2209 builder.end(); | |
2210 if (hasUnexpected) { | |
2211 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
2212 LocalContext slowPathValues = currentValues.copy(); | |
2213 slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); | |
2214 | |
2215 ExecutableTypeData delegateType = node.getGenericExecutableType(type); | |
2216 boolean found = false; | |
2217 for (NodeExecutionData otherExecution : node.getChildExecutions()) { | |
2218 if (found) { | |
2219 LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType); | |
2220 LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues); | |
2221 builder.tree(createAssignExecuteChild(builder, otherExecution, delegateType, childEvaluatedValue, genericShortCircuit, slowPathValues)); | |
2222 slowPathValues.setValue(otherExecution, childEvaluatedValue); | |
2223 } else { | |
2224 // skip forward already evaluated | |
2225 found = execution == otherExecution; | |
2226 } | |
2227 } | |
2228 builder.tree(createCallNext(builder, type, delegateType, slowPathValues)); | |
2229 builder.end(); | |
2230 } | |
2231 | |
2232 return createShortCircuit(targetValue, shortCircuit, builder.build()); | |
2233 } | |
2234 | |
2235 private static CodeTree createShortCircuit(LocalVariable targetValue, LocalVariable shortCircuitValue, CodeTree tryExecute) { | |
2236 if (shortCircuitValue == null) { | |
2237 return tryExecute; | |
2238 } | |
2239 | |
2240 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2241 | |
2242 builder.tree(shortCircuitValue.createDeclaration(shortCircuitValue.createReference())); | |
2243 builder.tree(targetValue.createDeclaration(builder.create().defaultValue(targetValue.getTypeMirror()).build())); | |
2244 | |
2245 builder.startIf().string(shortCircuitValue.getName()).end().startBlock(); | |
2246 builder.tree(tryExecute); | |
2247 builder.end(); | |
2248 | |
2249 return builder.build(); | |
2250 } | |
2251 | |
2252 private static CodeTree createTryExecuteChild(LocalVariable value, CodeTree executeChild, boolean needDeclaration, boolean hasTry) { | |
2253 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2254 boolean hasDeclaration = false; | |
2255 if ((hasTry || !executeChild.isSingleLine()) && needDeclaration) { | |
2256 builder.tree(value.createDeclaration(null)); | |
2257 hasDeclaration = true; | |
2258 } | |
2259 | |
2260 if (hasTry) { | |
2261 builder.startTryBlock(); | |
2262 } else { | |
2263 builder.startGroup(); | |
2264 } | |
2265 | |
2266 if (executeChild.isSingleLine()) { | |
2267 builder.startStatement(); | |
2268 if (hasDeclaration || !needDeclaration) { | |
2269 builder.tree(executeChild); | |
2270 } else { | |
2271 builder.type(value.getTypeMirror()).string(" ").tree(executeChild); | |
2272 } | |
2273 builder.end(); | |
2274 } else { | |
2275 builder.tree(executeChild); | |
2276 } | |
2277 | |
2278 builder.end(); | |
2279 | |
2280 return builder.build(); | |
2281 } | |
2282 | |
2283 private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) { | |
2284 if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) { | |
2285 throw new AssertionError("Execute child not shared with method but called."); | |
2286 } | |
2287 usedExecuteChildMethods.add(execution); | |
2288 | |
2289 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2290 builder.tree(targetValue.createReference()).string(" = "); | |
2291 builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror())); | |
2292 if (currentValues.get(FRAME_VALUE) == null) { | |
2293 builder.nullLiteral(); | |
2294 } else { | |
2295 builder.string(FRAME_VALUE); | |
2296 } | |
2297 | |
2298 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getTypeMirror()); | |
2299 if (implicitProfile != null) { | |
2300 builder.string(implicitProfile.getName()); | |
2301 } | |
2302 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { | |
2303 builder.tree(currentValues.getValue(i).createReference()); | |
2304 } | |
2305 builder.end(); | |
2306 return builder.build(); | |
2307 } | |
2308 | |
2309 private CodeTree createExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) { | |
2310 final CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2311 | |
2312 CodeTree assignment = createAssignmentStart(target, shared); | |
2313 | |
2314 final Set<ExecutableTypeData> executableTypes = findSpecializedExecutableTypes(execution, target.getTypeMirror()); | |
2315 if (executableTypes.isEmpty()) { | |
2316 throw new AssertionError(); // cannot execute child | |
2317 } else if (executableTypes.size() == 1 && !typeSystem.hasImplicitSourceTypes(target.getTypeMirror())) { | |
2318 ExecutableTypeData executableType = executableTypes.iterator().next(); | |
2319 if (isObject(target.getTypeMirror()) && executableType.getEvaluatedCount() == 0) { | |
2320 return createPolymorphicExecuteChild(execution, target, currentValues, shared); | |
2321 } else { | |
2322 builder.tree(assignment); | |
2323 builder.tree(createSingleExecute(execution, target, currentValues, executableType)); | |
2324 } | |
2325 } else { | |
2326 if (options.implicitCastOptimization().isNone()) { | |
2327 throw new AssertionError("findSpecializedExecutableTypes is always 1 if implicit cast opt is disabled"); | |
2328 } else if (options.implicitCastOptimization().isDuplicateTail()) { | |
2329 builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues)); | |
2330 } else if (options.implicitCastOptimization().isMergeCasts()) { | |
2331 // TODO | |
2332 throw new UnsupportedOperationException(); | |
2333 } else { | |
2334 throw new AssertionError(); | |
2335 } | |
2336 } | |
2337 return builder.build(); | |
2338 } | |
2339 | |
2340 private CodeTree createSingleExecute(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, ExecutableTypeData executableType) { | |
2341 CodeTree execute = callExecuteMethod(execution, executableType, currentValues); | |
2342 return expect(executableType.getReturnType(), target.getTypeMirror(), execute); | |
2343 } | |
2344 | |
2345 private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError { | |
2346 ExecutableTypeData genericExecutableType = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size()); | |
2347 if (genericExecutableType == null) { | |
2348 throw new AssertionError("At least one generic executable method must be available."); | |
2349 } | |
2350 | |
2351 List<ExecutableTypeData> specializedExecutables = resolvePolymorphicExecutables(execution); | |
2352 Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() { | |
2353 public int compare(ExecutableTypeData o1, ExecutableTypeData o2) { | |
2354 return compareType(o1.getReturnType(), o2.getReturnType()); | |
2355 } | |
2356 }); | |
2357 | |
2358 CodeTree assignment = createAssignmentStart(target, shared); | |
2359 CodeTree executeGeneric = createSingleExecute(execution, target, currentValues, genericExecutableType); | |
2360 | |
2361 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2362 if (specializedExecutables.isEmpty()) { | |
2363 builder.tree(assignment); | |
2364 builder.tree(executeGeneric); | |
2365 } else { | |
2366 final CodeTreeBuilder polyChainBuilder = builder.create(); | |
2367 final String profileField = polymorphicTypeProfileFieldName(execution); | |
2368 final String valueFieldName = "_value"; | |
2369 final String typeFieldName = "_type"; | |
2370 | |
2371 builder.declaration(getType(Class.class), profileField, accessParent(profileField)); | |
2372 | |
2373 boolean encounteredUnexpectedResult = false; | |
2374 boolean hasSpecializedTypes = false; | |
2375 for (ExecutableTypeData executableType : specializedExecutables) { | |
2376 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); | |
2377 polyChainBuilder.string(profileField); | |
2378 polyChainBuilder.string(" == ").typeLiteral(executableType.getReturnType()); | |
2379 polyChainBuilder.end(); | |
2380 polyChainBuilder.startBlock(); | |
2381 polyChainBuilder.startStatement(); | |
2382 polyChainBuilder.tree(assignment); | |
2383 polyChainBuilder.tree(createSingleExecute(execution, target, currentValues, executableType)).end(); | |
2384 polyChainBuilder.end(); | |
2385 encounteredUnexpectedResult |= executableType.hasUnexpectedValue(context); | |
2386 } | |
2387 | |
2388 // else if null -> specialize | |
2389 polyChainBuilder.startElseIf().string(profileField).string(" == null").end(); | |
2390 polyChainBuilder.startBlock(); | |
2391 polyChainBuilder.tree(createTransferToInterpreterAndInvalidate()); | |
2392 polyChainBuilder.declaration(context.getType(Class.class), typeFieldName, polyChainBuilder.create().typeLiteral(genericType).build()); | |
2393 polyChainBuilder.startTryBlock(); | |
2394 polyChainBuilder.declaration(genericExecutableType.getReturnType(), valueFieldName, executeGeneric); | |
2395 | |
2396 hasSpecializedTypes = false; | |
2397 for (ExecutableTypeData executableType : specializedExecutables) { | |
2398 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); | |
2399 polyChainBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, executableType.getReturnType(), CodeTreeBuilder.singleString(valueFieldName))); | |
2400 polyChainBuilder.end(); | |
2401 polyChainBuilder.startBlock(); | |
2402 polyChainBuilder.startStatement().string(typeFieldName).string(" = ").typeLiteral(executableType.getReturnType()).end(); | |
2403 polyChainBuilder.end(); | |
2404 } | |
2405 polyChainBuilder.startElseBlock(); | |
2406 polyChainBuilder.startStatement().string(typeFieldName).string(" = ").typeLiteral(genericType).end(); | |
2407 polyChainBuilder.end(); | |
2408 polyChainBuilder.startReturn().string(valueFieldName).end(); | |
2409 | |
2410 polyChainBuilder.end().startFinallyBlock(); | |
2411 polyChainBuilder.startStatement().tree(accessParent(profileField)).string(" = ").string(typeFieldName).end(); | |
2412 polyChainBuilder.end(); | |
2413 polyChainBuilder.end(); | |
2414 | |
2415 // else -> execute generic | |
2416 polyChainBuilder.startElseBlock(); | |
2417 polyChainBuilder.startStatement().tree(assignment).tree(executeGeneric).end(); | |
2418 polyChainBuilder.end(); | |
2419 | |
2420 CodeTree executePolymorphic = polyChainBuilder.build(); | |
2421 if (encounteredUnexpectedResult) { | |
2422 builder.startTryBlock(); | |
2423 builder.tree(executePolymorphic); | |
2424 builder.end(); | |
2425 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
2426 builder.startStatement().tree(accessParent(profileField)).string(" = ").typeLiteral(genericType).end(); | |
2427 builder.startReturn().string("ex.getResult()").end(); | |
2428 builder.end(); | |
2429 } else { | |
2430 builder.tree(executePolymorphic); | |
2431 } | |
2432 } | |
2433 return builder.build(); | |
2434 } | |
2435 | |
2436 private List<ExecutableTypeData> resolvePolymorphicExecutables(NodeExecutionData execution) { | |
2437 if (singleSpecializable) { | |
2438 return Collections.emptyList(); | |
2439 } | |
2440 Set<TypeMirror> specializedTypes = new HashSet<>(); | |
2441 for (TypeMirror type : node.findSpecializedTypes(execution)) { | |
2442 specializedTypes.addAll(typeSystem.lookupSourceTypes(type)); | |
2443 } | |
2444 return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); | |
2445 } | |
2446 | |
2447 private static CodeTree createAssignmentStart(LocalVariable target, boolean shared) { | |
2448 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2449 if (shared) { | |
2450 builder.string("return "); | |
2451 } else { | |
2452 builder.string(target.getName()).string(" = "); | |
2453 } | |
2454 return builder.build(); | |
2455 } | |
2456 | |
2457 private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) { | |
2458 CodeTreeBuilder builder = parent.create(); | |
2459 List<TypeMirror> sourceTypes = typeSystem.lookupSourceTypes(target.getTypeMirror()); | |
2460 String implicitClassFieldName = implicitClassFieldName(execution); | |
2461 List<ExecutableTypeData> executableTypes = resolveSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization()); | |
2462 | |
2463 boolean elseIf = false; | |
2464 for (ExecutableTypeData executableType : executableTypes) { | |
2465 elseIf = builder.startIf(elseIf); | |
2466 builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getReturnType()); | |
2467 builder.end(); | |
2468 builder.startBlock(); | |
2469 builder.startStatement().tree(assignment); | |
2470 | |
2471 CodeTree execute = callExecuteMethod(execution, executableType, currentValues); | |
2472 ImplicitCastData cast = typeSystem.lookupCast(executableType.getReturnType(), target.getTypeMirror()); | |
2473 if (cast != null) { | |
2474 execute = callMethod(null, cast.getMethod(), execute); | |
2475 } | |
2476 builder.tree(execute); | |
2477 builder.end(); | |
2478 builder.end(); | |
2479 } | |
2480 | |
2481 if (!executableTypes.isEmpty()) { | |
2482 builder.startElseBlock(); | |
2483 } | |
2484 | |
2485 LocalVariable genericValue = target.makeGeneric(context).nextName(); | |
2486 builder.tree(createAssignExecuteChild(builder, execution, node.getGenericExecutableType(null), genericValue, null, currentValues)); | |
2487 if (executableTypes.size() == sourceTypes.size()) { | |
2488 builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end(); | |
2489 } else { | |
2490 builder.startStatement().tree(assignment); | |
2491 builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName)); | |
2492 builder.end(); | |
2493 } | |
2494 | |
2495 if (!executableTypes.isEmpty()) { | |
2496 builder.end(); | |
2497 } | |
2498 return builder.build(); | |
2499 } | |
2500 | |
2501 private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, ExecutableTypeData forType, LocalContext currentValues, CodeTree execution) { | |
2502 if (specialization.getExceptions().isEmpty()) { | |
2503 return execution; | |
2504 } | |
2505 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
2506 builder.startTryBlock(); | |
2507 builder.tree(execution); | |
2508 TypeMirror[] exceptionTypes = new TypeMirror[specialization.getExceptions().size()]; | |
2509 for (int i = 0; i < exceptionTypes.length; i++) { | |
2510 exceptionTypes[i] = specialization.getExceptions().get(i).getJavaClass(); | |
2511 } | |
2512 builder.end().startCatchBlock(exceptionTypes, "ex"); | |
2513 builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end(); | |
2514 builder.tree(createCallRemove("threw rewrite exception", forType, currentValues)); | |
2515 builder.end(); | |
2516 return builder.build(); | |
2517 } | |
2518 | |
2519 private CodeTree[] createMethodGuardCheck(List<GuardExpression> guardExpressions, SpecializationData specialization, LocalContext currentValues, boolean fastPath) { | |
2520 CodeTreeBuilder expressionBuilder = CodeTreeBuilder.createBuilder(); | |
2521 CodeTreeBuilder assertionBuilder = CodeTreeBuilder.createBuilder(); | |
2522 String and = ""; | |
2523 for (GuardExpression guard : guardExpressions) { | |
2524 DSLExpression expression = guard.getExpression(); | |
2525 | |
2526 Map<Variable, CodeTree> resolvedBindings = castBoundTypes(bindExpressionValues(expression, specialization, currentValues)); | |
2527 CodeTree expressionCode = DSLExpressionGenerator.write(expression, accessParent(null), resolvedBindings); | |
2528 | |
2529 if (!specialization.isDynamicParameterBound(expression) && fastPath) { | |
2530 /* | |
2531 * Guards where no dynamic parameters are bound can just be executed on the fast | |
2532 * path. | |
2533 */ | |
2534 assertionBuilder.startAssert().tree(expressionCode).end(); | |
2535 } else { | |
2536 expressionBuilder.string(and); | |
2537 expressionBuilder.tree(expressionCode); | |
2538 and = " && "; | |
2539 } | |
2540 } | |
2541 return new CodeTree[]{expressionBuilder.build(), assertionBuilder.build()}; | |
2542 } | |
2543 | |
2544 private static Map<Variable, CodeTree> castBoundTypes(Map<Variable, LocalVariable> bindings) { | |
2545 Map<Variable, CodeTree> resolvedBindings = new HashMap<>(); | |
2546 for (Variable variable : bindings.keySet()) { | |
2547 LocalVariable localVariable = bindings.get(variable); | |
2548 CodeTree resolved = localVariable.createReference(); | |
2549 TypeMirror sourceType = localVariable.getTypeMirror(); | |
2550 TypeMirror targetType = variable.getResolvedTargetType(); | |
2551 if (targetType == null) { | |
2552 targetType = variable.getResolvedType(); | |
2553 } | |
2554 if (!ElementUtils.isAssignable(sourceType, targetType)) { | |
2555 resolved = CodeTreeBuilder.createBuilder().cast(targetType, resolved).build(); | |
2556 } | |
2557 resolvedBindings.put(variable, resolved); | |
2558 } | |
2559 return resolvedBindings; | |
2560 } | |
2561 | |
2562 private static Map<Variable, LocalVariable> bindExpressionValues(DSLExpression expression, SpecializationData specialization, LocalContext currentValues) throws AssertionError { | |
2563 Map<Variable, LocalVariable> bindings = new HashMap<>(); | |
2564 | |
2565 Set<Variable> boundVariables = expression.findBoundVariables(); | |
2566 if (specialization == null && !boundVariables.isEmpty()) { | |
2567 throw new AssertionError("Cannot bind guard variable in non-specialization group. yet."); | |
2568 } | |
2569 | |
2570 // resolve bindings for local context | |
2571 for (Variable variable : boundVariables) { | |
2572 Parameter resolvedParameter = specialization.findByVariable(variable.getResolvedVariable()); | |
2573 if (resolvedParameter != null) { | |
2574 LocalVariable localVariable; | |
2575 if (resolvedParameter.getSpecification().isSignature()) { | |
2576 NodeExecutionData execution = resolvedParameter.getSpecification().getExecution(); | |
2577 localVariable = currentValues.getValue(execution); | |
2578 } else { | |
2579 localVariable = currentValues.get(resolvedParameter.getLocalName()); | |
2580 } | |
2581 if (localVariable != null) { | |
2582 bindings.put(variable, localVariable); | |
2583 } | |
2584 } | |
2585 } | |
2586 return bindings; | |
2587 } | |
2588 | |
2589 private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, | |
2590 SpecializationBody specializationExecution) { | |
2591 CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); | |
2592 CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder(); | |
2593 for (TypeGuard typeGuard : typeGuards) { | |
2594 int signatureIndex = typeGuard.getSignatureIndex(); | |
2595 LocalVariable value = currentValues.getValue(signatureIndex); | |
2596 TypeMirror targetType = typeGuard.getType(); | |
2597 if (!ElementUtils.needsCastTo(value.getTypeMirror(), targetType)) { | |
2598 continue; | |
2599 } | |
2600 NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); | |
2601 if (!checksBuilder.isEmpty()) { | |
2602 checksBuilder.string(" && "); | |
2603 } | |
2604 | |
2605 CodeTreeBuilder checkBuilder = checksBuilder.create(); | |
2606 CodeTreeBuilder castBuilder = checksBuilder.create(); | |
2607 | |
2608 LocalVariable shortCircuit = currentValues.getShortCircuit(execution); | |
2609 if (shortCircuit != null) { | |
2610 checkBuilder.string("("); | |
2611 CodeTreeBuilder referenceBuilder = checkBuilder.create(); | |
2612 if (!ElementUtils.isPrimitive(shortCircuit.getTypeMirror())) { | |
2613 referenceBuilder.string("(boolean) "); | |
2614 } | |
2615 referenceBuilder.tree(shortCircuit.createReference()); | |
2616 checkBuilder.string("!").tree(referenceBuilder.build()); | |
2617 checkBuilder.string(" || "); | |
2618 castBuilder.tree(referenceBuilder.build()).string(" ? "); | |
2619 } | |
2620 | |
2621 List<ImplicitCastData> sourceTypes = typeSystem.lookupByTargetType(targetType); | |
2622 CodeTree valueReference = value.createReference(); | |
2623 if (sourceTypes.isEmpty()) { | |
2624 checkBuilder.tree(TypeSystemCodeGenerator.check(typeSystem, targetType, value.createReference())); | |
2625 castBuilder.tree(TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference)); | |
2626 } else { | |
2627 ImplicitCastOptimization opt = options.implicitCastOptimization(); | |
2628 if (specializationExecution.isFastPath() && !opt.isNone()) { | |
2629 if (opt.isDuplicateTail()) { | |
2630 String typeHintField = implicitClassFieldName(execution); | |
2631 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, typeHintField)); | |
2632 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, typeHintField)); | |
2633 } else if (opt.isMergeCasts()) { | |
2634 checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference)); | |
2635 castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference)); | |
2636 } else { | |
2637 throw new AssertionError("implicit cast opt"); | |
2638 } | |
2639 } else { | |
2640 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(typeSystem, targetType, valueReference, null)); | |
2641 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(typeSystem, targetType, valueReference, null)); | |
2642 } | |
2643 } | |
2644 | |
2645 if (shortCircuit != null) { | |
2646 checkBuilder.string(")"); | |
2647 castBuilder.string(" : ").defaultValue(targetType); | |
2648 } | |
2649 | |
2650 if (castGuards == null || castGuards.contains(typeGuard)) { | |
2651 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); | |
2652 currentValues.setValue(execution, castVariable); | |
2653 localsBuilder.tree(castVariable.createDeclaration(castBuilder.build())); | |
2654 } | |
2655 | |
2656 checksBuilder.tree(checkBuilder.build()); | |
2657 } | |
2658 | |
2659 if (specialization != null && !specializationExecution.isFastPath()) { | |
2660 for (CacheExpression cache : specialization.getCaches()) { | |
2661 if (specialization.isCacheBoundByGuard(cache)) { | |
2662 initializeCache(localsBuilder, specialization, cache, currentValues); | |
2663 } | |
2664 } | |
2665 } | |
2666 | |
2667 return new CodeTree[]{checksBuilder.build(), localsBuilder.build()}; | |
2668 } | |
2669 | |
2670 private void initializeCache(CodeTreeBuilder builder, SpecializationData specialization, CacheExpression cache, LocalContext currentValues) { | |
2671 CodeTree initializer = DSLExpressionGenerator.write(cache.getExpression(), accessParent(null), castBoundTypes(bindExpressionValues(cache.getExpression(), specialization, currentValues))); | |
2672 String name = cache.getParameter().getLocalName(); | |
2673 // multiple specializations might use the same name | |
2674 String varName = name + specialization.getIndex(); | |
2675 TypeMirror type = cache.getParameter().getType(); | |
2676 builder.declaration(type, varName, initializer); | |
2677 currentValues.set(name, new LocalVariable(type, varName, null, null)); | |
2678 } | |
2679 | |
2680 public static final class LocalContext { | |
2681 | |
2682 private final NodeGenFactory factory; | |
2683 private final Map<String, LocalVariable> values = new HashMap<>(); | |
2684 | |
2685 private LocalContext(NodeGenFactory factory) { | |
2686 this.factory = factory; | |
2687 } | |
2688 | |
2689 public void loadFastPathState(SpecializationData specialization) { | |
2690 for (CacheExpression cache : specialization.getCaches()) { | |
2691 Parameter cacheParameter = cache.getParameter(); | |
2692 String name = cacheParameter.getVariableElement().getSimpleName().toString(); | |
2693 set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name), null)); | |
2694 } | |
2695 | |
2696 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
2697 String name = assumptionName(assumption); | |
2698 TypeMirror type = assumption.getExpression().getResolvedType(); | |
2699 set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null)); | |
2700 } | |
2701 } | |
2702 | |
2703 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, int varArgsThreshold, String... optionalArguments) { | |
2704 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); | |
2705 addParametersTo(method, varArgsThreshold, optionalArguments); | |
2706 return method; | |
2707 } | |
2708 | |
2709 public static LocalContext load(NodeGenFactory factory, ExecutableTypeData type, int varargsThreshold) { | |
2710 LocalContext context = new LocalContext(factory); | |
2711 context.loadEvaluatedValues(type, varargsThreshold); | |
2712 return context; | |
2713 } | |
2714 | |
2715 private void loadEvaluatedValues(ExecutableTypeData executedType, int varargsThreshold) { | |
2716 TypeMirror frame = executedType.getFrameParameter(); | |
2717 if (frame == null) { | |
2718 removeValue(FRAME_VALUE); | |
2719 } else { | |
2720 set(FRAME_VALUE, new LocalVariable(frame, FRAME_VALUE, null, null)); | |
2721 } | |
2722 for (NodeFieldData field : factory.node.getFields()) { | |
2723 String fieldName = fieldValueName(field); | |
2724 values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null)); | |
2725 } | |
2726 boolean varargs = needsVarargs(false, varargsThreshold); | |
2727 List<TypeMirror> evaluatedParameter = executedType.getEvaluatedParameters(); | |
2728 int evaluatedIndex = 0; | |
2729 for (int executionIndex = 0; executionIndex < factory.node.getExecutionCount(); executionIndex++) { | |
2730 NodeExecutionData execution = factory.node.getChildExecutions().get(executionIndex); | |
2731 if (execution.isShortCircuit()) { | |
2732 if (evaluatedIndex < executedType.getEvaluatedCount()) { | |
2733 TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex); | |
2734 LocalVariable shortCircuit = createShortCircuitValue(execution).newType(evaluatedType); | |
2735 if (varargs) { | |
2736 shortCircuit = shortCircuit.accessWith(createReadVarargs(evaluatedIndex)); | |
2737 } | |
2738 values.put(shortCircuit.getName(), shortCircuit.makeOriginal()); | |
2739 evaluatedIndex++; | |
2740 } | |
2741 } | |
2742 if (evaluatedIndex < executedType.getEvaluatedCount()) { | |
2743 TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex); | |
2744 LocalVariable value = createValue(execution, evaluatedType); | |
2745 if (varargs) { | |
2746 value = value.accessWith(createReadVarargs(evaluatedIndex)); | |
2747 } | |
2748 values.put(value.getName(), value.makeOriginal()); | |
2749 evaluatedIndex++; | |
2750 } | |
2751 } | |
2752 } | |
2753 | |
2754 public static LocalContext load(NodeGenFactory factory) { | |
2755 return load(factory, factory.createSpecializationNodeSignature(factory.node.getSignatureSize()), factory.varArgsThreshold); | |
2756 } | |
2757 | |
2758 public LocalContext copy() { | |
2759 LocalContext copy = new LocalContext(factory); | |
2760 copy.values.putAll(values); | |
2761 return copy; | |
2762 } | |
2763 | |
2764 private static String fieldValueName(NodeFieldData field) { | |
2765 return field.getName() + "Value"; | |
2766 } | |
2767 | |
2768 @SuppressWarnings("static-method") | |
2769 public LocalVariable createValue(NodeExecutionData execution, TypeMirror type) { | |
2770 return new LocalVariable(type, valueName(execution), null, null); | |
2771 } | |
2772 | |
2773 public LocalVariable createShortCircuitValue(NodeExecutionData execution) { | |
2774 return new LocalVariable(factory.getType(boolean.class), shortCircuitName(execution), null, null); | |
2775 } | |
2776 | |
2777 private static String valueName(NodeExecutionData execution) { | |
2778 return execution.getName() + "Value"; | |
2779 } | |
2780 | |
2781 private static String shortCircuitName(NodeExecutionData execution) { | |
2782 return "has" + ElementUtils.firstLetterUpperCase(valueName(execution)); | |
2783 } | |
2784 | |
2785 public void set(String id, LocalVariable var) { | |
2786 values.put(id, var); | |
2787 } | |
2788 | |
2789 public LocalVariable get(String id) { | |
2790 return values.get(id); | |
2791 } | |
2792 | |
2793 public LocalVariable get(Parameter parameter, int signatureIndex) { | |
2794 LocalVariable var = get(parameter.getLocalName()); | |
2795 if (var == null && parameter.getSpecification().isSignature()) { | |
2796 // lookup by signature index for executeWith | |
2797 List<NodeExecutionData> childExecutions = factory.node.getChildExecutions(); | |
2798 if (signatureIndex < childExecutions.size() && signatureIndex >= 0) { | |
2799 NodeExecutionData execution = childExecutions.get(signatureIndex); | |
2800 var = getValue(execution); | |
2801 } | |
2802 } | |
2803 return var; | |
2804 } | |
2805 | |
2806 public LocalVariable getValue(NodeExecutionData execution) { | |
2807 return get(valueName(execution)); | |
2808 } | |
2809 | |
2810 public LocalVariable getValue(int signatureIndex) { | |
2811 List<NodeExecutionData> childExecutions = factory.node.getChildExecutions(); | |
2812 if (signatureIndex < childExecutions.size()) { | |
2813 return getValue(childExecutions.get(signatureIndex)); | |
2814 } else { | |
2815 return null; | |
2816 } | |
2817 } | |
2818 | |
2819 public void removeValue(String id) { | |
2820 values.remove(id); | |
2821 } | |
2822 | |
2823 public void setValue(NodeExecutionData execution, LocalVariable var) { | |
2824 values.put(valueName(execution), var); | |
2825 } | |
2826 | |
2827 public void setShortCircuitValue(NodeExecutionData execution, LocalVariable var) { | |
2828 if (var == null) { | |
2829 return; | |
2830 } | |
2831 values.put(shortCircuitName(execution), var); | |
2832 } | |
2833 | |
2834 private boolean needsVarargs(boolean requireLoaded, int varArgsThreshold) { | |
2835 int size = 0; | |
2836 for (NodeExecutionData execution : factory.node.getChildExecutions()) { | |
2837 if (requireLoaded && getValue(execution) == null) { | |
2838 continue; | |
2839 } | |
2840 if (execution.isShortCircuit()) { | |
2841 size += 2; | |
2842 } else { | |
2843 size++; | |
2844 } | |
2845 } | |
2846 return size >= varArgsThreshold; | |
2847 } | |
2848 | |
2849 private static CodeTree createReadVarargs(int i) { | |
2850 return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build(); | |
2851 } | |
2852 | |
2853 public void addReferencesTo(CodeTreeBuilder builder, String... optionalNames) { | |
2854 for (String var : optionalNames) { | |
2855 LocalVariable local = values.get(var); | |
2856 if (local == null) { | |
2857 builder.nullLiteral(); | |
2858 } else { | |
2859 builder.tree(local.createReference()); | |
2860 } | |
2861 } | |
2862 | |
2863 List<NodeExecutionData> executions = factory.node.getChildExecutions(); | |
2864 for (NodeExecutionData execution : executions) { | |
2865 if (execution.isShortCircuit()) { | |
2866 LocalVariable shortCircuitVar = getShortCircuit(execution); | |
2867 if (shortCircuitVar != null) { | |
2868 builder.tree(shortCircuitVar.createReference()); | |
2869 } | |
2870 } | |
2871 LocalVariable var = getValue(execution); | |
2872 if (var != null) { | |
2873 builder.startGroup(); | |
2874 if (executions.size() == 1 && ElementUtils.typeEquals(var.getTypeMirror(), factory.getType(Object[].class))) { | |
2875 // if the current type is Object[] do not use varargs for a single argument | |
2876 builder.string("(Object) "); | |
2877 } | |
2878 builder.tree(var.createReference()); | |
2879 builder.end(); | |
2880 } | |
2881 } | |
2882 } | |
2883 | |
2884 public void addParametersTo(CodeExecutableElement method, int varArgsThreshold, String... optionalNames) { | |
2885 for (String var : optionalNames) { | |
2886 LocalVariable local = values.get(var); | |
2887 if (local != null) { | |
2888 method.addParameter(local.createParameter()); | |
2889 } | |
2890 } | |
2891 if (needsVarargs(true, varArgsThreshold)) { | |
2892 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_")); | |
2893 method.setVarArgs(true); | |
2894 } else { | |
2895 for (NodeExecutionData execution : factory.node.getChildExecutions()) { | |
2896 if (execution.isShortCircuit()) { | |
2897 LocalVariable shortCircuitVar = getShortCircuit(execution); | |
2898 if (shortCircuitVar != null) { | |
2899 method.addParameter(shortCircuitVar.createParameter()); | |
2900 } | |
2901 } | |
2902 | |
2903 LocalVariable var = getValue(execution); | |
2904 if (var != null) { | |
2905 method.addParameter(var.createParameter()); | |
2906 } | |
2907 } | |
2908 } | |
2909 } | |
2910 | |
2911 private LocalVariable getShortCircuit(NodeExecutionData execution) { | |
2912 return values.get(shortCircuitName(execution)); | |
2913 } | |
2914 | |
2915 @Override | |
2916 public String toString() { | |
2917 return "LocalContext [values=" + values + "]"; | |
2918 } | |
2919 | |
2920 } | |
2921 | |
2922 public static final class LocalVariable { | |
2923 | |
2924 private final TypeMirror typeMirror; | |
2925 private final CodeTree accessorTree; | |
2926 private final String name; | |
2927 private final LocalVariable previous; | |
2928 | |
2929 public static LocalVariable fromParameter(Parameter parameter) { | |
2930 NodeExecutionData execution = parameter.getSpecification().getExecution(); | |
2931 String name = null; | |
2932 if (execution == null) { | |
2933 name = parameter.getLocalName(); | |
2934 } else { | |
2935 name = createName(execution); | |
2936 } | |
2937 return new LocalVariable(parameter.getType(), name, null, null); | |
2938 } | |
2939 | |
2940 private LocalVariable(TypeMirror typeMirror, String name, CodeTree accessorTree, LocalVariable previous) { | |
2941 Objects.requireNonNull(typeMirror); | |
2942 this.typeMirror = typeMirror; | |
2943 this.accessorTree = accessorTree; | |
2944 this.name = name; | |
2945 this.previous = previous; | |
2946 } | |
2947 | |
2948 public String getShortCircuitName() { | |
2949 return "has" + ElementUtils.firstLetterUpperCase(getName()); | |
2950 } | |
2951 | |
2952 public String getName() { | |
2953 return name; | |
2954 } | |
2955 | |
2956 private static String createNextName(String name) { | |
2957 return name + "_"; | |
2958 } | |
2959 | |
2960 private static String createName(NodeExecutionData execution) { | |
2961 if (execution == null) { | |
2962 return "<error>"; | |
2963 } | |
2964 return execution.getName() + "Value"; | |
2965 } | |
2966 | |
2967 public TypeMirror getTypeMirror() { | |
2968 return typeMirror; | |
2969 } | |
2970 | |
2971 public CodeVariableElement createParameter() { | |
2972 return new CodeVariableElement(getTypeMirror(), getName()); | |
2973 } | |
2974 | |
2975 public CodeTree createDeclaration(CodeTree init) { | |
2976 return CodeTreeBuilder.createBuilder().declaration(getTypeMirror(), getName(), init).build(); | |
2977 } | |
2978 | |
2979 public CodeTree createReference() { | |
2980 if (accessorTree != null) { | |
2981 return accessorTree; | |
2982 } else { | |
2983 return CodeTreeBuilder.singleString(getName()); | |
2984 } | |
2985 } | |
2986 | |
2987 public LocalVariable newType(TypeMirror newType) { | |
2988 return new LocalVariable(newType, name, accessorTree, this); | |
2989 } | |
2990 | |
2991 public LocalVariable accessWith(CodeTree tree) { | |
2992 return new LocalVariable(typeMirror, name, tree, this); | |
2993 } | |
2994 | |
2995 public LocalVariable nextName() { | |
2996 return new LocalVariable(typeMirror, createNextName(name), accessorTree, this); | |
2997 } | |
2998 | |
2999 public LocalVariable makeOriginal() { | |
3000 return new LocalVariable(typeMirror, name, accessorTree, null); | |
3001 } | |
3002 | |
3003 public LocalVariable original() { | |
3004 LocalVariable variable = this; | |
3005 while (variable.previous != null) { | |
3006 variable = variable.previous; | |
3007 } | |
3008 return variable; | |
3009 } | |
3010 | |
3011 public LocalVariable makeGeneric(ProcessorContext context) { | |
3012 return newType(context.getType(Object.class)); | |
3013 } | |
3014 | |
3015 @Override | |
3016 public String toString() { | |
3017 return "Local[type = " + getTypeMirror() + ", name = " + name + ", accessWith = " + accessorTree + "]"; | |
3018 } | |
3019 | |
3020 } | |
3021 | |
3022 private abstract class SpecializationBody { | |
3023 | |
3024 private final boolean fastPath; | |
3025 private final boolean needsCastedValues; | |
3026 | |
3027 public SpecializationBody(boolean fastPath, boolean needsCastedValues) { | |
3028 this.fastPath = fastPath; | |
3029 this.needsCastedValues = needsCastedValues; | |
3030 } | |
3031 | |
3032 public final boolean isFastPath() { | |
3033 return fastPath; | |
3034 } | |
3035 | |
3036 public final boolean needsCastedValues() { | |
3037 return needsCastedValues; | |
3038 } | |
3039 | |
3040 public abstract CodeTree createBody(SpecializationData specialization, LocalContext currentValues); | |
3041 | |
3042 } | |
3043 | |
3044 } |