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 }