comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 18761:a665483c3881

Truffle-DSL: new node layout implementation.
author Christian Humer <christian.humer@gmail.com>
date Mon, 29 Dec 2014 23:38:54 +0100
parents
children a720bf2e2f43
comparison
equal deleted inserted replaced
18760:6fa3999631d8 18761:a665483c3881
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.internal.*;
39 import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization;
40 import com.oracle.truffle.api.dsl.internal.DSLOptions.TypeBoxingOptimization;
41 import com.oracle.truffle.api.frame.*;
42 import com.oracle.truffle.api.nodes.*;
43 import com.oracle.truffle.api.nodes.Node.Child;
44 import com.oracle.truffle.dsl.processor.*;
45 import com.oracle.truffle.dsl.processor.java.*;
46 import com.oracle.truffle.dsl.processor.java.model.*;
47 import com.oracle.truffle.dsl.processor.model.*;
48 import com.oracle.truffle.dsl.processor.parser.*;
49 import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard;
50
51 public class NodeGenFactory {
52
53 private static final String FRAME_VALUE = "frameValue";
54
55 private final ProcessorContext context;
56 private final NodeData node;
57 private final TypeSystemData typeSystem;
58 private final TypeData genericType;
59 private final DSLOptions options;
60
61 public NodeGenFactory(ProcessorContext context, NodeData node) {
62 this.context = context;
63 this.node = node;
64 this.typeSystem = node.getTypeSystem();
65 this.genericType = typeSystem.getGenericTypeData();
66 this.options = typeSystem.getOptions();
67 }
68
69 public static String nodeTypeName(NodeData node) {
70 return resolveNodeId(node) + "NodeGen";
71 }
72
73 private static String resolveNodeId(NodeData node) {
74 String nodeid = node.getNodeId();
75 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
76 nodeid = nodeid.substring(0, nodeid.length() - 4);
77 }
78 return nodeid;
79 }
80
81 public static TypeMirror nodeType(NodeData node) {
82 return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), nodeTypeName(node));
83 }
84
85 private static String specializationTypeName(SpecializationData specialization) {
86 return specialization.getId() + "Node";
87 }
88
89 private static TypeMirror specializationType(SpecializationData specialization) {
90 return new GeneratedTypeMirror(ElementUtils.getPackageName(specialization.getNode().getTemplateType()) + "." + nodeTypeName(specialization.getNode()), specializationTypeName(specialization));
91 }
92
93 private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) {
94 return execution.getName() + "Type_";
95 }
96
97 private static String nodeFieldName(NodeExecutionData execution) {
98 return execution.getName() + "_";
99 }
100
101 private static String specializationStartFieldName() {
102 return "specialization_";
103 }
104
105 private static String excludedFieldName(SpecializationData specialization) {
106 return "exclude" + specialization.getId() + "_";
107 }
108
109 private static String executeChildMethodName(NodeExecutionData execution, TypeData type) {
110 return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + "_";
111 }
112
113 private static CodeTree accessParent(String name) {
114 if (name == null) {
115 return CodeTreeBuilder.singleString("root");
116 } else {
117 return CodeTreeBuilder.createBuilder().string("root.").string(name).build();
118 }
119 }
120
121 private static String assumptionName(String assumption) {
122 return assumption + "_";
123 }
124
125 public CodeTypeElement create() {
126 String typeName = nodeTypeName(node);
127 TypeMirror baseType = node.getTemplateType().asType();
128 CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PUBLIC, FINAL), typeName, baseType);
129
130 clazz.getImplements().add(getType(SpecializedNode.class));
131
132 for (String assumption : node.getAssumptions()) {
133 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption)));
134 }
135
136 for (NodeChildData child : node.getChildren()) {
137 clazz.addOptional(createAccessChildMethod(child));
138 }
139
140 for (NodeFieldData field : node.getFields()) {
141 if (!field.isGenerated()) {
142 continue;
143 }
144
145 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), field.getType(), field.getName()));
146 if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) {
147 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), field.getGetter());
148 method.getModifiers().remove(Modifier.ABSTRACT);
149 method.createBuilder().startReturn().string("this.").string(field.getName()).end();
150 clazz.add(method);
151 }
152 }
153
154 List<? extends ExecutableElement> superConstructors = ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements());
155 for (ExecutableElement superConstructor : superConstructors) {
156 if (getVisibility(superConstructor.getModifiers()) == PRIVATE) {
157 continue;
158 }
159 if (superConstructors.size() > 1 && superConstructor.getParameters().size() > 0 &&
160 ElementUtils.typeEquals(superConstructor.getEnclosingElement().asType(), superConstructor.getParameters().get(0).asType())) {
161 // constructor is copy constructor
162 continue;
163 }
164 clazz.add(createNodeConstructor(clazz, superConstructor));
165 }
166
167 for (NodeExecutionData execution : node.getChildExecutions()) {
168 clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class));
169 }
170
171 for (NodeExecutionData execution : node.getChildExecutions()) {
172 if (findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) {
173 continue;
174 }
175 clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class));
176 }
177
178 for (SpecializationData specialization : node.getSpecializations()) {
179 if (mayBeExcluded(specialization)) {
180 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class));
181 }
182 }
183
184 clazz.add(createNodeField(PRIVATE, TypeSystemNodeFactory.nodeType(node.getTypeSystem()), specializationStartFieldName(), Child.class));
185 clazz.add(createMethodGetSpecializationNode());
186 clazz.add(createDeepCopyMethod());
187 clazz.add(createGetCostMethod());
188
189 Collection<TypeData> specializedTypes = node.findSpecializedReturnTypes();
190 for (ExecutableTypeData execType : node.getExecutableTypes()) {
191 if (shouldImplementExecutableType(specializedTypes, execType)) {
192 clazz.add(createExecutableTypeOverride(execType));
193 }
194 }
195
196 SpecializationData initialSpecialization = createSpecializations(clazz);
197
198 for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
199 CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder();
200 builder.startStatement();
201 builder.string("this.").string(specializationStartFieldName());
202 builder.string(" = ").tree(createCallCreateMethod(initialSpecialization, "this", null));
203 builder.end();
204 }
205
206 return clazz;
207 }
208
209 private CodeExecutableElement createNodeConstructor(CodeTypeElement clazz, ExecutableElement superConstructor) {
210 CodeExecutableElement constructor = GeneratorUtils.createConstructorUsingFields(modifiers(PUBLIC), clazz, superConstructor);
211
212 List<CodeVariableElement> childParameters = new ArrayList<>();
213 for (NodeChildData child : node.getChildren()) {
214 childParameters.add(new CodeVariableElement(child.getOriginalType(), child.getName()));
215 }
216 constructor.getParameters().addAll(superConstructor.getParameters().size(), childParameters);
217
218 CodeTreeBuilder builder = constructor.appendBuilder();
219 List<String> childValues = new ArrayList<>(node.getChildren().size());
220 for (NodeChildData child : node.getChildren()) {
221 String name = child.getName();
222 if (child.getCardinality().isMany()) {
223 CreateCastData createCast = node.findCast(child.getName());
224 if (createCast != null) {
225 CodeTree nameTree = CodeTreeBuilder.singleString(name);
226 CodeTreeBuilder callBuilder = builder.create();
227 callBuilder.string(name).string(" != null ? ");
228 callBuilder.tree(callTemplateMethod(builder, null, createCast, nameTree));
229 callBuilder.string(" : null");
230 name += "_";
231 builder.declaration(child.getNodeType(), name, callBuilder.build());
232 }
233 }
234 childValues.add(name);
235 }
236
237 for (NodeExecutionData execution : node.getChildExecutions()) {
238 CreateCastData createCast = node.findCast(execution.getChild().getName());
239
240 builder.startStatement();
241 builder.string("this.").string(nodeFieldName(execution)).string(" = ");
242
243 String name = childValues.get(node.getChildren().indexOf(execution.getChild()));
244 CodeTreeBuilder accessorBuilder = builder.create();
245 accessorBuilder.string(name);
246
247 if (execution.isIndexed()) {
248 accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]");
249 }
250
251 CodeTree accessor = accessorBuilder.build();
252
253 if (createCast != null && execution.getChild().getCardinality().isOne()) {
254 accessor = callTemplateMethod(builder, null, createCast, accessor);
255 }
256
257 if (execution.isIndexed()) {
258 CodeTreeBuilder nullCheck = builder.create();
259 nullCheck.string(name).string(" != null ? ");
260 nullCheck.tree(accessor);
261 nullCheck.string(" : null");
262 accessor = nullCheck.build();
263 }
264
265 builder.tree(accessor);
266
267 builder.end();
268 }
269
270 return constructor;
271 }
272
273 private static boolean mayBeExcluded(SpecializationData specialization) {
274 return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty();
275 }
276
277 private SpecializationData createSpecializations(CodeTypeElement clazz) {
278 List<SpecializationData> reachableSpecializations = getReachableSpecializations();
279
280 if (isSingleSpecializable(reachableSpecializations)) {
281 SpecializationData single = reachableSpecializations.get(0);
282 clazz.add(createSingleSpecialization(single));
283 return single;
284 } else {
285 CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization(clazz));
286 TypeMirror baseSpecializationType = baseSpecialization.asType();
287
288 Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>();
289
290 List<SpecializationData> generateSpecializations = new ArrayList<>();
291 generateSpecializations.add(node.getUninitializedSpecialization());
292 if (needsPolymorphic(reachableSpecializations)) {
293 generateSpecializations.add(node.getPolymorphicSpecialization());
294 }
295 generateSpecializations.addAll(reachableSpecializations);
296
297 for (SpecializationData specialization : generateSpecializations) {
298 generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType)));
299 }
300
301 baseSpecialization.addOptional(createCreateNext(generated));
302 baseSpecialization.addOptional(createCreateFallback(generated));
303 baseSpecialization.addOptional(createCreatePolymorphic(generated));
304
305 return node.getUninitializedSpecialization();
306 }
307 }
308
309 // create specialization
310
311 private CodeTypeElement createBaseSpecialization(CodeTypeElement parentClass) {
312 CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, STATIC, ABSTRACT), "BaseNode", TypeSystemNodeFactory.nodeType(typeSystem));
313
314 clazz.addOptional(createSpecializationConstructor(clazz, null, null));
315 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
316
317 clazz.addOptional(createUnsupported());
318 clazz.add(createGetSuppliedChildren());
319
320 int signatureSize = node.getSignatureSize();
321 Set<Integer> evaluatedCount = getEvaluatedCounts();
322 for (int evaluated : evaluatedCount) {
323 if (signatureSize != evaluated || signatureSize == 0) {
324 clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated));
325 }
326 }
327
328 for (NodeExecutionData execution : node.getChildExecutions()) {
329 Collection<TypeData> specializedTypes = node.findSpecializedTypes(execution);
330 specializedTypes.add(genericType);
331 for (TypeData specializedType : specializedTypes) {
332 if (isExecuteChildShared(execution, specializedType)) {
333 if (specializedType.isGeneric()) {
334 parentClass.add(createExecuteChildMethod(execution, specializedType));
335 } else {
336 clazz.add(createExecuteChildMethod(execution, specializedType));
337 }
338 }
339 }
340 }
341
342 return clazz;
343 }
344
345 private CodeTypeElement createSingleSpecialization(SpecializationData specialization) {
346 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), TypeSystemNodeFactory.nodeType(typeSystem));
347 CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, null, "0"));
348 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
349 TypeData returnType = specialization.getReturnType().getTypeSystemType();
350 Set<Integer> evaluatedCount = getEvaluatedCounts();
351 for (int evaluated : evaluatedCount) {
352 clazz.add(createFastPathExecuteMethod(specialization, null, evaluated));
353 }
354 if (isTypeBoxingEliminated(specialization)) {
355 clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
356 }
357 clazz.add(createFastPathWrapExecuteMethod(genericType, null));
358
359 clazz.addOptional(createUnsupported());
360 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor));
361 clazz.add(createGetSuppliedChildren());
362
363 return clazz;
364 }
365
366 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) {
367 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType);
368
369 CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null));
370
371 for (Parameter p : specialization.getSignatureParameters()) {
372 TypeData targetType = p.getTypeSystemType();
373 if (targetType.hasImplicitSourceTypes()) {
374 NodeExecutionData execution = p.getSpecification().getExecution();
375 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
376 if (implicitProfile != null) {
377 implicitProfile.getModifiers().add(PRIVATE);
378 implicitProfile.getModifiers().add(FINAL);
379 clazz.add(implicitProfile);
380 }
381 }
382 }
383
384 if (specialization.isFallback()) {
385 clazz.add(createFallbackGuardMethod());
386 }
387
388 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor));
389 clazz.addOptional(createMergeMethod(specialization));
390 clazz.addOptional(createIsSameMethod(specialization));
391
392 TypeData returnType = specialization.getReturnType().getTypeSystemType();
393 int signatureSize = specialization.getSignatureSize();
394
395 clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize));
396
397 if (isTypeBoxingEliminated(specialization)) {
398 clazz.add(createFastPathExecuteMethod(specialization, returnType, 0));
399
400 if (signatureSize > 0 && !returnType.isGeneric()) {
401 clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
402 }
403
404 ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0);
405 if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
406 clazz.add(createFastPathWrapVoidMethod(returnType));
407 }
408 }
409
410 return clazz;
411 }
412
413 private Element createDeepCopyMethod() {
414 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), getType(Node.class), "deepCopy");
415 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
416 CodeTreeBuilder builder = executable.createBuilder();
417 builder.startReturn().startStaticCall(getType(SpecializationNode.class), "updateRoot").string("super.deepCopy()").end().end();
418 return executable;
419 }
420
421 private Element createGetCostMethod() {
422 TypeMirror returnType = getType(NodeCost.class);
423 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost");
424 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
425 CodeTreeBuilder builder = executable.createBuilder();
426 builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end();
427 return executable;
428 }
429
430 private CodeExecutableElement createIsSameMethod(SpecializationData specialization) {
431 if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) {
432 return null;
433 }
434
435 List<CodeVariableElement> profiles = new ArrayList<>();
436 for (Parameter parameter : specialization.getSignatureParameters()) {
437 NodeExecutionData execution = parameter.getSpecification().getExecution();
438 if (execution == null) {
439 continue;
440 }
441 CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType());
442 if (var != null) {
443 profiles.add(var);
444 }
445 }
446
447 if (profiles.isEmpty()) {
448 return null;
449 }
450
451 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isSame");
452 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other"));
453 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
454 CodeTreeBuilder builder = method.createBuilder();
455
456 builder.startReturn();
457 builder.string("super.isSame(other)");
458
459 for (CodeVariableElement profile : profiles) {
460 builder.string(" && ");
461 builder.string("this.").string(profile.getName()).string(" == ").string("(").cast(specializationType(specialization)).string("other).").string(profile.getName());
462 }
463
464 builder.end();
465 return method;
466 }
467
468 private Element createMergeMethod(SpecializationData specialization) {
469 if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) {
470 return null;
471 }
472 TypeMirror specializationNodeType = getType(SpecializationNode.class);
473 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge");
474 executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode"));
475 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
476 CodeTreeBuilder builder = executable.createBuilder();
477
478 if (specialization.isPolymorphic()) {
479 builder.statement("return polymorphicMerge(newNode)");
480 } else {
481 boolean elseIf = false;
482 for (SpecializationData containedSpecialization : specialization.getExcludedBy()) {
483 elseIf = builder.startIf(elseIf);
484 builder.string("newNode.getClass() == ").typeLiteral(specializationType(containedSpecialization));
485 builder.end();
486 builder.startBlock();
487 builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")");
488 builder.end();
489 }
490 builder.statement("return super.merge(newNode)");
491 }
492
493 return executable;
494 }
495
496 private Element createFastPathWrapVoidMethod(TypeData wrap) {
497 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType()));
498 executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE));
499 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
500 CodeTreeBuilder builder = executable.createBuilder();
501 builder.startStatement();
502 builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap));
503 builder.string(FRAME_VALUE);
504 builder.end();
505 builder.end();
506
507 return executable;
508 }
509
510 private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) {
511 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override));
512 executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE));
513 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
514 CodeTreeBuilder builder = executable.createBuilder();
515 if (wrap != null) {
516 builder.startTryBlock();
517 }
518 builder.startReturn();
519 builder.startCall(TypeSystemNodeFactory.executeName(wrap));
520 builder.string(FRAME_VALUE);
521 builder.end();
522 builder.end();
523 if (wrap != null) {
524 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
525 builder.statement("return ex.getResult()");
526 builder.end();
527 }
528
529 return executable;
530 }
531
532 private boolean needsPolymorphic(List<SpecializationData> reachableSpecializations) {
533 if (reachableSpecializations.size() > 1) {
534 return true;
535 }
536 if (options.implicitCastOptimization().isDuplicateTail()) {
537 SpecializationData specialization = reachableSpecializations.get(0);
538 for (Parameter parameter : specialization.getSignatureParameters()) {
539 if (parameter.getTypeSystemType().hasImplicitSourceTypes()) {
540 return true;
541 }
542 }
543 }
544 return false;
545 }
546
547 private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) {
548 SpecializationData fallback = node.getGenericSpecialization();
549 if (fallback == null) {
550 return null;
551 }
552 CodeTypeElement generatedType = generatedSpecializationClasses.get(fallback);
553 if (generatedType == null) {
554 return null;
555 }
556
557 TypeMirror returnType = getType(SpecializationNode.class);
558 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createFallback");
559 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
560 method.createBuilder().startReturn().tree(createCallCreateMethod(fallback, null, null)).end();
561 return method;
562 }
563
564 private Element createCreatePolymorphic(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) {
565 SpecializationData polymorphic = node.getPolymorphicSpecialization();
566 CodeTypeElement generatedPolymorphic = generatedSpecializationClasses.get(polymorphic);
567 if (generatedPolymorphic == null) {
568 return null;
569 }
570 TypeMirror returnType = getType(SpecializationNode.class);
571 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createPolymorphic");
572 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
573 method.createBuilder().startReturn().tree(createCallCreateMethod(polymorphic, null, null)).end();
574 return method;
575 }
576
577 private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) {
578 final LocalContext locals = LocalContext.load(this);
579
580 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE);
581 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
582
583 CodeTreeBuilder builder = method.createBuilder();
584 SpecializationGroup group = createSpecializationGroups();
585 CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationExecution() {
586 public CodeTree createExecute(SpecializationData specialization, LocalContext values) {
587 CodeTypeElement generatedType = specializationClasses.get(specialization);
588 if (generatedType == null) {
589 throw new AssertionError("No generated type for " + specialization);
590 }
591 return createSlowPathExecute(specialization, locals);
592 }
593
594 public boolean isFastPath() {
595 return false;
596 }
597 });
598
599 builder.tree(execution);
600
601 if (hasFallthrough(group, genericType, locals, false)) {
602 builder.returnNull();
603 }
604 return method;
605 }
606
607 private CodeExecutableElement createFallbackGuardMethod() {
608 boolean frameUsed = node.isFrameUsedByAnyGuard(context);
609 LocalContext locals = LocalContext.load(this);
610
611 if (!frameUsed) {
612 locals.removeValue(FRAME_VALUE);
613 }
614
615 CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE);
616 if (!frameUsed) {
617 boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class)));
618 }
619
620 CodeTreeBuilder builder = boundaryMethod.createBuilder();
621 builder.startReturn();
622 builder.startCall("createNext");
623 locals.addReferencesTo(builder, FRAME_VALUE);
624 builder.end();
625 builder.string(" == null");
626 builder.end();
627 return boundaryMethod;
628 }
629
630 private ExecutableElement createAccessChildMethod(NodeChildData child) {
631 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) {
632 ExecutableElement getter = (ExecutableElement) child.getAccessElement();
633 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), getter);
634 method.getModifiers().remove(Modifier.ABSTRACT);
635
636 List<NodeExecutionData> executions = new ArrayList<>();
637 for (NodeExecutionData execution : node.getChildExecutions()) {
638 if (execution.getChild() == child) {
639 executions.add(execution);
640 }
641 }
642
643 CodeTreeBuilder builder = method.createBuilder();
644 if (child.getCardinality().isMany()) {
645 builder.startReturn().startNewArray((ArrayType) child.getOriginalType(), null);
646 for (NodeExecutionData execution : executions) {
647 builder.string(nodeFieldName(execution));
648 }
649 builder.end().end();
650 } else {
651 for (NodeExecutionData execution : executions) {
652 builder.startReturn().string("this.").string(nodeFieldName(execution)).end();
653 break;
654 }
655 }
656 return method;
657 }
658 return null;
659 }
660
661 private boolean isTypeBoxingEliminated(SpecializationData specialization) {
662 if (specialization.getMethod() == null) {
663 return false;
664 }
665
666 TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization();
667 if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) {
668 return true;
669 }
670 for (Parameter p : specialization.getSignatureParameters()) {
671 if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) {
672 return true;
673 }
674 }
675 return false;
676
677 }
678
679 private Set<Integer> getEvaluatedCounts() {
680 Set<Integer> evaluatedCount = new TreeSet<>();
681 Collection<TypeData> returnSpecializedTypes = node.findSpecializedReturnTypes();
682 for (ExecutableTypeData execType : node.getExecutableTypes()) {
683 if (shouldImplementExecutableType(returnSpecializedTypes, execType)) {
684 evaluatedCount.add(execType.getEvaluatedCount());
685 }
686 }
687 return evaluatedCount;
688 }
689
690 // create specialization
691
692 private Element createUnsupported() {
693 SpecializationData fallback = node.getGenericSpecialization();
694 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
695 return null;
696 }
697 LocalContext locals = LocalContext.load(this);
698
699 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE);
700 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
701
702 CodeTreeBuilder builder = method.createBuilder();
703 builder.startReturn();
704 builder.tree(callTemplateMethod(builder, accessParent(null), fallback, locals));
705 builder.end();
706
707 return method;
708 }
709
710 private boolean isSingleSpecializable(List<SpecializationData> reachableSpecializations) {
711 if (reachableSpecializations.size() != 1) {
712 return false;
713 }
714 return !reachableSpecializations.get(0).hasRewrite(context);
715 }
716
717 private List<SpecializationData> getReachableSpecializations() {
718 List<SpecializationData> specializations = new ArrayList<>();
719 for (SpecializationData specialization : node.getSpecializations()) {
720 if (specialization.isReachable() && //
721 (specialization.isSpecialized() //
722 || (specialization.isFallback() && optimizeFallback(specialization)))) {
723 specializations.add(specialization);
724 }
725 }
726 return specializations;
727 }
728
729 private boolean optimizeFallback(SpecializationData specialization) {
730 switch (options.optimizeFallback()) {
731 case NEVER:
732 return false;
733 case DECLARED:
734 return specialization.getMethod() != null;
735 case ALWAYS:
736 return true;
737 default:
738 throw new AssertionError();
739 }
740 }
741
742 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) {
743 final String varArgsName = "args";
744 final TypeData returnType = execType.getType();
745 final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType;
746
747 CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName);
748
749 LocalContext locals = LocalContext.load(this, execType.getSignatureSize());
750
751 // rename varargs parameter
752 int signatureIndex = 0;
753 for (Parameter parameter : execType.getSignatureParameters()) {
754 if (parameter.isTypeVarArgs()) {
755 String newName = varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]";
756 NodeExecutionData execution = node.getChildExecutions().get(signatureIndex);
757 locals.setValue(execution, locals.getValue(execution).accessWith(CodeTreeBuilder.singleString(newName)));
758 }
759 signatureIndex++;
760 }
761
762 CodeTreeBuilder builder = method.createBuilder();
763
764 // create acceptAndExecute
765 CodeTreeBuilder executeBuilder = builder.create();
766 executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType));
767 Parameter frame = execType.getFrame();
768 if (frame == null) {
769 executeBuilder.nullLiteral();
770 } else {
771 executeBuilder.string(frame.getLocalName());
772 }
773 locals.addReferencesTo(executeBuilder);
774 executeBuilder.end();
775
776 CodeTreeBuilder contentBuilder = builder.create();
777 contentBuilder.startReturn();
778 contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build()));
779 contentBuilder.end();
780
781 // try catch assert if unexpected value is not expected
782 if (!execType.hasUnexpectedValue(context) && !returnType.isGeneric() && !returnType.isVoid()) {
783 builder.startTryBlock();
784 builder.tree(contentBuilder.build());
785 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
786 builder.startThrow().startNew(getType(AssertionError.class)).end().end();
787 builder.end();
788 } else {
789 builder.tree(contentBuilder.build());
790 }
791
792 return method;
793 }
794
795 private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError {
796 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod());
797
798 method.getAnnotationMirrors().clear();
799 method.getModifiers().remove(Modifier.ABSTRACT);
800
801 if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) {
802 throw new AssertionError("Should be verified in the parser");
803 }
804
805 // align argument names
806 int index = 0;
807 for (Parameter parameter : execType.getParameters()) {
808 CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index);
809 if (parameter.isTypeVarArgs()) {
810 var.getAnnotationMirrors().clear();
811 var.setName(varArgsName);
812 break;
813 }
814 var.setName(LocalVariable.fromParameter(parameter).createParameter().getName());
815 var.getAnnotationMirrors().clear();
816 index++;
817 }
818 return method;
819 }
820
821 private boolean shouldImplementExecutableType(Collection<TypeData> specializedTypes, ExecutableTypeData execType) {
822 TypeData type = execType.getType();
823 Set<Modifier> modifiers = execType.getMethod().getModifiers();
824 if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) {
825 return false;
826 } else if (execType.isAbstract()) {
827 return true;
828 } else if (type.isGeneric()) {
829 return true;
830 } else if (type.isVoid()) {
831 for (TypeData specializedType : specializedTypes) {
832 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) {
833 return true;
834 }
835 }
836 return false;
837 } else if (!specializedTypes.contains(type)) {
838 return false;
839 } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) {
840 return false;
841 }
842 return true;
843 }
844
845 private Element createMethodGetSpecializationNode() {
846 TypeMirror returntype = getType(SpecializationNode.class);
847 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode");
848 method.createBuilder().startReturn().string(specializationStartFieldName()).end();
849 return method;
850 }
851
852 private TypeMirror getType(Class<?> clazz) {
853 return context.getType(clazz);
854 }
855
856 private CodeVariableElement createNodeField(Modifier visibility, TypeMirror type, String name, Class<?> annotationType) {
857 CodeVariableElement childField = new CodeVariableElement(modifiers(), type, name);
858 childField.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(annotationType)));
859 setVisibility(childField.getModifiers(), visibility);
860 return childField;
861 }
862
863 private static List<ExecutableTypeData> findSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) {
864 if (optimization == TypeBoxingOptimization.NONE) {
865 return Collections.emptyList();
866 }
867
868 List<ExecutableTypeData> executables = new ArrayList<>();
869 for (TypeData type : types) {
870 if (!isTypeBoxingOptimized(optimization, type)) {
871 continue;
872 }
873 ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size());
874 if (foundType != null) {
875 executables.add(foundType);
876 }
877 }
878 return executables;
879 }
880
881 private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, CodeTree... boundValues) {
882 CodeTreeBuilder builder = parent.create();
883 if (method.getMethod().getModifiers().contains(STATIC)) {
884 builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName());
885 } else {
886 builder.startCall(receiver, method.getMethodName());
887 }
888 int index = -1;
889 for (Parameter parameter : method.getParameters()) {
890 index++;
891 if (index < boundValues.length) {
892 CodeTree tree = boundValues[index];
893 if (tree != null) {
894 builder.tree(tree);
895 continue;
896 }
897 }
898 builder.string(parameter.getLocalName());
899 }
900 builder.end();
901 return builder.build();
902 }
903
904 private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
905 CodeTree[] bindings = new CodeTree[method.getParameters().size()];
906
907 int signatureIndex = 0;
908 for (int i = 0; i < bindings.length; i++) {
909 Parameter parameter = method.getParameters().get(i);
910 LocalVariable var = currentValues.get(parameter, signatureIndex);
911 if (var != null) {
912 CodeTree valueReference = bindings[i] = var.createReference();
913 if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) {
914 valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference);
915 }
916 bindings[i] = valueReference;
917 }
918 if (parameter.getSpecification().isSignature()) {
919 signatureIndex++;
920 }
921 }
922 return callTemplateMethod(parent, receiver, method, bindings);
923 }
924
925 private SpecializationGroup createSpecializationGroups() {
926 return SpecializationGroup.create(getReachableSpecializations());
927 }
928
929 private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) {
930 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
931 if (specialization.isFallback()) {
932 return builder.returnNull().build();
933 }
934 if (node.isFrameUsedByAnyGuard(context)) {
935 builder.tree(createTransferToInterpreterAndInvalidate());
936 }
937 for (SpecializationData otherSpeciailzation : node.getSpecializations()) {
938 if (otherSpeciailzation == specialization) {
939 continue;
940 }
941 if (otherSpeciailzation.getExcludedBy().contains(specialization)) {
942 builder.startStatement();
943 builder.tree(accessParent(excludedFieldName(otherSpeciailzation)));
944 builder.string(" = true");
945 builder.end();
946 }
947 }
948
949 builder.startReturn().tree(createCallCreateMethod(specialization, null, currentValues)).end();
950
951 if (mayBeExcluded(specialization)) {
952 CodeTreeBuilder checkHasSeenBuilder = builder.create();
953 checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock();
954 checkHasSeenBuilder.tree(builder.build());
955 checkHasSeenBuilder.end();
956 return checkHasSeenBuilder.build();
957 }
958 return builder.build();
959 }
960
961 private static boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath) {
962 for (TypeGuard guard : group.getTypeGuards()) {
963 if (currentValues.getValue(guard.getSignatureIndex()) == null) {
964 // not evaluated
965 return true;
966 }
967 LocalVariable value = currentValues.getValue(guard.getSignatureIndex());
968 if (value.getType().needsCastTo(guard.getType())) {
969 return true;
970 }
971 }
972
973 List<GuardExpression> expressions = new ArrayList<>(group.getGuards());
974 expressions.removeAll(group.findElseConnectableGuards());
975 if (!expressions.isEmpty()) {
976 return true;
977 }
978
979 if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) {
980 return true;
981 }
982
983 if (!fastPath && group.getSpecialization() != null && !group.getSpecialization().getExceptions().isEmpty()) {
984 return true;
985 }
986
987 if (!group.getChildren().isEmpty()) {
988 return hasFallthrough(group.getChildren().get(group.getChildren().size() - 1), forType, currentValues, fastPath);
989 }
990
991 return false;
992 }
993
994 private Element createGetSuppliedChildren() {
995 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class));
996
997 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), nodeArray, "getSuppliedChildren");
998 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
999
1000 CodeTreeBuilder builder = method.createBuilder();
1001
1002 builder.startReturn().startNewArray(nodeArray, null);
1003 for (int i = 0; i < node.getChildExecutions().size(); i++) {
1004 NodeExecutionData execution = node.getChildExecutions().get(i);
1005 if (execution.isShortCircuit()) {
1006 builder.nullLiteral();
1007 }
1008 builder.tree(accessParent(nodeFieldName(execution)));
1009 }
1010 builder.end().end();
1011
1012 return method;
1013 }
1014
1015 // create specialization
1016
1017 private CodeTree createCallCreateMethod(SpecializationData specialization, String rootName, LocalContext currentValues) {
1018 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1019
1020 TypeMirror specializationType = specializationType(specialization);
1021 if (options.useLazyClassLoading()) {
1022 builder.startStaticCall(specializationType(specialization), "create");
1023 } else {
1024 builder.startNew(specializationType);
1025 }
1026 if (rootName != null) {
1027 builder.string(rootName);
1028 } else {
1029 builder.string("root");
1030 }
1031 if (currentValues != null) {
1032 for (Parameter p : specialization.getSignatureParameters()) {
1033 LocalVariable local = currentValues.get(p.getLocalName());
1034 CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType());
1035 if (var != null) {
1036 builder.tree(local.createReference());
1037 }
1038 }
1039 }
1040 builder.end();
1041
1042 return builder.build();
1043 }
1044
1045 private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) {
1046 if (!options.useLazyClassLoading()) {
1047 return null;
1048 }
1049
1050 CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor);
1051
1052 TypeMirror specializationType = specializationType(specialization);
1053
1054 executable.setReturnType(TypeSystemNodeFactory.nodeType(typeSystem));
1055 executable.setSimpleName(CodeNames.of("create"));
1056 executable.getModifiers().add(STATIC);
1057
1058 CodeTreeBuilder builder = executable.createBuilder();
1059 builder.startReturn().startNew(specializationType);
1060 for (VariableElement parameter : executable.getParameters()) {
1061 builder.string(parameter.getSimpleName().toString());
1062 }
1063 builder.end().end();
1064 return executable;
1065 }
1066
1067 private static String implicitClassFieldName(NodeExecutionData execution) {
1068 return execution.getName() + "ImplicitType";
1069 }
1070
1071 private static String implicitNodeFieldName(NodeExecutionData execution) {
1072 return execution.getName() + "Cast";
1073 }
1074
1075 private CodeExecutableElement createSpecializationConstructor(CodeTypeElement clazz, SpecializationData specialization, String constantIndex) {
1076 CodeExecutableElement constructor = new CodeExecutableElement(modifiers(), null, clazz.getSimpleName().toString());
1077
1078 constructor.addParameter(new CodeVariableElement(nodeType(node), "root"));
1079 CodeTreeBuilder builder = constructor.createBuilder();
1080
1081 if (specialization == null) {
1082 if (constantIndex == null) {
1083 builder.statement("super(index)");
1084 constructor.addParameter(new CodeVariableElement(getType(int.class), "index"));
1085 } else {
1086 builder.startStatement().startSuperCall().string(constantIndex).end().end();
1087 }
1088 builder.statement("this.root = root");
1089 } else {
1090 int index = resolveSpecializationIndex(specialization);
1091 builder.startStatement().startSuperCall().string("root").string(String.valueOf(index)).end().end();
1092
1093 for (Parameter p : specialization.getSignatureParameters()) {
1094 NodeExecutionData execution = p.getSpecification().getExecution();
1095
1096 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType());
1097 if (implicitProfile != null) {
1098 LocalVariable var = LocalVariable.fromParameter(p).makeGeneric();
1099
1100 String implicitFieldName = implicitProfile.getName();
1101 if (options.implicitCastOptimization().isDuplicateTail()) {
1102 constructor.addParameter(var.createParameter());
1103 CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference());
1104 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end();
1105 } else if (options.implicitCastOptimization().isMergeCasts()) {
1106 // use node that supports polymorphism
1107 constructor.addParameter(var.createParameter());
1108 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end();
1109 } else {
1110 throw new AssertionError();
1111 }
1112 }
1113 }
1114 }
1115
1116 if (constructor.getParameters().isEmpty()) {
1117 // do not generate default constructor
1118 return null;
1119 }
1120 return constructor;
1121 }
1122
1123 // TODO this logic can be inlined to the parser as soon as the old NodeGen layout is gone
1124 private static int resolveSpecializationIndex(SpecializationData specialization) {
1125 if (specialization.isFallback()) {
1126 return Integer.MAX_VALUE - 1;
1127 } else if (specialization.isUninitialized()) {
1128 return Integer.MAX_VALUE;
1129 } else if (specialization.isPolymorphic()) {
1130 return 0;
1131 } else {
1132 return specialization.getIndex();
1133 }
1134 }
1135
1136 private CodeTree createCallNext(TypeData forType, LocalContext currentValues) {
1137 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1138 builder.startCall("next", TypeSystemNodeFactory.executeName(null));
1139 currentValues.addReferencesTo(builder, FRAME_VALUE);
1140 builder.end();
1141 return TypeSystemCodeGenerator.expect(genericType, forType, builder.build());
1142 }
1143
1144 private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) {
1145 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1146 builder.startCall(methodName);
1147 if (reason != null) {
1148 builder.doubleQuote(reason);
1149 }
1150 currentValues.addReferencesTo(builder, FRAME_VALUE);
1151 builder.end();
1152
1153 TypeData executedType = forType.getTypeSystem().getGenericTypeData();
1154 return TypeSystemCodeGenerator.expect(executedType, forType, builder.build());
1155 }
1156
1157 private static ExecutableTypeData findSpecializedExecutableType(NodeExecutionData execution, TypeData type) {
1158 NodeChildData child = execution.getChild();
1159 int executeWithCount = child.getExecuteWith().size();
1160 return child.getNodeData().findExecutableType(type, executeWithCount);
1161 }
1162
1163 private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) {
1164 if (type.isGeneric() || type.isVoid()) {
1165 return false;
1166 }
1167 List<ExecutableTypeData> executableTypes = new ArrayList<>();
1168 executableTypes.add(findSpecializedExecutableType(execution, type));
1169
1170 if (!options.implicitCastOptimization().isNone()) {
1171 executableTypes.addAll(findSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()));
1172 }
1173
1174 for (ExecutableTypeData executableType : executableTypes) {
1175 if (executableType != null && executableType.hasUnexpectedValue(context)) {
1176 return true;
1177 }
1178 }
1179 return false;
1180 }
1181
1182 private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) {
1183 TypeData type = forType == null ? genericType : forType;
1184 LocalContext currentLocals = LocalContext.load(this, evaluatedArguments);
1185
1186 CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE);
1187 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
1188
1189 if (!type.isGeneric()) {
1190 executable.getThrownTypes().add(getType(UnexpectedResultException.class));
1191 }
1192
1193 CodeTreeBuilder builder = executable.createBuilder();
1194
1195 for (NodeExecutionData execution : node.getChildExecutions()) {
1196 LocalVariable var = currentLocals.getValue(execution);
1197 if (var == null) {
1198 TypeData targetType;
1199 if (specialization == null) {
1200 targetType = genericType;
1201 } else {
1202 targetType = specialization.findParameterOrDie(execution).getTypeSystemType();
1203 }
1204 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals);
1205 LocalVariable value = currentLocals.createValue(execution, targetType).nextName();
1206 builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals));
1207 currentLocals.setValue(execution, value);
1208 }
1209 }
1210
1211 LocalContext originalValues = currentLocals.copy();
1212 if (specialization == null) {
1213 builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end();
1214 } else if (specialization.isPolymorphic()) {
1215 builder.startReturn().tree(createCallNext(type, currentLocals)).end();
1216 } else if (specialization.isUninitialized()) {
1217 builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end();
1218 } else {
1219 final TypeData type_ = type;
1220 SpecializationGroup group = SpecializationGroup.create(specialization);
1221 SpecializationExecution executionFactory = new SpecializationExecution() {
1222 public CodeTree createExecute(SpecializationData s, LocalContext values) {
1223 return createFastPathExecute(type_, s, values);
1224 }
1225
1226 public boolean isFastPath() {
1227 return true;
1228 }
1229 };
1230 builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory));
1231 if (hasFallthrough(group, type, originalValues, true) || group.getSpecialization().isFallback()) {
1232 builder.startReturn().tree(createCallNext(type, originalValues)).end();
1233 }
1234 }
1235
1236 return executable;
1237 }
1238
1239 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
1240 LocalVariable shortCircuit = null;
1241 SpecializationData resolvedSpecialization = specialization;
1242 if (specialization == null) {
1243 resolvedSpecialization = node.getGenericSpecialization();
1244 }
1245
1246 if (execution.isShortCircuit()) {
1247 ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
1248 CodeTree access = callTemplateMethod(CodeTreeBuilder.createBuilder(), accessParent(null), shortCircuitData, currentLocals);
1249 shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
1250 }
1251 return shortCircuit;
1252 }
1253
1254 private int calculateShortCircuitIndex(NodeExecutionData execution) {
1255 int shortCircuitIndex = 0;
1256 for (NodeExecutionData otherExectuion : node.getChildExecutions()) {
1257 if (otherExectuion.isShortCircuit()) {
1258 if (otherExectuion == execution) {
1259 break;
1260 }
1261 shortCircuitIndex++;
1262 }
1263 }
1264 return shortCircuitIndex;
1265 }
1266
1267 private CodeTree createFastPathExecute(final TypeData forType, SpecializationData specialization, LocalContext currentValues) {
1268 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1269 int ifCount = 0;
1270 if (specialization.isFallback()) {
1271 builder.startIf().startCall("guardFallback");
1272 if (node.isFrameUsedByAnyGuard(context)) {
1273 builder.string(FRAME_VALUE);
1274 }
1275 currentValues.addReferencesTo(builder);
1276
1277 builder.end();
1278 builder.end();
1279 builder.startBlock();
1280 ifCount++;
1281 }
1282 CodeTreeBuilder execute = builder.create();
1283 execute.startReturn();
1284 if (specialization.getMethod() == null) {
1285 execute.startCall("unsupported");
1286 currentValues.addReferencesTo(execute, FRAME_VALUE);
1287 execute.end();
1288 } else {
1289 execute.tree(callTemplateMethod(execute, accessParent(null), specialization, currentValues));
1290 }
1291 execute.end();
1292 builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build()));
1293
1294 builder.end(ifCount);
1295 return builder.build();
1296 }
1297
1298 private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationExecution execution) {
1299 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1300
1301 Set<TypeGuard> castGuards;
1302 if (execution.isFastPath()) {
1303 castGuards = null; // cast all
1304 } else {
1305 castGuards = new HashSet<>();
1306 for (TypeGuard castGuard : group.getTypeGuards()) {
1307 if (isTypeGuardUsedInAnyGuardBelow(group, currentValues, castGuard)) {
1308 castGuards.add(castGuard);
1309 }
1310 }
1311 }
1312 CodeTree[] checkAndCast = createTypeCheckAndCast(group.getTypeGuards(), castGuards, currentValues, execution);
1313 CodeTree check = checkAndCast[0];
1314 CodeTree cast = checkAndCast[1];
1315
1316 List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards();
1317 List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards());
1318 guardExpressions.removeAll(elseGuardExpressions);
1319 CodeTree methodGuards = createMethodGuardCheck(guardExpressions, currentValues);
1320
1321 if (!group.getAssumptions().isEmpty()) {
1322 if (execution.isFastPath() && !forType.isGeneric()) {
1323 cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues);
1324 } else {
1325 methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions());
1326 }
1327 }
1328
1329 int ifCount = 0;
1330 if (!check.isEmpty()) {
1331 builder.startIf();
1332 builder.tree(check).end();
1333 builder.startBlock();
1334 ifCount++;
1335 }
1336 if (!cast.isEmpty()) {
1337 builder.tree(cast);
1338 }
1339 boolean elseIf = !elseGuardExpressions.isEmpty();
1340 if (!methodGuards.isEmpty()) {
1341 builder.startIf(elseIf);
1342 builder.tree(methodGuards).end();
1343 builder.startBlock();
1344 ifCount++;
1345 } else if (elseIf) {
1346 builder.startElseBlock();
1347 ifCount++;
1348 }
1349
1350 boolean reachable = isReachableGroup(group, ifCount);
1351 if (reachable) {
1352 for (SpecializationGroup child : group.getChildren()) {
1353 builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution));
1354 }
1355 SpecializationData specialization = group.getSpecialization();
1356 if (specialization != null) {
1357 builder.tree(execution.createExecute(specialization, currentValues));
1358 }
1359 }
1360 builder.end(ifCount);
1361
1362 return builder.build();
1363 }
1364
1365 private static CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List<String> assumptions) {
1366 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1367
1368 builder.tree(methodGuards);
1369 String connect = methodGuards.isEmpty() ? "" : " && ";
1370 for (String assumption : assumptions) {
1371 builder.string(connect);
1372 builder.startCall(accessParent(assumptionName(assumption)), "isValid").end();
1373 connect = " && ";
1374 }
1375
1376 return builder.build();
1377 }
1378
1379 private CodeTree appendAssumptionFastPath(CodeTree casts, List<String> assumptions, TypeData forType, LocalContext currentValues) {
1380 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1381 builder.tree(casts);
1382 builder.startTryBlock();
1383 for (String assumption : assumptions) {
1384 builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end();
1385 }
1386 builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae");
1387 builder.startReturn().tree(createCallNext(forType, currentValues)).end();
1388 builder.end();
1389 return builder.build();
1390 }
1391
1392 private static boolean isReachableGroup(SpecializationGroup group, int ifCount) {
1393 if (ifCount != 0) {
1394 return true;
1395 }
1396 SpecializationGroup previous = group.getPreviousGroup();
1397 if (previous == null || previous.findElseConnectableGuards().isEmpty()) {
1398 return true;
1399 }
1400
1401 /*
1402 * Hacky else case. In this case the specialization is not reachable due to previous else
1403 * branch. This is only true if the minimum state is not checked.
1404 */
1405 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() &&
1406 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) {
1407 return false;
1408 }
1409
1410 return true;
1411 }
1412
1413 private boolean isTypeGuardUsedInAnyGuardBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) {
1414 NodeExecutionData execution = node.getChildExecutions().get(typeGuard.getSignatureIndex());
1415
1416 for (GuardExpression guard : group.getGuards()) {
1417 List<Parameter> guardParameters = guard.getResolvedGuard().findByExecutionData(execution);
1418 TypeData sourceType = currentValues.getValue(typeGuard.getSignatureIndex()).getType();
1419
1420 for (Parameter guardParameter : guardParameters) {
1421 if (sourceType.needsCastTo(guardParameter.getType())) {
1422 return true;
1423 }
1424 }
1425 }
1426
1427 for (SpecializationGroup child : group.getChildren()) {
1428 if (isTypeGuardUsedInAnyGuardBelow(child, currentValues, typeGuard)) {
1429 return true;
1430 }
1431 }
1432
1433 return false;
1434 }
1435
1436 private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) {
1437 LocalContext locals = LocalContext.load(this, 0);
1438
1439 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE);
1440 if (hasUnexpectedResult(execution, targetType)) {
1441 method.getThrownTypes().add(getType(UnexpectedResultException.class));
1442 }
1443
1444 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType);
1445 if (implicitProfile != null) {
1446 method.addParameter(implicitProfile);
1447 }
1448
1449 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) {
1450 NodeExecutionData executeWith = node.getChildExecutions().get(i);
1451 LocalVariable var = locals.createValue(executeWith, genericType);
1452 method.addParameter(var.createParameter());
1453 locals.setValue(executeWith, var);
1454 }
1455
1456 CodeTreeBuilder builder = method.createBuilder();
1457 CodeTree executeChild = createExecuteChild(execution, targetType, locals.createValue(execution, targetType), locals, true);
1458 if (executeChild.isSingleLine()) {
1459 builder.statement(executeChild);
1460 } else {
1461 builder.tree(executeChild);
1462 }
1463 return method;
1464 }
1465
1466 private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) {
1467 if (targetType.hasImplicitSourceTypes()) {
1468 switch (options.implicitCastOptimization()) {
1469 case NONE:
1470 return null;
1471 case DUPLICATE_TAIL:
1472 return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution));
1473 case MERGE_CASTS:
1474 return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution));
1475 }
1476 }
1477 return null;
1478 }
1479
1480 private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) {
1481 if (targetType.isVoid()) {
1482 return false;
1483 } else if (targetType.isGeneric()) {
1484 if (isSingleSpecializable(getReachableSpecializations())) {
1485 return false;
1486 }
1487 return findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1;
1488 } else {
1489 if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) {
1490 return false;
1491 }
1492 if (!targetType.hasImplicitSourceTypes()) {
1493 return false;
1494 }
1495
1496 int uses = 0;
1497 for (SpecializationData specialization : node.getSpecializations()) {
1498 List<Parameter> parameters = specialization.findByExecutionData(execution);
1499 for (Parameter parameter : parameters) {
1500 if (targetType.equals(parameter.getTypeSystemType())) {
1501 uses++;
1502 }
1503 }
1504 }
1505 if (uses > 1) {
1506 return findSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1;
1507 } else {
1508 return false;
1509 }
1510 }
1511 }
1512
1513 private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) {
1514 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1515 boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType());
1516
1517 CodeTree executeChild;
1518 if (isExecuteChildShared(execution, targetValue.getType())) {
1519 executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues);
1520 } else {
1521 executeChild = createExecuteChild(execution, targetValue.getType(), targetValue, currentValues, false);
1522 }
1523
1524 builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected));
1525 builder.end();
1526 if (hasUnexpected) {
1527 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
1528
1529 LocalContext slowPathValues = currentValues.copy();
1530 slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
1531 boolean found = false;
1532 for (NodeExecutionData otherExecution : node.getChildExecutions()) {
1533 if (found) {
1534 LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType);
1535 LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues);
1536 builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues));
1537 slowPathValues.setValue(otherExecution, childEvaluatedValue);
1538 } else {
1539 // skip forward already evaluated
1540 found = execution == otherExecution;
1541 }
1542 }
1543 builder.startReturn().tree(createCallNext(returnType, slowPathValues)).end();
1544 builder.end();
1545 }
1546
1547 if (shortCircuit != null) {
1548 currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null));
1549 }
1550 return createShortCircuit(targetValue, shortCircuit, builder.build());
1551 }
1552
1553 private static CodeTree createShortCircuit(LocalVariable targetValue, LocalVariable shortCircuitValue, CodeTree tryExecute) {
1554 if (shortCircuitValue == null) {
1555 return tryExecute;
1556 }
1557
1558 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1559
1560 builder.tree(shortCircuitValue.createDeclaration(shortCircuitValue.createReference()));
1561 builder.tree(targetValue.createDeclaration(builder.create().defaultValue(targetValue.getTypeMirror()).build()));
1562
1563 builder.startIf().string(shortCircuitValue.getName()).end().startBlock();
1564 builder.tree(tryExecute);
1565 builder.end();
1566
1567 return builder.build();
1568 }
1569
1570 private static CodeTree createTryExecuteChild(LocalVariable value, CodeTree executeChild, boolean needDeclaration, boolean hasTry) {
1571 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1572 boolean hasDeclaration = false;
1573 if ((hasTry || !executeChild.isSingleLine()) && needDeclaration) {
1574 builder.tree(value.createDeclaration(null));
1575 hasDeclaration = true;
1576 }
1577
1578 if (hasTry) {
1579 builder.startTryBlock();
1580 } else {
1581 builder.startGroup();
1582 }
1583
1584 if (executeChild.isSingleLine()) {
1585 builder.startStatement();
1586 if (hasDeclaration || !needDeclaration) {
1587 builder.tree(executeChild);
1588 } else {
1589 builder.type(value.getTypeMirror()).string(" ").tree(executeChild);
1590 }
1591 builder.end();
1592 } else {
1593 builder.tree(executeChild);
1594 }
1595
1596 builder.end();
1597
1598 return builder.build();
1599 }
1600
1601 private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) {
1602 if (!isExecuteChildShared(execution, targetValue.getType())) {
1603 throw new AssertionError("Execute child not shared with method but called.");
1604 }
1605
1606 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1607 builder.tree(targetValue.createReference()).string(" = ");
1608 if (targetValue.getType().isGeneric()) {
1609 builder.startCall("root", executeChildMethodName(execution, targetValue.getType()));
1610 } else {
1611 builder.startCall(executeChildMethodName(execution, targetValue.getType()));
1612 }
1613 builder.string(FRAME_VALUE);
1614
1615 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType());
1616 if (implicitProfile != null) {
1617 builder.string(implicitProfile.getName());
1618 }
1619 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) {
1620 builder.tree(currentValues.getValue(i).createReference());
1621 }
1622 builder.end();
1623 return builder.build();
1624 }
1625
1626 private CodeTree createExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable target, LocalContext currentValues, boolean shared) {
1627 final CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1628 final ExecutableTypeData executableType = findSpecializedExecutableType(execution, target.getType());
1629
1630 CodeTree assignment = createAssignmentStart(target, shared, false);
1631
1632 if (executableType == null) {
1633 if (target.getType().isGeneric()) {
1634 throw new AssertionError("Should be caught by the parser.");
1635 }
1636 CodeTree genericExecute = createExecuteChild(execution, returnType, target.makeGeneric(), currentValues, shared);
1637 builder.tree(genericExecute);
1638 } else {
1639 if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) {
1640 return createPolymorphicExecuteChild(execution, target, currentValues, shared);
1641 } else if (target.getType().hasImplicitSourceTypes()) {
1642 if (options.implicitCastOptimization().isNone()) {
1643 CodeTree execute = createCallSharedExecuteChild(execution, target.makeGeneric(), currentValues);
1644 return TypeSystemCodeGenerator.implicitExpect(target.getType(), execute, null);
1645 } else if (options.implicitCastOptimization().isDuplicateTail()) {
1646 builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues));
1647 } else if (options.implicitCastOptimization().isMergeCasts()) {
1648 // TODO
1649 } else {
1650 throw new AssertionError();
1651 }
1652 } else {
1653 builder.tree(assignment);
1654
1655 CodeTree accessChild;
1656 if (shared && target.getType().isGeneric()) {
1657 accessChild = CodeTreeBuilder.singleString(nodeFieldName(execution));
1658 } else {
1659 accessChild = accessParent(nodeFieldName(execution));
1660 }
1661
1662 CodeTree execute = callTemplateMethod(builder, accessChild, executableType, currentValues);
1663 CodeTree expect = TypeSystemCodeGenerator.expect(executableType.getType(), returnType, execute);
1664 builder.tree(expect);
1665 }
1666 }
1667 return builder.build();
1668 }
1669
1670 private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError {
1671 ExecutableTypeData genericExecutableType = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size());
1672 if (genericExecutableType == null) {
1673 throw new AssertionError("error should be caught by the parser");
1674 }
1675
1676 CodeTree assignment = createAssignmentStart(target, shared, true);
1677
1678 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1679 CodeTreeBuilder polyChainBuilder = builder.create();
1680 boolean hasUnexpectedResult = false;
1681
1682 Set<TypeData> specializedTypes = new HashSet<>();
1683 for (TypeData type : node.findSpecializedTypes(execution)) {
1684 specializedTypes.addAll(type.getImplicitSourceTypes());
1685 }
1686
1687 List<ExecutableTypeData> specializedExecutables = findSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination());
1688
1689 Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() {
1690 public int compare(ExecutableTypeData o1, ExecutableTypeData o2) {
1691 return o1.getType().compareTo(o2.getType());
1692 }
1693 });
1694
1695 if (isSingleSpecializable(getReachableSpecializations())) {
1696 specializedExecutables = Collections.emptyList();
1697 }
1698
1699 boolean hasSpecializedTypes = false;
1700 for (ExecutableTypeData executableType : specializedExecutables) {
1701 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
1702 polyChainBuilder.tree(createAccessPolymorphicField(execution, shared));
1703 polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType());
1704 polyChainBuilder.end();
1705 polyChainBuilder.startBlock();
1706 polyChainBuilder.startStatement();
1707 polyChainBuilder.tree(assignment);
1708 polyChainBuilder.tree(callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), executableType, currentValues)).end();
1709 polyChainBuilder.end();
1710 hasUnexpectedResult |= executableType.hasUnexpectedValue(context);
1711 }
1712
1713 CodeTree executeGeneric = callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), genericExecutableType, currentValues);
1714
1715 if (specializedExecutables.isEmpty()) {
1716 builder.tree(assignment);
1717 builder.tree(executeGeneric);
1718 } else {
1719 CodeTree accessPolymorphicProfile = createAccessPolymorphicField(execution, shared);
1720 polyChainBuilder.startElseIf().tree(accessPolymorphicProfile).string(" == null").end();
1721 polyChainBuilder.startBlock();
1722 polyChainBuilder.tree(createTransferToInterpreterAndInvalidate());
1723 polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), "value_", executeGeneric);
1724
1725 hasSpecializedTypes = false;
1726 for (ExecutableTypeData executableType : specializedExecutables) {
1727 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes);
1728 polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString("value_")));
1729 polyChainBuilder.end();
1730 polyChainBuilder.startBlock();
1731 polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end();
1732 polyChainBuilder.end();
1733 }
1734
1735 polyChainBuilder.startElseBlock();
1736 polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
1737 polyChainBuilder.end();
1738
1739 polyChainBuilder.startReturn().string("value_").end();
1740
1741 polyChainBuilder.end();
1742 polyChainBuilder.startElseBlock();
1743 polyChainBuilder.startStatement().tree(assignment).tree(executeGeneric).end();
1744 polyChainBuilder.end();
1745
1746 if (hasUnexpectedResult) {
1747 builder.startTryBlock();
1748 }
1749
1750 builder.tree(polyChainBuilder.build());
1751
1752 if (hasUnexpectedResult) {
1753 builder.end();
1754 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
1755 builder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end();
1756 builder.startReturn().string("ex.getResult()").end();
1757 builder.end();
1758 }
1759 }
1760 return builder.build();
1761 }
1762
1763 private static CodeTree createAssignmentStart(LocalVariable target, boolean shared, boolean accessParent) {
1764 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1765 if (shared) {
1766 builder.string("return ");
1767 } else {
1768 builder.string(target.getName()).string(" = ");
1769 if (accessParent) {
1770 builder.tree(accessParent(null)).string(".");
1771 }
1772 }
1773 return builder.build();
1774 }
1775
1776 private static CodeTree createAccessPolymorphicField(NodeExecutionData execution, boolean shared) {
1777 String name = polymorphicTypeProfileFieldName(execution);
1778 if (shared) {
1779 return CodeTreeBuilder.singleString(name);
1780 } else {
1781 return accessParent(name);
1782 }
1783 }
1784
1785 private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) {
1786 CodeTreeBuilder builder = parent.create();
1787 List<TypeData> sourceTypes = target.getType().getImplicitSourceTypes();
1788 String implicitClassFieldName = implicitClassFieldName(execution);
1789 String nodeFieldName = nodeFieldName(execution);
1790 List<ExecutableTypeData> executableTypes = findSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization());
1791
1792 boolean elseIf = false;
1793 for (ExecutableTypeData executableType : executableTypes) {
1794 elseIf = builder.startIf(elseIf);
1795 builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getBoxedType());
1796 builder.end();
1797 builder.startBlock();
1798 builder.startStatement().tree(assignment);
1799
1800 CodeTree execute = callTemplateMethod(builder, accessParent(nodeFieldName), executableType, currentValues);
1801 ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType());
1802 if (cast != null) {
1803 execute = callTemplateMethod(builder, null, cast, execute);
1804 }
1805 builder.tree(execute);
1806 builder.end();
1807 builder.end();
1808 }
1809
1810 if (!executableTypes.isEmpty()) {
1811 builder.startElseBlock();
1812 }
1813
1814 LocalVariable genericValue = target.makeGeneric().nextName();
1815 LocalVariable genericShortCircuit = resolveShortCircuit(null, execution, currentValues);
1816
1817 builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, genericShortCircuit, currentValues));
1818 if (executableTypes.size() == sourceTypes.size()) {
1819 builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end();
1820 } else {
1821 builder.startStatement().tree(assignment);
1822 builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName));
1823 builder.end();
1824 }
1825
1826 if (!executableTypes.isEmpty()) {
1827 builder.end();
1828 }
1829 return builder.build();
1830 }
1831
1832 private static CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) {
1833 if (specialization.getExceptions().isEmpty()) {
1834 return execution;
1835 }
1836 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1837 builder.startTryBlock();
1838 builder.tree(execution);
1839 TypeMirror[] exceptionTypes = new TypeMirror[specialization.getExceptions().size()];
1840 for (int i = 0; i < exceptionTypes.length; i++) {
1841 exceptionTypes[i] = specialization.getExceptions().get(i).getJavaClass();
1842 }
1843 builder.end().startCatchBlock(exceptionTypes, "ex");
1844 builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end();
1845 builder.startReturn();
1846 builder.tree(createCallDelegate("remove", "threw rewrite exception", forType, currentValues));
1847 builder.end();
1848 builder.end();
1849 return builder.build();
1850 }
1851
1852 private static CodeTree createMethodGuardCheck(List<GuardExpression> guardExpressions, LocalContext currentValues) {
1853 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1854 String and = "";
1855 for (GuardExpression guard : guardExpressions) {
1856 builder.string(and);
1857 if (guard.isNegated()) {
1858 builder.string("!");
1859 }
1860 builder.tree(callTemplateMethod(builder, accessParent(null), guard.getResolvedGuard(), currentValues));
1861 and = " && ";
1862 }
1863 return builder.build();
1864 }
1865
1866 private CodeTree[] createTypeCheckAndCast(List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) {
1867 CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder();
1868 CodeTreeBuilder castsBuilder = CodeTreeBuilder.createBuilder();
1869 for (TypeGuard typeGuard : typeGuards) {
1870 int signatureIndex = typeGuard.getSignatureIndex();
1871 LocalVariable value = currentValues.getValue(signatureIndex);
1872 TypeData targetType = typeGuard.getType();
1873 if (!value.getType().needsCastTo(targetType)) {
1874 continue;
1875 }
1876 NodeExecutionData execution = node.getChildExecutions().get(signatureIndex);
1877 if (!checksBuilder.isEmpty()) {
1878 checksBuilder.string(" && ");
1879 }
1880
1881 CodeTreeBuilder checkBuilder = checksBuilder.create();
1882 CodeTreeBuilder castBuilder = checksBuilder.create();
1883
1884 LocalVariable shortCircuit = currentValues.getShortCircuit(execution);
1885 if (shortCircuit != null) {
1886 checkBuilder.string("(");
1887 CodeTreeBuilder referenceBuilder = checkBuilder.create();
1888 if (!shortCircuit.getType().isPrimitive()) {
1889 referenceBuilder.string("(boolean) ");
1890 }
1891 referenceBuilder.tree(shortCircuit.createReference());
1892 checkBuilder.string("!").tree(referenceBuilder.build());
1893 checkBuilder.string(" || ");
1894 castBuilder.tree(referenceBuilder.build()).string(" ? ");
1895 }
1896
1897 List<ImplicitCastData> sourceTypes = typeSystem.lookupByTargetType(targetType);
1898 CodeTree valueReference = value.createReference();
1899 if (sourceTypes.isEmpty()) {
1900 checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference()));
1901 castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference));
1902 } else {
1903 ImplicitCastOptimization opt = options.implicitCastOptimization();
1904 if (specializationExecution.isFastPath() && !opt.isNone()) {
1905 if (opt.isDuplicateTail()) {
1906 String typeHintField = implicitClassFieldName(execution);
1907 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField));
1908 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField));
1909 } else if (opt.isMergeCasts()) {
1910 checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference));
1911 castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference));
1912 } else {
1913 throw new AssertionError("implicit cast opt");
1914 }
1915 } else {
1916 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null));
1917 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null));
1918 }
1919 }
1920
1921 if (shortCircuit != null) {
1922 checkBuilder.string(")");
1923 castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType());
1924 }
1925
1926 if (castGuards == null || castGuards.contains(typeGuard)) {
1927 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null);
1928 currentValues.setValue(execution, castVariable);
1929 castsBuilder.tree(castVariable.createDeclaration(castBuilder.build()));
1930 }
1931
1932 checksBuilder.tree(checkBuilder.build());
1933 }
1934 return new CodeTree[]{checksBuilder.build(), castsBuilder.build()};
1935 }
1936
1937 public static final class LocalContext {
1938
1939 private final NodeGenFactory factory;
1940 private final Map<String, LocalVariable> values = new HashMap<>();
1941
1942 private LocalContext(NodeGenFactory factory) {
1943 this.factory = factory;
1944 }
1945
1946 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) {
1947 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
1948 addParametersTo(method, optionalArguments);
1949 return method;
1950 }
1951
1952 public static LocalContext load(NodeGenFactory factory, int signatureSize) {
1953 LocalContext context = new LocalContext(factory);
1954 context.loadValues(signatureSize);
1955 return context;
1956 }
1957
1958 public static LocalContext load(NodeGenFactory factory) {
1959 return load(factory, factory.node.getSignatureSize());
1960 }
1961
1962 public LocalContext copy() {
1963 LocalContext copy = new LocalContext(factory);
1964 copy.values.putAll(values);
1965 return copy;
1966 }
1967
1968 private static String fieldValueName(NodeFieldData field) {
1969 return field.getName() + "Value";
1970 }
1971
1972 @SuppressWarnings("static-method")
1973 public LocalVariable createValue(NodeExecutionData execution, TypeData type) {
1974 return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null);
1975 }
1976
1977 public LocalVariable createShortCircuitValue(NodeExecutionData execution) {
1978 return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null);
1979 }
1980
1981 private static String valueName(NodeExecutionData execution) {
1982 return execution.getName() + "Value";
1983 }
1984
1985 private static String shortCircuitName(NodeExecutionData execution) {
1986 return "has" + ElementUtils.firstLetterUpperCase(valueName(execution));
1987 }
1988
1989 public LocalVariable get(String id) {
1990 return values.get(id);
1991 }
1992
1993 public LocalVariable get(Parameter parameter, int signatureIndex) {
1994 LocalVariable var = get(parameter.getLocalName());
1995 if (var == null && parameter.getSpecification().isSignature()) {
1996 // lookup by signature index for executeWith
1997 NodeExecutionData execution = factory.node.getChildExecutions().get(signatureIndex);
1998 var = getValue(execution);
1999 }
2000 return var;
2001 }
2002
2003 public LocalVariable getValue(NodeExecutionData execution) {
2004 return get(valueName(execution));
2005 }
2006
2007 public LocalVariable getValue(int signatureIndex) {
2008 return getValue(factory.node.getChildExecutions().get(signatureIndex));
2009 }
2010
2011 public void removeValue(String id) {
2012 values.remove(id);
2013 }
2014
2015 public void setValue(NodeExecutionData execution, LocalVariable var) {
2016 values.put(valueName(execution), var);
2017 }
2018
2019 public void setShortCircuitValue(NodeExecutionData execution, LocalVariable var) {
2020 if (var == null) {
2021 return;
2022 }
2023 values.put(shortCircuitName(execution), var);
2024 }
2025
2026 private boolean needsVarargs(boolean requireLoaded) {
2027 int size = 0;
2028 for (NodeExecutionData execution : factory.node.getChildExecutions()) {
2029 if (requireLoaded && getValue(execution) == null) {
2030 continue;
2031 }
2032 if (execution.isShortCircuit()) {
2033 size += 2;
2034 } else {
2035 size++;
2036 }
2037 }
2038 return size > 4;
2039 }
2040
2041 private void loadValues(int evaluatedArguments) {
2042 values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(VirtualFrame.class), FRAME_VALUE, null));
2043
2044 for (NodeFieldData field : factory.node.getFields()) {
2045 String fieldName = fieldValueName(field);
2046 values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, NodeGenFactory.accessParent(field.getName())));
2047 }
2048
2049 boolean varargs = needsVarargs(false);
2050 for (int i = 0; i < evaluatedArguments; i++) {
2051 NodeExecutionData execution = factory.node.getChildExecutions().get(i);
2052 if (execution.isShortCircuit()) {
2053 LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric();
2054 if (varargs) {
2055 shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
2056 }
2057 values.put(shortCircuit.getName(), shortCircuit);
2058 }
2059 LocalVariable value = createValue(execution, factory.genericType);
2060 if (varargs) {
2061 value = value.accessWith(createReadVarargs(i));
2062 }
2063 values.put(value.getName(), value);
2064 }
2065 }
2066
2067 private static CodeTree createReadVarargs(int i) {
2068 return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build();
2069 }
2070
2071 public void addReferencesTo(CodeTreeBuilder builder, String... optionalNames) {
2072 for (String var : optionalNames) {
2073 LocalVariable local = values.get(var);
2074 if (local == null) {
2075 builder.nullLiteral();
2076 } else {
2077 builder.tree(local.createReference());
2078 }
2079 }
2080
2081 List<NodeExecutionData> executions = factory.node.getChildExecutions();
2082 for (NodeExecutionData execution : executions) {
2083 if (execution.isShortCircuit()) {
2084 LocalVariable shortCircuitVar = getShortCircuit(execution);
2085 if (shortCircuitVar != null) {
2086 builder.tree(shortCircuitVar.createReference());
2087 }
2088 }
2089 LocalVariable var = getValue(execution);
2090 if (var != null) {
2091 builder.startGroup();
2092 if (executions.size() == 1 && ElementUtils.typeEquals(var.getTypeMirror(), factory.getType(Object[].class))) {
2093 // if the current type is Object[] do not use varargs for a single argument
2094 builder.string("(Object) ");
2095 }
2096 builder.tree(var.createReference());
2097 builder.end();
2098 }
2099 }
2100 }
2101
2102 public void addParametersTo(CodeExecutableElement method, String... optionalNames) {
2103 for (String var : optionalNames) {
2104 LocalVariable local = values.get(var);
2105 if (local != null) {
2106 method.addParameter(local.createParameter());
2107 }
2108 }
2109 if (needsVarargs(true)) {
2110 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_"));
2111 method.setVarArgs(true);
2112 } else {
2113 for (NodeExecutionData execution : factory.node.getChildExecutions()) {
2114 if (execution.isShortCircuit()) {
2115 LocalVariable shortCircuitVar = getShortCircuit(execution);
2116 if (shortCircuitVar != null) {
2117 method.addParameter(shortCircuitVar.createParameter());
2118 }
2119 }
2120
2121 LocalVariable var = getValue(execution);
2122 if (var != null) {
2123 method.addParameter(var.createParameter());
2124 }
2125 }
2126 }
2127 }
2128
2129 private LocalVariable getShortCircuit(NodeExecutionData execution) {
2130 return values.get(shortCircuitName(execution));
2131 }
2132
2133 }
2134
2135 public final static class LocalVariable {
2136
2137 private final TypeData type;
2138 private final TypeMirror typeMirror;
2139 private final CodeTree accessorTree;
2140 private final String name;
2141
2142 public static LocalVariable fromParameter(Parameter parameter) {
2143 NodeExecutionData execution = parameter.getSpecification().getExecution();
2144 String name = null;
2145 if (execution == null) {
2146 name = parameter.getLocalName();
2147 } else {
2148 name = createName(execution);
2149 }
2150 return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null);
2151 }
2152
2153 private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree) {
2154 Objects.requireNonNull(typeMirror);
2155 this.typeMirror = typeMirror;
2156 this.accessorTree = accessorTree;
2157 this.type = type;
2158 this.name = name;
2159 }
2160
2161 public TypeData getType() {
2162 return type;
2163 }
2164
2165 public String getShortCircuitName() {
2166 return "has" + ElementUtils.firstLetterUpperCase(getName());
2167 }
2168
2169 public String getName() {
2170 return name;
2171 }
2172
2173 private static String createNextName(String name) {
2174 return name + "_";
2175 }
2176
2177 private static String createName(NodeExecutionData execution) {
2178 if (execution == null) {
2179 return "<error>";
2180 }
2181 return execution.getName() + "Value";
2182 }
2183
2184 public TypeMirror getTypeMirror() {
2185 return typeMirror;
2186 }
2187
2188 public CodeVariableElement createParameter() {
2189 return new CodeVariableElement(getTypeMirror(), getName());
2190 }
2191
2192 public CodeTree createDeclaration(CodeTree init) {
2193 return CodeTreeBuilder.createBuilder().declaration(getTypeMirror(), getName(), init).build();
2194 }
2195
2196 public CodeTree createReference() {
2197 if (accessorTree != null) {
2198 return accessorTree;
2199 } else {
2200 return CodeTreeBuilder.singleString(getName());
2201 }
2202 }
2203
2204 public LocalVariable newType(TypeData newType) {
2205 return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree);
2206 }
2207
2208 public final LocalVariable accessWith(CodeTree tree) {
2209 return new LocalVariable(type, typeMirror, name, tree);
2210 }
2211
2212 public final LocalVariable nextName() {
2213 return new LocalVariable(type, typeMirror, createNextName(name), accessorTree);
2214 }
2215
2216 public final LocalVariable makeGeneric() {
2217 return newType(type.getTypeSystem().getGenericTypeData());
2218 }
2219
2220 }
2221
2222 private interface SpecializationExecution {
2223
2224 boolean isFastPath();
2225
2226 CodeTree createExecute(SpecializationData specialization, LocalContext currentValues);
2227
2228 }
2229
2230 }