comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java @ 16759:23415229349b

Truffle-DSL: new package structure.
author Christian Humer <christian.humer@gmail.com>
date Mon, 11 Aug 2014 15:57:14 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java@bd28da642eea
children e6d15134ca86
comparison
equal deleted inserted replaced
16758:c5f8eeb3cbc8 16759:23415229349b
1 /*
2 * Copyright (c) 2012, 2012, 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.java.ElementUtils.*;
26 import static javax.lang.model.element.Modifier.*;
27
28 import java.util.*;
29
30 import javax.lang.model.element.*;
31 import javax.lang.model.type.*;
32 import javax.lang.model.util.*;
33
34 import com.oracle.truffle.api.dsl.*;
35 import com.oracle.truffle.api.nodes.*;
36 import com.oracle.truffle.dsl.processor.*;
37 import com.oracle.truffle.dsl.processor.java.*;
38 import com.oracle.truffle.dsl.processor.java.model.*;
39 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
40 import com.oracle.truffle.dsl.processor.model.*;
41 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
42 import com.oracle.truffle.dsl.processor.parser.*;
43 import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard;
44
45 public class NodeCodeGenerator extends AbstractCompilationUnitFactory<NodeData> {
46
47 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
48
49 private static final String EXECUTE_CHAINED = "executeChained0";
50 private static final String SPECIALIZE = "specialize0";
51 private static final String DSLSHARE_REWRITE = "rewrite";
52 private static final String DSLSHARE_FIND_ROOT = "findRoot";
53 private static final String DSLSHARE_REWRITE_TO_POLYMORHPIC = "rewriteToPolymorphic";
54 private static final String EXECUTE_UNINITIALIZED = "executeUninitialized0";
55 private static final String REWRITE = "rewrite0";
56 private static final String CREATE_INFO = "createInfo0";
57 private static final String CONTAINS_FALLBACK = "containsFallback";
58
59 private static final String FACTORY_METHOD_NAME = "create0";
60 private static final String EMPTY_CLASS_ARRAY = "EMPTY_CLASS_ARRAY";
61
62 private static final String METADATA_FIELD_NAME = "METADATA";
63
64 private TypeMirror getUnexpectedValueException() {
65 return getContext().getTruffleTypes().getUnexpectedValueException();
66 }
67
68 private static String factoryClassName(NodeData node) {
69 return node.getNodeId() + "Factory";
70 }
71
72 private static String nodeSpecializationClassName(SpecializationData specialization) {
73 String nodeid = resolveNodeId(specialization.getNode());
74 String name = ElementUtils.firstLetterUpperCase(nodeid);
75 name += ElementUtils.firstLetterUpperCase(specialization.getId());
76 name += "Node";
77 return name;
78 }
79
80 private static String nodePolymorphicClassName(NodeData node) {
81 return ElementUtils.firstLetterUpperCase(resolveNodeId(node)) + "PolymorphicNode";
82 }
83
84 private static String resolveNodeId(NodeData node) {
85 String nodeid = node.getNodeId();
86 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
87 nodeid = nodeid.substring(0, nodeid.length() - 4);
88 }
89 return nodeid;
90 }
91
92 private static String valueNameEvaluated(Parameter targetParameter) {
93 return valueName(targetParameter) + "Evaluated";
94 }
95
96 private static String implicitTypeName(Parameter param) {
97 return param.getLocalName() + "ImplicitType";
98 }
99
100 private static String polymorphicTypeName(NodeExecutionData param) {
101 return param.getName() + "PolymorphicType";
102 }
103
104 private static String valueName(Parameter param) {
105 return param.getLocalName();
106 }
107
108 private static CodeTree createAccessChild(NodeExecutionData targetExecution, String thisReference) {
109 String reference = thisReference;
110 if (reference == null) {
111 reference = "this";
112 }
113 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
114 Element accessElement = targetExecution.getChild().getAccessElement();
115 if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) {
116 builder.string(reference).string(".").string(targetExecution.getChild().getName());
117 } else if (accessElement.getKind() == ElementKind.FIELD) {
118 builder.string(reference).string(".").string(accessElement.getSimpleName().toString());
119 } else {
120 throw new AssertionError();
121 }
122 if (targetExecution.isIndexed()) {
123 builder.string("[" + targetExecution.getIndex() + "]");
124 }
125 return builder.getRoot();
126 }
127
128 private static String castValueName(Parameter parameter) {
129 return valueName(parameter) + "Cast";
130 }
131
132 private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) {
133 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
134 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
135 }
136 for (Parameter parameter : specialization.getParameters()) {
137 ParameterSpec spec = parameter.getSpecification();
138 if (forceFrame && spec.getName().equals("frame")) {
139 continue;
140 }
141 if (spec.isLocal()) {
142 continue;
143 }
144
145 String name = valueName(parameter);
146 if (evaluated && spec.isSignature()) {
147 name = valueNameEvaluated(parameter);
148 }
149
150 method.addParameter(new CodeVariableElement(parameter.getType(), name));
151 }
152 }
153
154 private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
155 Map<String, String> customNames) {
156 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
157 builder.string("frameValue");
158 }
159 for (Parameter parameter : specialization.getParameters()) {
160 ParameterSpec spec = parameter.getSpecification();
161 if (forceFrame && spec.getName().equals("frame")) {
162 continue;
163 }
164
165 if (parameter.getSpecification().isLocal()) {
166 continue;
167 }
168
169 Parameter sourceParameter = source.findParameter(parameter.getLocalName());
170
171 if (customNames != null && customNames.containsKey(parameter.getLocalName())) {
172 builder.string(customNames.get(parameter.getLocalName()));
173 } else if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) {
174 builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
175 } else if (sourceParameter != null) {
176 builder.string(valueName(sourceParameter, parameter));
177 } else {
178 builder.string(valueName(parameter));
179 }
180 }
181 }
182
183 private static String valueName(Parameter sourceParameter, Parameter targetParameter) {
184 if (!sourceParameter.getSpecification().isSignature()) {
185 return valueName(targetParameter);
186 } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
187 if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
188 return castValueName(targetParameter);
189 }
190 }
191 return valueName(targetParameter);
192 }
193
194 private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName,
195 String... customSignatureValueNames) {
196 CodeTreeBuilder builder = parent.create();
197
198 boolean castedValues = sourceMethod != targetMethod;
199
200 builder.startGroup();
201 ExecutableElement method = targetMethod.getMethod();
202 if (method == null) {
203 throw new UnsupportedOperationException();
204 }
205 TypeElement targetClass = ElementUtils.findNearestEnclosingType(method.getEnclosingElement());
206 NodeData node = (NodeData) targetMethod.getTemplate();
207
208 if (target == null) {
209 boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
210 if (accessible) {
211 if (builder.findMethod().getModifiers().contains(STATIC)) {
212 if (method.getModifiers().contains(STATIC)) {
213 builder.type(targetClass.asType());
214 } else {
215 builder.string(THIS_NODE_LOCAL_VAR_NAME);
216 }
217 } else {
218 if (targetMethod instanceof ExecutableTypeData) {
219 builder.string("this");
220 } else {
221 builder.string("super");
222 }
223 }
224 } else {
225 if (method.getModifiers().contains(STATIC)) {
226 builder.type(targetClass.asType());
227 } else {
228 Parameter firstParameter = null;
229 for (Parameter searchParameter : targetMethod.getParameters()) {
230 if (searchParameter.getSpecification().isSignature()) {
231 firstParameter = searchParameter;
232 break;
233 }
234 }
235 if (firstParameter == null) {
236 throw new AssertionError();
237 }
238
239 Parameter sourceParameter = sourceMethod.findParameter(firstParameter.getLocalName());
240
241 if (castedValues && sourceParameter != null) {
242 builder.string(valueName(sourceParameter, firstParameter));
243 } else {
244 builder.string(valueName(firstParameter));
245 }
246 }
247 }
248 builder.string(".");
249 } else {
250 builder.tree(target);
251 }
252 builder.startCall(method.getSimpleName().toString());
253
254 int signatureIndex = 0;
255
256 for (Parameter targetParameter : targetMethod.getParameters()) {
257 Parameter valueParameter = null;
258 if (sourceMethod != null) {
259 valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
260 }
261 if (valueParameter == null) {
262 valueParameter = targetParameter;
263 }
264 TypeMirror targetType = targetParameter.getType();
265 TypeMirror valueType = null;
266 if (valueParameter != null) {
267 valueType = valueParameter.getType();
268 }
269
270 if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) {
271 builder.string(customSignatureValueNames[signatureIndex]);
272 signatureIndex++;
273 } else if (targetParameter.getSpecification().isLocal()) {
274 builder.startGroup();
275 if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) {
276 builder.string(THIS_NODE_LOCAL_VAR_NAME).string(".");
277 } else {
278 builder.string("this.");
279 }
280 builder.string(targetParameter.getSpecification().getName());
281 builder.end();
282 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
283 builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
284 } else if (!ElementUtils.needsCastTo(valueType, targetType)) {
285 builder.startGroup();
286 builder.string(valueName(targetParameter));
287 builder.end();
288 } else {
289 builder.string(castValueName(targetParameter));
290 }
291 }
292
293 builder.end().end();
294
295 return builder.getRoot();
296 }
297
298 private static String baseClassName(NodeData node) {
299 String nodeid = resolveNodeId(node);
300 String name = ElementUtils.firstLetterUpperCase(nodeid);
301 name += "BaseNode";
302 return name;
303 }
304
305 private static CodeTree createCallTypeSystemMethod(CodeTreeBuilder parent, NodeData node, String methodName, CodeTree... args) {
306 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
307 startCallTypeSystemMethod(builder, node.getTypeSystem(), methodName);
308 for (CodeTree arg : args) {
309 builder.tree(arg);
310 }
311 builder.end().end();
312 return builder.getRoot();
313 }
314
315 private static void startCallTypeSystemMethod(CodeTreeBuilder body, TypeSystemData typeSystem, String methodName) {
316 GeneratedTypeMirror typeMirror = new GeneratedTypeMirror(ElementUtils.getPackageName(typeSystem.getTemplateType()), TypeSystemCodeGenerator.typeName(typeSystem));
317 body.startGroup();
318 body.staticReference(typeMirror, TypeSystemCodeGenerator.singletonName(typeSystem));
319 body.string(".").startCall(methodName);
320 }
321
322 /**
323 * <pre>
324 * variant1 $condition != null
325 *
326 * $type $name = defaultValue($type);
327 * if ($condition) {
328 * $name = $value;
329 * }
330 *
331 * variant2 $condition != null
332 * $type $name = $value;
333 * </pre>
334 *
335 * .
336 */
337 private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) {
338 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
339 if (condition == null) {
340 builder.declaration(type, name, value);
341 } else {
342 builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot());
343
344 builder.startIf().tree(condition).end();
345 builder.startBlock();
346 builder.startStatement();
347 builder.string(name);
348 builder.string(" = ");
349 builder.tree(value);
350 builder.end(); // statement
351 builder.end(); // block
352 }
353 return builder.getRoot();
354 }
355
356 private void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) {
357 CodeTreeBuilder nodes = builder.create();
358 CodeTreeBuilder arguments = builder.create();
359 nodes.startCommaGroup();
360 arguments.startCommaGroup();
361 boolean empty = true;
362 for (Parameter parameter : current.getParameters()) {
363 NodeExecutionData executionData = parameter.getSpecification().getExecution();
364 if (executionData != null) {
365 if (executionData.isShortCircuit()) {
366 nodes.nullLiteral();
367 arguments.string(valueName(parameter.getPreviousParameter()));
368 }
369 nodes.tree(createAccessChild(executionData, "rootNode"));
370 arguments.string(valueName(parameter));
371 empty = false;
372 }
373 }
374 nodes.end();
375 arguments.end();
376 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
377
378 builder.declaration(baseClassName(getModel()), "rootNode", builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_FIND_ROOT).string("this").end());
379 builder.startThrow().startNew(getContext().getType(UnsupportedSpecializationException.class));
380 builder.string("rootNode");
381 builder.startNewArray(getContext().getTruffleTypes().getNodeArray(), null);
382 builder.tree(nodes.getRoot());
383 builder.end();
384 if (!empty) {
385 builder.tree(arguments.getRoot());
386 }
387 builder.end().end();
388 }
389
390 private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
391 List<ExecutableElement> constructors = new ArrayList<>();
392 for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(nodeType).getEnclosedElements())) {
393 if (constructor.getModifiers().contains(PRIVATE)) {
394 continue;
395 }
396 if (isCopyConstructor(constructor)) {
397 continue;
398 }
399 constructors.add(constructor);
400 }
401
402 if (constructors.isEmpty()) {
403 constructors.add(new CodeExecutableElement(null, ElementUtils.getSimpleName(nodeType)));
404 }
405
406 return constructors;
407 }
408
409 private static ExecutableElement findCopyConstructor(TypeMirror type) {
410 for (ExecutableElement constructor : ElementFilter.constructorsIn(ElementUtils.fromTypeMirror(type).getEnclosedElements())) {
411 if (constructor.getModifiers().contains(PRIVATE)) {
412 continue;
413 }
414 if (isCopyConstructor(constructor)) {
415 return constructor;
416 }
417 }
418
419 return null;
420 }
421
422 private static boolean isCopyConstructor(ExecutableElement element) {
423 if (element.getParameters().size() != 1) {
424 return false;
425 }
426 VariableElement var = element.getParameters().get(0);
427 TypeElement enclosingType = ElementUtils.findNearestEnclosingType(var);
428 if (ElementUtils.typeEquals(var.asType(), enclosingType.asType())) {
429 return true;
430 }
431 List<TypeElement> types = ElementUtils.getDirectSuperTypes(enclosingType);
432 for (TypeElement type : types) {
433 if (!(type instanceof CodeTypeElement)) {
434 // no copy constructors which are not generated types
435 return false;
436 }
437
438 if (ElementUtils.typeEquals(var.asType(), type.asType())) {
439 return true;
440 }
441 }
442 return false;
443 }
444
445 @Override
446 @SuppressWarnings("unchecked")
447 protected void createChildren(NodeData node) {
448 List<CodeTypeElement> casts = new ArrayList<>(getElement().getEnclosedElements());
449 getElement().getEnclosedElements().clear();
450
451 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
452 for (NodeData nodeChild : node.getEnclosingNodes()) {
453 NodeCodeGenerator generator = new NodeCodeGenerator();
454 childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements());
455 }
456
457 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) {
458 NodeFactoryFactory factory = new NodeFactoryFactory(childTypes);
459 add(factory, node);
460 factory.getElement().getEnclosedElements().addAll(casts);
461 }
462 }
463
464 private static CodeTree createCastType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
465 if (targetType == null) {
466 return value;
467 } else if (sourceType != null && !sourceType.needsCastTo(targetType)) {
468 return value;
469 }
470
471 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
472 String targetMethodName;
473 if (expect) {
474 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
475 } else {
476 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
477 }
478 startCallTypeSystemMethod(builder, typeSystem, targetMethodName);
479 builder.tree(value);
480 builder.end().end();
481 return builder.getRoot();
482 }
483
484 private static CodeTree createExpectType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, CodeTree expression) {
485 return createCastType(typeSystem, sourceType, targetType, true, expression);
486 }
487
488 private CodeTree createDeoptimize(CodeTreeBuilder parent) {
489 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
490 builder.startStatement();
491 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end();
492 builder.end();
493 return builder.getRoot();
494 }
495
496 private class NodeFactoryFactory extends AbstractClassElementFactory<NodeData> {
497
498 private final Map<NodeData, List<TypeElement>> childTypes;
499 private CodeTypeElement generatedNode;
500
501 public NodeFactoryFactory(Map<NodeData, List<TypeElement>> childElements) {
502 this.childTypes = childElements;
503 }
504
505 @Override
506 protected CodeTypeElement create(NodeData node) {
507 Modifier visibility = ElementUtils.getVisibility(node.getTemplateType().getModifiers());
508
509 CodeTypeElement clazz = createClass(node, modifiers(), factoryClassName(node), null, false);
510 if (visibility != null) {
511 clazz.getModifiers().add(visibility);
512 }
513 clazz.getModifiers().add(Modifier.FINAL);
514 return clazz;
515 }
516
517 @Override
518 protected void createChildren(NodeData node) {
519 CodeTypeElement clazz = getElement();
520
521 Modifier createVisibility = ElementUtils.getVisibility(clazz.getModifiers());
522
523 if (node.needsFactory()) {
524 NodeBaseFactory factory = new NodeBaseFactory();
525 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization());
526 generatedNode = factory.getElement();
527
528 createFactoryMethods(node, clazz, createVisibility);
529
530 for (SpecializationData specialization : node.getSpecializations()) {
531 if (!specialization.isReachable() || specialization.isGeneric()) {
532 continue;
533 }
534
535 if (specialization.isPolymorphic() && node.isPolymorphic(context)) {
536 PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(generatedNode);
537 add(polymorphicFactory, specialization);
538 continue;
539 }
540
541 add(new SpecializedNodeFactory(generatedNode), specialization);
542 }
543
544 TypeMirror nodeFactory = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getTruffleTypes().getNodeFactoryBase()), node.getNodeType());
545 clazz.setSuperClass(nodeFactory);
546 clazz.add(createNodeFactoryConstructor(node));
547 clazz.add(createCreateNodeMethod(node));
548 // clazz.add(createGetNodeClassMethod(node));
549 // clazz.add(createGetNodeSignaturesMethod());
550 // clazz.add(createGetChildrenSignatureMethod(node));
551 clazz.add(createGetInstanceMethod(node, createVisibility));
552 clazz.add(createInstanceConstant(node, clazz.asType()));
553 }
554
555 for (NodeData childNode : childTypes.keySet()) {
556 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
557 continue;
558 }
559
560 for (TypeElement type : childTypes.get(childNode)) {
561 Set<Modifier> typeModifiers = ((CodeTypeElement) type).getModifiers();
562 Modifier visibility = ElementUtils.getVisibility(type.getModifiers());
563 typeModifiers.clear();
564 if (visibility != null) {
565 typeModifiers.add(visibility);
566 }
567
568 typeModifiers.add(Modifier.STATIC);
569 typeModifiers.add(Modifier.FINAL);
570 clazz.add(type);
571 }
572 }
573
574 List<NodeData> children = node.getNodeDeclaringChildren();
575 if (node.getDeclaringNode() == null && children.size() > 0) {
576 clazz.add(createGetFactories(node));
577 }
578
579 }
580
581 private Element createNodeFactoryConstructor(NodeData node) {
582 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), null, factoryClassName(node));
583 CodeTreeBuilder builder = method.createBuilder();
584 builder.startStatement();
585 builder.startCall("super");
586
587 // node type
588 builder.typeLiteral(node.getNodeType());
589
590 // execution signature
591 builder.startGroup();
592 if (node.getChildExecutions().isEmpty()) {
593 builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
594 } else {
595 builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null);
596 for (NodeExecutionData execution : node.getChildExecutions()) {
597 builder.typeLiteral(execution.getNodeType());
598 }
599 builder.end();
600 }
601 builder.end();
602
603 // node signatures
604 builder.startGroup();
605 builder.startNewArray(new ArrayCodeTypeMirror(new ArrayCodeTypeMirror(context.getType(Class.class))), null);
606 List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
607 for (ExecutableElement constructor : constructors) {
608 builder.startGroup();
609 if (constructor.getParameters().isEmpty()) {
610 builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
611 } else {
612 builder.startNewArray(new ArrayCodeTypeMirror(context.getType(Class.class)), null);
613 for (VariableElement var : constructor.getParameters()) {
614 builder.typeLiteral(var.asType());
615 }
616 builder.end();
617 }
618 builder.end();
619 }
620 builder.end();
621 builder.end();
622
623 builder.end().end().end();
624 return method;
625 }
626
627 private CodeExecutableElement createCreateNodeMethod(NodeData node) {
628 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode");
629 CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments");
630 method.setVarArgs(true);
631 method.addParameter(arguments);
632
633 CodeTreeBuilder builder = method.createBuilder();
634 List<ExecutableElement> signatures = findUserConstructors(generatedNode.asType());
635 boolean ifStarted = false;
636
637 for (ExecutableElement element : signatures) {
638 ifStarted = builder.startIf(ifStarted);
639 builder.string("arguments.length == " + element.getParameters().size());
640
641 int index = 0;
642 for (VariableElement param : element.getParameters()) {
643 if (ElementUtils.isObject(param.asType())) {
644 continue;
645 }
646 builder.string(" && ");
647 if (!param.asType().getKind().isPrimitive()) {
648 builder.string("(arguments[" + index + "] == null || ");
649 }
650 builder.string("arguments[" + index + "] instanceof ");
651 builder.type(ElementUtils.boxType(getContext(), param.asType()));
652 if (!param.asType().getKind().isPrimitive()) {
653 builder.string(")");
654 }
655 index++;
656 }
657 builder.end();
658 builder.startBlock();
659
660 builder.startReturn().startCall("create");
661 index = 0;
662 for (VariableElement param : element.getParameters()) {
663 builder.startGroup();
664 if (!ElementUtils.isObject(param.asType())) {
665 builder.string("(").type(param.asType()).string(") ");
666 }
667 builder.string("arguments[").string(String.valueOf(index)).string("]");
668 builder.end();
669 index++;
670 }
671 builder.end().end();
672
673 builder.end(); // block
674 }
675
676 builder.startElseBlock();
677 builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class));
678 builder.doubleQuote("Invalid create signature.");
679 builder.end().end();
680 builder.end(); // else block
681 return method;
682 }
683
684 private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) {
685 TypeElement nodeFactoryType = ElementUtils.fromTypeMirror(getContext().getType(NodeFactory.class));
686 TypeMirror returnType = ElementUtils.getDeclaredType(nodeFactoryType, node.getNodeType());
687
688 CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance");
689 if (visibility != null) {
690 method.getModifiers().add(visibility);
691 }
692 method.getModifiers().add(Modifier.STATIC);
693
694 String varName = instanceVarName(node);
695
696 CodeTreeBuilder builder = method.createBuilder();
697 builder.startIf();
698 builder.string(varName).string(" == null");
699 builder.end().startBlock();
700
701 builder.startStatement();
702 builder.string(varName);
703 builder.string(" = ");
704 builder.startNew(factoryClassName(node)).end();
705 builder.end();
706
707 builder.end();
708 builder.startReturn().string(varName).end();
709 return method;
710 }
711
712 private String instanceVarName(NodeData node) {
713 if (node.getDeclaringNode() != null) {
714 return ElementUtils.firstLetterLowerCase(factoryClassName(node)) + "Instance";
715 } else {
716 return "instance";
717 }
718 }
719
720 private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) {
721 String varName = instanceVarName(node);
722 CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName);
723 var.getModifiers().add(Modifier.PRIVATE);
724 var.getModifiers().add(Modifier.STATIC);
725 return var;
726 }
727
728 private ExecutableElement createGetFactories(NodeData node) {
729 List<NodeData> children = node.getNodeDeclaringChildren();
730 if (node.needsFactory()) {
731 children.add(node);
732 }
733
734 List<TypeMirror> nodeTypesList = new ArrayList<>();
735 TypeMirror prev = null;
736 boolean allSame = true;
737 for (NodeData child : children) {
738 nodeTypesList.add(child.getNodeType());
739 if (prev != null && !ElementUtils.typeEquals(child.getNodeType(), prev)) {
740 allSame = false;
741 }
742 prev = child.getNodeType();
743 }
744 TypeMirror commonNodeSuperType = ElementUtils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()]));
745
746 Types types = getContext().getEnvironment().getTypeUtils();
747 TypeMirror factoryType = getContext().getType(NodeFactory.class);
748 TypeMirror baseType;
749 if (allSame) {
750 baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), commonNodeSuperType);
751 } else {
752 baseType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null));
753 }
754 TypeMirror listType = ElementUtils.getDeclaredType(ElementUtils.fromTypeMirror(getContext().getType(List.class)), baseType);
755
756 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories");
757
758 CodeTreeBuilder builder = method.createBuilder();
759 builder.startReturn();
760 builder.startStaticCall(getContext().getType(Arrays.class), "asList");
761
762 for (NodeData child : children) {
763 builder.startGroup();
764 NodeData childNode = child;
765 List<NodeData> factories = new ArrayList<>();
766 while (childNode.getDeclaringNode() != null) {
767 factories.add(childNode);
768 childNode = childNode.getDeclaringNode();
769 }
770 Collections.reverse(factories);
771 for (NodeData nodeData : factories) {
772 builder.string(factoryClassName(nodeData)).string(".");
773 }
774 builder.string("getInstance()");
775 builder.end();
776 }
777 builder.end();
778 builder.end();
779 return method;
780 }
781
782 private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) {
783 List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType());
784 for (ExecutableElement constructor : constructors) {
785 clazz.add(createCreateMethod(node, createVisibility, constructor));
786 }
787 }
788
789 private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) {
790 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor);
791 method.setSimpleName(CodeNames.of("create"));
792 method.getModifiers().clear();
793 if (visibility != null) {
794 method.getModifiers().add(visibility);
795 }
796 method.getModifiers().add(Modifier.STATIC);
797 method.setReturnType(node.getNodeType());
798
799 CodeTreeBuilder body = method.createBuilder();
800 body.startReturn();
801 if (node.getSpecializations().isEmpty()) {
802 body.nullLiteral();
803 } else {
804 body.startCall(nodeSpecializationClassName(node.getSpecializations().get(0)), FACTORY_METHOD_NAME);
805 for (VariableElement var : method.getParameters()) {
806 body.string(var.getSimpleName().toString());
807 }
808 body.end();
809 }
810 body.end();
811 return method;
812 }
813
814 }
815
816 private class NodeBaseFactory extends AbstractClassElementFactory<SpecializationData> {
817
818 @Override
819 protected CodeTypeElement create(SpecializationData specialization) {
820 NodeData node = specialization.getNode();
821 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false);
822 clazz.getImplements().add(context.getTruffleTypes().getDslNode());
823
824 for (NodeChildData child : node.getChildren()) {
825 clazz.add(createChildField(child));
826
827 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) {
828 ExecutableElement getter = (ExecutableElement) child.getAccessElement();
829 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter);
830 method.getModifiers().remove(Modifier.ABSTRACT);
831 CodeTreeBuilder builder = method.createBuilder();
832 builder.startReturn().string("this.").string(child.getName()).end();
833 clazz.add(method);
834 }
835 }
836
837 for (NodeFieldData field : node.getFields()) {
838 if (!field.isGenerated()) {
839 continue;
840 }
841
842 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), field.getType(), field.getName()));
843 if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) {
844 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), field.getGetter());
845 method.getModifiers().remove(Modifier.ABSTRACT);
846 method.createBuilder().startReturn().string("this.").string(field.getName()).end();
847 clazz.add(method);
848 }
849 }
850
851 for (String assumption : node.getAssumptions()) {
852 clazz.add(createAssumptionField(assumption));
853 }
854
855 createConstructors(node, clazz);
856
857 return clazz;
858 }
859
860 @Override
861 protected void createChildren(SpecializationData specialization) {
862 NodeData node = specialization.getNode();
863 CodeTypeElement clazz = getElement();
864
865 SpecializationGroup rootGroup = createSpecializationGroups(node);
866
867 if (node.needsRewrites(context)) {
868 if (node.isPolymorphic(context)) {
869
870 CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0");
871 var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation()));
872 clazz.add(var);
873
874 CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getPolymorphicSpecialization());
875 clazz.add(genericCachedExecute);
876
877 }
878
879 for (CodeExecutableElement method : createImplicitChildrenAccessors()) {
880 clazz.add(method);
881 }
882 clazz.add(createInfoMessage(node));
883 clazz.add(createMonomorphicRewrite());
884 clazz.add(createCreateSpecializationMethod(node, rootGroup));
885 }
886
887 clazz.add(createAdoptChildren0());
888 clazz.add(createGetMetadata0(true));
889 clazz.add(createUpdateTypes0());
890 clazz.add(createGetNext());
891 }
892
893 private Element createGetNext() {
894 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(Node.class), "getNext0");
895 CodeTreeBuilder builder = method.createBuilder();
896 NodeData node = getModel().getNode();
897
898 if (node.isPolymorphic(context)) {
899 builder.startReturn().string("next0").end();
900 } else {
901 builder.returnNull();
902 }
903
904 return method;
905 }
906
907 protected final CodeExecutableElement createUpdateTypes0() {
908 ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
909 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getType(void.class), "updateTypes0");
910 method.getParameters().add(new CodeVariableElement(classArray, "types"));
911
912 if (getModel().isPolymorphic()) {
913 CodeTreeBuilder builder = method.createBuilder();
914
915 int index = 0;
916 for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) {
917 String fieldName = polymorphicTypeName(execution);
918
919 builder.startStatement();
920 builder.string(fieldName).string(" = ").string("types[").string(String.valueOf(index)).string("]");
921 builder.end();
922 index++;
923 }
924 }
925
926 return method;
927 }
928
929 protected final CodeExecutableElement createGetMetadata0(boolean empty) {
930 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), context.getTruffleTypes().getDslMetadata(), "getMetadata0");
931 if (empty) {
932 method.createBuilder().startReturn().staticReference(context.getTruffleTypes().getDslMetadata(), "NONE").end();
933 } else {
934 method.createBuilder().startReturn().string(METADATA_FIELD_NAME).end();
935 }
936 return method;
937 }
938
939 private CodeExecutableElement createAdoptChildren0() {
940 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, FINAL), context.getType(void.class), "adoptChildren0");
941 method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "other"));
942 method.getParameters().add(new CodeVariableElement(context.getTruffleTypes().getNode(), "newNext"));
943 NodeData node = getModel().getNode();
944 CodeTreeBuilder builder = method.createBuilder();
945 List<NodeExecutionData> executions = node.getChildExecutions();
946
947 if (executions.size() > 0) {
948 builder.startIf().string("other == null").end().startBlock();
949 for (NodeExecutionData execution : executions) {
950 builder.startStatement().tree(createAccessChild(execution, "this")).string(" = null").end();
951 }
952 builder.end().startElseBlock();
953
954 String access;
955 if (executions.size() > 1) {
956 builder.declaration(baseClassName(node), "otherCast", builder.create().cast(baseClassName(node)).string("other"));
957 access = "otherCast";
958 } else {
959 assert executions.size() == 1;
960 access = "((" + baseClassName(node) + ") other)";
961 }
962 for (NodeExecutionData execution : executions) {
963 builder.startStatement().tree(createAccessChild(execution, "this")).string(" = ").tree(createAccessChild(execution, access)).end();
964 }
965
966 builder.end();
967 }
968
969 if (getModel().getNode().isPolymorphic(context)) {
970 builder.startIf().string("newNext == null").end().startBlock();
971 builder.statement("this.next0 = null");
972 builder.end().startElseBlock();
973 builder.statement("this.next0 = (" + baseClassName(getModel().getNode()) + ") newNext");
974 builder.end();
975 }
976
977 return method;
978 }
979
980 private List<CodeExecutableElement> createImplicitChildrenAccessors() {
981 NodeData node = getModel().getNode();
982 List<Set<TypeData>> prototype = Collections.nCopies(node.getGenericSpecialization().getParameters().size(), null);
983 List<Set<TypeData>> expectTypes = new ArrayList<>(prototype);
984
985 for (ExecutableTypeData executableType : node.getExecutableTypes()) {
986 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
987 Parameter parameter = executableType.getSignatureParameter(i);
988 if (i >= expectTypes.size()) {
989 break;
990 }
991 Set<TypeData> types = expectTypes.get(i);
992 if (types == null) {
993 types = new TreeSet<>();
994 expectTypes.set(i, types);
995 }
996 types.add(parameter.getTypeSystemType());
997 }
998 }
999
1000 List<CodeExecutableElement> methods = new ArrayList<>();
1001 List<Set<TypeData>> visitedList = new ArrayList<>(prototype);
1002 for (SpecializationData spec : node.getSpecializations()) {
1003 int signatureIndex = -1;
1004 for (Parameter param : spec.getParameters()) {
1005 if (!param.getSpecification().isSignature()) {
1006 continue;
1007 }
1008 signatureIndex++;
1009 Set<TypeData> visitedTypeData = visitedList.get(signatureIndex);
1010 if (visitedTypeData == null) {
1011 visitedTypeData = new TreeSet<>();
1012 visitedList.set(signatureIndex, visitedTypeData);
1013 }
1014
1015 if (visitedTypeData.contains(param.getTypeSystemType())) {
1016 continue;
1017 }
1018 visitedTypeData.add(param.getTypeSystemType());
1019
1020 Set<TypeData> expect = expectTypes.get(signatureIndex);
1021 if (expect == null) {
1022 expect = Collections.emptySet();
1023 }
1024
1025 methods.addAll(createExecuteChilds(param, expect));
1026 }
1027 }
1028 return methods;
1029 }
1030
1031 private CodeTree truffleBooleanOption(CodeTreeBuilder parent, String name) {
1032 CodeTreeBuilder builder = parent.create();
1033 builder.staticReference(getContext().getTruffleTypes().getTruffleOptions(), name);
1034 return builder.getRoot();
1035 }
1036
1037 private Element createInfoMessage(NodeData node) {
1038 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), CREATE_INFO);
1039 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message"));
1040 addInternalValueParameters(method, node.getGenericSpecialization(), false, false);
1041
1042 CodeTreeBuilder builder = method.createBuilder();
1043
1044 builder.startIf().tree(truffleBooleanOption(builder, TruffleTypes.OPTION_DETAILED_REWRITE_REASONS)).end();
1045 builder.startBlock();
1046
1047 builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end();
1048 builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end();
1049
1050 String sep = null;
1051 for (Parameter parameter : node.getGenericSpecialization().getSignatureParameters()) {
1052 builder.startStatement();
1053 builder.string("builder");
1054 if (sep != null) {
1055 builder.startCall(".append").doubleQuote(sep).end();
1056 }
1057 builder.startCall(".append").doubleQuote(parameter.getLocalName()).end();
1058 builder.startCall(".append").doubleQuote(" = ").end();
1059 builder.startCall(".append").string(parameter.getLocalName()).end();
1060 builder.end();
1061
1062 if (!ElementUtils.isPrimitive(parameter.getType())) {
1063 builder.startIf().string(parameter.getLocalName() + " != null").end();
1064 builder.startBlock();
1065 }
1066 builder.startStatement();
1067 if (ElementUtils.isPrimitive(parameter.getType())) {
1068 builder.startCall("builder.append").doubleQuote(" (" + ElementUtils.getSimpleName(parameter.getType()) + ")").end();
1069 } else {
1070 builder.startCall("builder.append").doubleQuote(" (").end();
1071 builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end();
1072 builder.startCall(".append").doubleQuote(")").end();
1073 }
1074 builder.end();
1075 if (!ElementUtils.isPrimitive(parameter.getType())) {
1076 builder.end();
1077 }
1078
1079 sep = ", ";
1080 }
1081
1082 builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end();
1083 builder.startReturn().string("builder.toString()").end();
1084
1085 builder.end();
1086 builder.startElseBlock();
1087 builder.startReturn().string("message").end();
1088 builder.end();
1089
1090 return method;
1091 }
1092
1093 private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) {
1094 CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), EXECUTE_CHAINED);
1095 addInternalValueParameters(cachedExecute, polymorph, true, false);
1096
1097 ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0);
1098 boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext());
1099 if (sourceThrowsUnexpected && sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) {
1100 sourceThrowsUnexpected = false;
1101 }
1102 if (sourceThrowsUnexpected) {
1103 cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class));
1104 }
1105 return cachedExecute;
1106
1107 }
1108
1109 private void createConstructors(NodeData node, CodeTypeElement clazz) {
1110 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
1111 ExecutableElement sourceSectionConstructor = null;
1112 if (constructors.isEmpty()) {
1113 clazz.add(createUserConstructor(clazz, null));
1114 } else {
1115 for (ExecutableElement constructor : constructors) {
1116 clazz.add(createUserConstructor(clazz, constructor));
1117 if (NodeParser.isSourceSectionConstructor(context, constructor)) {
1118 sourceSectionConstructor = constructor;
1119 }
1120 }
1121 }
1122 if (node.needsRewrites(getContext())) {
1123 ExecutableElement copyConstructor = findCopyConstructor(node.getNodeType());
1124 clazz.add(createCopyConstructor(clazz, copyConstructor, sourceSectionConstructor));
1125 }
1126 }
1127
1128 private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) {
1129 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
1130 CodeTreeBuilder builder = method.createBuilder();
1131
1132 NodeData node = getModel().getNode();
1133
1134 if (superConstructor != null) {
1135 for (VariableElement param : superConstructor.getParameters()) {
1136 method.getParameters().add(CodeVariableElement.clone(param));
1137 }
1138 }
1139
1140 if (superConstructor != null) {
1141 builder.startStatement().startSuperCall();
1142 for (VariableElement param : superConstructor.getParameters()) {
1143 builder.string(param.getSimpleName().toString());
1144 }
1145 builder.end().end();
1146 }
1147
1148 for (VariableElement var : type.getFields()) {
1149 if (var.getModifiers().contains(STATIC)) {
1150 continue;
1151 }
1152 NodeChildData child = node.findChild(var.getSimpleName().toString());
1153
1154 if (child != null) {
1155 method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName()));
1156 } else {
1157 method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString()));
1158 }
1159
1160 builder.startStatement();
1161 String fieldName = var.getSimpleName().toString();
1162
1163 CodeTree init = createStaticCast(builder, child, fieldName);
1164
1165 builder.string("this.").string(fieldName).string(" = ").tree(init);
1166 builder.end();
1167 }
1168 return method;
1169 }
1170
1171 private CodeTree createStaticCast(CodeTreeBuilder parent, NodeChildData child, String fieldName) {
1172 NodeData parentNode = getModel().getNode();
1173 if (child != null) {
1174 CreateCastData createCast = parentNode.findCast(child.getName());
1175 if (createCast != null) {
1176 return createTemplateMethodCall(parent, null, parentNode.getGenericSpecialization(), createCast, null, fieldName);
1177 }
1178 }
1179 return CodeTreeBuilder.singleString(fieldName);
1180 }
1181
1182 private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor, ExecutableElement sourceSectionConstructor) {
1183 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString());
1184 CodeTreeBuilder builder = method.createBuilder();
1185 method.getParameters().add(new CodeVariableElement(type.asType(), "copy"));
1186
1187 if (superConstructor != null) {
1188 builder.startStatement().startSuperCall().string("copy").end().end();
1189 } else if (sourceSectionConstructor != null) {
1190 builder.startStatement().startSuperCall().string("copy.getSourceSection()").end().end();
1191 }
1192
1193 for (VariableElement var : type.getFields()) {
1194 if (var.getModifiers().contains(STATIC) || !var.getModifiers().contains(FINAL)) {
1195 continue;
1196 }
1197 final String varName = var.getSimpleName().toString();
1198 final TypeMirror varType = var.asType();
1199 if (ElementUtils.isAssignable(varType, getContext().getTruffleTypes().getNodeArray())) {
1200 CodeTree size = builder.create().string("copy.", varName, ".length").getRoot();
1201 builder.startStatement().string("this.").string(varName).string(" = ").startNewArray((ArrayType) varType, size).end().end();
1202 } else {
1203 builder.startStatement().string("this.", varName, " = copy.", varName).end();
1204 }
1205 }
1206
1207 return method;
1208 }
1209
1210 private CodeVariableElement createAssumptionField(String assumption) {
1211 CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption);
1212 var.getModifiers().add(Modifier.FINAL);
1213 return var;
1214 }
1215
1216 private CodeVariableElement createChildField(NodeChildData child) {
1217 TypeMirror type = child.getNodeType();
1218 CodeVariableElement var = new CodeVariableElement(type, child.getName());
1219 var.getModifiers().add(Modifier.PROTECTED);
1220
1221 DeclaredType annotationType;
1222 if (child.getCardinality() == Cardinality.MANY) {
1223 var.getModifiers().add(Modifier.FINAL);
1224 annotationType = getContext().getTruffleTypes().getChildrenAnnotation();
1225 } else {
1226 annotationType = getContext().getTruffleTypes().getChildAnnotation();
1227 }
1228
1229 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
1230 return var;
1231 }
1232
1233 private SpecializationGroup createSpecializationGroups(final NodeData node) {
1234 List<SpecializationData> specializations = node.getSpecializations();
1235 List<SpecializationData> filteredSpecializations = new ArrayList<>();
1236 for (SpecializationData current : specializations) {
1237 if (current.isUninitialized() || current.isPolymorphic() || !current.isReachable()) {
1238 continue;
1239 }
1240 filteredSpecializations.add(current);
1241 }
1242
1243 return SpecializationGroup.create(filteredSpecializations);
1244 }
1245
1246 protected final CodeExecutableElement createExecuteUninitialized() {
1247 NodeData node = getModel().getNode();
1248 SpecializationData generic = node.getGenericSpecialization();
1249 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), generic.getReturnType().getType(), EXECUTE_UNINITIALIZED);
1250 addInternalValueParameters(method, generic, true, false);
1251 CodeTreeBuilder builder = method.createBuilder();
1252
1253 CodeTreeBuilder createSpecializationCall = builder.create();
1254 createSpecializationCall.startCall(SPECIALIZE);
1255 addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null);
1256 createSpecializationCall.end();
1257 builder.declaration(baseClassName(node), "newNode", createSpecializationCall);
1258
1259 if (generic.isReachable()) {
1260 builder.startIf().string("newNode == null").end().startBlock();
1261
1262 builder.startIf().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "inInterpreter").end().end().startBlock();
1263 builder.statement("containsFallback = true");
1264 builder.end();
1265 builder.tree(createGenericInvoke(builder, generic, generic));
1266 builder.end();
1267 builder.startElseBlock();
1268 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
1269 }
1270
1271 builder.startReturn();
1272 builder.startStaticCall(context.getTruffleTypes().getDslShare(), "rewriteUninitialized").string("this").string("newNode").end();
1273 builder.string(".").startCall(EXECUTE_CHAINED);
1274 addInternalValueParameterNames(builder, generic, generic, null, true, null);
1275 builder.end();
1276 builder.end();
1277
1278 if (generic.isReachable()) {
1279 builder.end();
1280 }
1281
1282 return method;
1283 }
1284
1285 private CodeTree createInfoCall(CodeTreeBuilder parent, SpecializationData specialization, String reason) {
1286 CodeTreeBuilder builder = parent.create();
1287 builder.startCall(CREATE_INFO).string(reason);
1288 addInternalValueParameterNames(builder, specialization, specialization, null, false, null);
1289 builder.end();
1290 return builder.getRoot();
1291 }
1292
1293 private CodeExecutableElement createMonomorphicRewrite() {
1294 NodeData node = getModel().getNode();
1295
1296 SpecializationData generic = node.getGenericSpecialization();
1297 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), generic.getReturnType().getType(), REWRITE);
1298 addInternalValueParameters(method, generic, true, false);
1299 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason"));
1300
1301 CodeTreeBuilder builder = method.createBuilder();
1302
1303 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end().end();
1304 String baseClassName = baseClassName(getModel().getNode());
1305 CodeTreeBuilder createSpecializationCall = builder.create();
1306 createSpecializationCall.startCall(SPECIALIZE);
1307 addInternalValueParameterNames(createSpecializationCall, generic, generic, null, node.needsFrame(getContext()), null);
1308 createSpecializationCall.end();
1309 builder.declaration(baseClassName, "newNode", createSpecializationCall);
1310
1311 builder.startIf().string("newNode == null").end().startBlock();
1312 builder.startStatement();
1313 String uninitializedName = nodeSpecializationClassName(node.getUninitializedSpecialization());
1314 builder.string("newNode = ").startNew(uninitializedName).string("this").end();
1315 builder.end();
1316 if (node.isFallbackReachable()) {
1317 builder.startStatement().string("((", uninitializedName, ") newNode).containsFallback = true").end();
1318 }
1319 builder.end();
1320
1321 builder.startStatement();
1322 builder.type(getContext().getType(String.class)).string(" message = ").tree(createInfoCall(builder, generic, "reason"));
1323 builder.end();
1324
1325 builder.declaration(baseClassName, "returnNode",
1326 builder.create().startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE).string("this").string("newNode").string("message").end().getRoot());
1327 builder.startIf().string("returnNode == null").end().startBlock();
1328 builder.tree(createRewritePolymorphic(builder, node, "this"));
1329 builder.end();
1330
1331 builder.startReturn();
1332 builder.startCall("returnNode", EXECUTE_CHAINED);
1333 addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, null);
1334 builder.end();
1335 builder.end();
1336
1337 return method;
1338 }
1339
1340 private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node, String currentNode) {
1341 String polyClassName = nodePolymorphicClassName(node);
1342 CodeTreeBuilder builder = parent.create();
1343
1344 builder.startStatement().string("returnNode = ");
1345 builder.startStaticCall(context.getTruffleTypes().getDslShare(), DSLSHARE_REWRITE_TO_POLYMORHPIC);
1346 builder.string("this");
1347 builder.tree(builder.create().startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string(currentNode).end().getRoot());
1348 builder.tree(builder.create().startNew(polyClassName).string(currentNode).end().getRoot());
1349 builder.startGroup().cast(baseClassName(node)).startCall("copy").end().end();
1350 builder.string("newNode");
1351 builder.string("message");
1352 builder.end();
1353 builder.end();
1354
1355 return builder.getRoot();
1356 }
1357
1358 private CodeExecutableElement createCreateSpecializationMethod(NodeData node, SpecializationGroup group) {
1359 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), baseClassName(node)),
1360 SPECIALIZE);
1361 if (!node.needsFrame(getContext())) {
1362 method.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getSlowPath()));
1363 }
1364
1365 addInternalValueParameters(method, node.getGenericSpecialization(), node.needsFrame(getContext()), false);
1366 final CodeTreeBuilder builder = method.createBuilder();
1367 builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, new CodeBlock<SpecializationData>() {
1368
1369 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
1370 return createCreateSpecializationMethodBody0(builder, current);
1371 }
1372 }, null, false, true, false, true));
1373
1374 emitUnreachableSpecializations(builder, node);
1375
1376 return method;
1377 }
1378
1379 protected CodeTree createCreateSpecializationMethodBody0(CodeTreeBuilder parent, SpecializationData current) {
1380 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1381 if (current.isGeneric()) {
1382 builder.startReturn().nullLiteral().end();
1383 } else {
1384 String className = nodeSpecializationClassName(current);
1385 if (!current.getExcludedBy().isEmpty()) {
1386 builder.startIf().string("!").startStaticCall(context.getTruffleTypes().getDslShare(), "isExcluded");
1387 builder.string("this").string(nodeSpecializationClassName(current), ".", METADATA_FIELD_NAME).end().end();
1388 builder.startBlock();
1389 }
1390
1391 if (current.getNode().getGenericSpecialization().isReachable()) {
1392 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
1393 }
1394 builder.startReturn();
1395 builder.cast(baseClassName(getModel().getNode()));
1396 builder.startGroup().startCall(className, FACTORY_METHOD_NAME).string("this");
1397 for (Parameter param : current.getSignatureParameters()) {
1398 NodeChildData child = param.getSpecification().getExecution().getChild();
1399 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
1400 if (types.size() > 1) {
1401 builder.string(implicitTypeName(param));
1402 }
1403 }
1404 builder.end().end();
1405 builder.end();
1406
1407 if (!current.getExcludedBy().isEmpty()) {
1408 builder.end();
1409 }
1410 }
1411 return builder.getRoot();
1412
1413 }
1414
1415 private void emitUnreachableSpecializations(final CodeTreeBuilder builder, NodeData node) {
1416 for (SpecializationData current : node.getSpecializations()) {
1417 if (current.isReachable()) {
1418 continue;
1419 }
1420 builder.string("// unreachable ").string(current.getId()).newLine();
1421 }
1422 }
1423
1424 protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final CodeBlock<SpecializationData> guardedblock,
1425 final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts, final boolean castForGuardsOnly) {
1426 return guard(outerParent, source, group, new CodeBlock<Integer>() {
1427
1428 public CodeTree create(CodeTreeBuilder parent, Integer ifCount) {
1429 CodeTreeBuilder builder = parent.create();
1430
1431 if (group.getSpecialization() != null) {
1432 builder.tree(guardedblock.create(builder, group.getSpecialization()));
1433
1434 assert group.getChildren().isEmpty() : "missed a specialization";
1435
1436 } else {
1437 for (SpecializationGroup childGroup : group.getChildren()) {
1438 builder.tree(createExecuteTree(builder, source, childGroup, guardedblock, null, false, emitAssumptions, typedCasts, castForGuardsOnly));
1439 }
1440 }
1441
1442 return builder.getRoot();
1443 }
1444 }, elseBlock, forceElse, emitAssumptions, typedCasts, castForGuardsOnly);
1445 }
1446
1447 private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, CodeBlock<Integer> bodyBlock, CodeTree elseBlock, boolean forceElse,
1448 boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) {
1449 CodeTreeBuilder builder = parent.create();
1450
1451 int ifCount = emitGuards(builder, source, group, emitAssumptions, typedCasts, castForGuardsOnly);
1452
1453 if (isReachableGroup(group, ifCount)) {
1454 builder.tree(bodyBlock.create(builder, ifCount));
1455 }
1456
1457 builder.end(ifCount);
1458
1459 if (elseBlock != null) {
1460 if (ifCount > 0 || forceElse) {
1461 builder.tree(elseBlock);
1462 }
1463 }
1464
1465 return builder.getRoot();
1466 }
1467
1468 private boolean isReachableGroup(SpecializationGroup group, int ifCount) {
1469 if (ifCount != 0) {
1470 return true;
1471 }
1472 SpecializationGroup previous = group.getPreviousGroup();
1473 if (previous == null || previous.findElseConnectableGuards().isEmpty()) {
1474 return true;
1475 }
1476
1477 /*
1478 * Hacky else case. In this case the specialization is not reachable due to previous
1479 * else branch. This is only true if the minimum state is not checked.
1480 */
1481 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() &&
1482 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) {
1483 return false;
1484 }
1485
1486 return true;
1487 }
1488
1489 private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean emitAssumptions, boolean typedCasts, boolean castForGuardsOnly) {
1490 NodeData node = source.getNode();
1491
1492 CodeTreeBuilder guardsBuilder = builder.create();
1493 CodeTreeBuilder castBuilder = builder.create();
1494 CodeTreeBuilder guardsCastBuilder = builder.create();
1495
1496 String guardsAnd = "";
1497 String guardsCastAnd = "";
1498
1499 if (emitAssumptions) {
1500 for (String assumption : group.getAssumptions()) {
1501 guardsBuilder.string(guardsAnd);
1502 guardsBuilder.string("this");
1503 guardsBuilder.string(".").string(assumption).string(".isValid()");
1504 guardsAnd = " && ";
1505 }
1506 }
1507
1508 for (TypeGuard typeGuard : group.getTypeGuards()) {
1509 Parameter valueParam = source.getSignatureParameter(typeGuard.getSignatureIndex());
1510
1511 if (valueParam == null) {
1512 /*
1513 * If used inside a execute evaluated method then the value param may not exist.
1514 * In that case we assume that the value is executed generic or of the current
1515 * specialization.
1516 */
1517 if (group.getSpecialization() != null) {
1518 valueParam = group.getSpecialization().getSignatureParameter(typeGuard.getSignatureIndex());
1519 } else {
1520 valueParam = node.getGenericSpecialization().getSignatureParameter(typeGuard.getSignatureIndex());
1521 }
1522 }
1523
1524 NodeExecutionData execution = valueParam.getSpecification().getExecution();
1525 CodeTree implicitGuard = createTypeGuard(guardsBuilder, execution, valueParam, typeGuard.getType(), typedCasts);
1526 if (implicitGuard != null) {
1527 guardsBuilder.string(guardsAnd);
1528 guardsBuilder.tree(implicitGuard);
1529 guardsAnd = " && ";
1530 }
1531
1532 CodeTree implicitGetType = null;
1533 if (castForGuardsOnly) {
1534 implicitGetType = createGetImplicitType(builder, execution, valueParam, typeGuard.getType());
1535 }
1536
1537 boolean performCast = true;
1538 if (castForGuardsOnly) {
1539 // if cast for guards we just cast if the type guard is used inside a guard.
1540 performCast = group.isTypeGuardUsedInAnyGuardBelow(context, source, typeGuard);
1541 }
1542
1543 if (performCast) {
1544 CodeTree cast = createCast(castBuilder, execution, valueParam, typeGuard.getType(), typedCasts);
1545 if (cast != null) {
1546 castBuilder.tree(cast);
1547 }
1548 }
1549 if (implicitGetType != null) {
1550 castBuilder.tree(implicitGetType);
1551 }
1552 }
1553 List<GuardExpression> elseGuards = group.findElseConnectableGuards();
1554
1555 for (GuardExpression guard : group.getGuards()) {
1556 if (elseGuards.contains(guard)) {
1557 continue;
1558 }
1559
1560 if (needsTypeGuard(source, group, guard)) {
1561 guardsCastBuilder.tree(createMethodGuard(builder, guardsCastAnd, source, guard));
1562 guardsCastAnd = " && ";
1563 } else {
1564 guardsBuilder.tree(createMethodGuard(builder, guardsAnd, source, guard));
1565 guardsAnd = " && ";
1566 }
1567 }
1568
1569 int ifCount = startGuardIf(builder, guardsBuilder, 0, elseGuards);
1570 builder.tree(castBuilder.getRoot());
1571 ifCount = startGuardIf(builder, guardsCastBuilder, ifCount, elseGuards);
1572 return ifCount;
1573 }
1574
1575 private int startGuardIf(CodeTreeBuilder builder, CodeTreeBuilder conditionBuilder, int ifCount, List<GuardExpression> elseGuard) {
1576 int newIfCount = ifCount;
1577
1578 if (!conditionBuilder.isEmpty()) {
1579 if (ifCount == 0 && !elseGuard.isEmpty()) {
1580 builder.startElseIf();
1581 } else {
1582 builder.startIf();
1583 }
1584 builder.tree(conditionBuilder.getRoot());
1585 builder.end().startBlock();
1586 newIfCount++;
1587 } else if (ifCount == 0 && !elseGuard.isEmpty()) {
1588 builder.startElseBlock();
1589 newIfCount++;
1590 }
1591 return newIfCount;
1592 }
1593
1594 private boolean needsTypeGuard(SpecializationData source, SpecializationGroup group, GuardExpression guard) {
1595 int signatureIndex = 0;
1596 for (Parameter parameter : guard.getResolvedGuard().getParameters()) {
1597 if (!parameter.getSpecification().isSignature()) {
1598 continue;
1599 }
1600
1601 TypeGuard typeGuard = group.findTypeGuard(signatureIndex);
1602 if (typeGuard != null) {
1603 TypeData requiredType = typeGuard.getType();
1604
1605 Parameter sourceParameter = source.findParameter(parameter.getLocalName());
1606 if (sourceParameter == null) {
1607 sourceParameter = source.getNode().getGenericSpecialization().findParameter(parameter.getLocalName());
1608 }
1609
1610 if (ElementUtils.needsCastTo(sourceParameter.getType(), requiredType.getPrimitiveType())) {
1611 return true;
1612 }
1613 }
1614
1615 signatureIndex++;
1616 }
1617 return false;
1618 }
1619
1620 private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) {
1621 NodeData node = execution.getChild().getNodeData();
1622
1623 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1624
1625 TypeData sourceType = source.getTypeSystemType();
1626
1627 if (!sourceType.needsCastTo(targetType)) {
1628 return null;
1629 }
1630
1631 builder.startGroup();
1632
1633 if (execution.isShortCircuit()) {
1634 Parameter shortCircuit = source.getPreviousParameter();
1635 assert shortCircuit != null;
1636 builder.string("(");
1637 builder.string("!").string(valueName(shortCircuit));
1638 builder.string(" || ");
1639 }
1640
1641 String castMethodName;
1642 String castTypeName = null;
1643 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
1644 if (types.size() > 1) {
1645 castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType);
1646 if (typedCasts) {
1647 castTypeName = implicitTypeName(source);
1648 }
1649 } else {
1650 castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType);
1651 }
1652
1653 startCallTypeSystemMethod(builder, node.getTypeSystem(), castMethodName);
1654 builder.string(valueName(source));
1655 if (castTypeName != null) {
1656 builder.string(castTypeName);
1657 }
1658 builder.end().end(); // call
1659
1660 if (execution.isShortCircuit()) {
1661 builder.string(")");
1662 }
1663
1664 builder.end(); // group
1665
1666 return builder.getRoot();
1667 }
1668
1669 // TODO merge redundancies with #createTypeGuard
1670 private CodeTree createCast(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType, boolean typedCasts) {
1671 NodeData node = execution.getChild().getNodeData();
1672 TypeData sourceType = source.getTypeSystemType();
1673
1674 if (!sourceType.needsCastTo(targetType)) {
1675 return null;
1676 }
1677
1678 CodeTree condition = null;
1679 if (execution.isShortCircuit()) {
1680 Parameter shortCircuit = source.getPreviousParameter();
1681 assert shortCircuit != null;
1682 condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
1683 }
1684
1685 String castMethodName;
1686 String castTypeName = null;
1687 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
1688 if (types.size() > 1) {
1689 castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType);
1690 if (typedCasts) {
1691 castTypeName = implicitTypeName(source);
1692 }
1693 } else {
1694 castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
1695 }
1696
1697 List<CodeTree> args = new ArrayList<>();
1698 args.add(CodeTreeBuilder.singleString(valueName(source)));
1699 if (castTypeName != null) {
1700 args.add(CodeTreeBuilder.singleString(castTypeName));
1701 }
1702
1703 CodeTree cast = createCallTypeSystemMethod(parent, node, castMethodName, args.toArray(new CodeTree[0]));
1704
1705 CodeTreeBuilder builder = parent.create();
1706 builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, cast));
1707
1708 return builder.getRoot();
1709 }
1710
1711 private CodeTree createGetImplicitType(CodeTreeBuilder parent, NodeExecutionData execution, Parameter source, TypeData targetType) {
1712 CodeTree condition = null;
1713 if (execution.isShortCircuit()) {
1714 Parameter shortCircuit = source.getPreviousParameter();
1715 assert shortCircuit != null;
1716 condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
1717 }
1718
1719 CodeTreeBuilder builder = parent.create();
1720 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
1721 if (types.size() > 1) {
1722 CodeTree castType = createCallTypeSystemMethod(parent, execution.getChild().getNodeData(), TypeSystemCodeGenerator.getImplicitClass(targetType),
1723 CodeTreeBuilder.singleString(valueName(source)));
1724 builder.tree(createLazyAssignment(builder, implicitTypeName(source), getContext().getType(Class.class), condition, castType));
1725 }
1726 return builder.getRoot();
1727 }
1728
1729 private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardExpression guard) {
1730 CodeTreeBuilder builder = parent.create();
1731 builder.string(prefix);
1732 if (guard.isNegated()) {
1733 builder.string("!");
1734 }
1735 builder.tree(createTemplateMethodCall(builder, null, source, guard.getResolvedGuard(), null));
1736 return builder.getRoot();
1737 }
1738
1739 protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) {
1740 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1741
1742 if (current.getMethod() == null) {
1743 emitEncounteredSynthetic(builder, current);
1744 } else {
1745 builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end();
1746 }
1747
1748 return encloseThrowsWithFallThrough(current, builder.getRoot());
1749 }
1750
1751 private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) {
1752 if (current.getExceptions().isEmpty()) {
1753 return tree;
1754 }
1755 CodeTreeBuilder builder = new CodeTreeBuilder(null);
1756
1757 builder.startTryBlock();
1758 builder.tree(tree);
1759 for (SpecializationThrowsData exception : current.getExceptions()) {
1760 builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx");
1761 builder.tree(createDeoptimize(builder));
1762 builder.tree(createCallRewriteMonomorphic(builder, false, current.getNode().getGenericSpecialization().getReturnType().getTypeSystemType(), current, null,
1763 "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass())));
1764 }
1765 builder.end();
1766
1767 return builder.getRoot();
1768 }
1769
1770 protected CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) {
1771 TypeData type = executable.getType();
1772 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1773 NodeData node = specialization.getNode();
1774
1775 TypeData primaryType = castExecutable.getType();
1776
1777 boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
1778 boolean returnVoid = type.isVoid();
1779
1780 List<Parameter> executeParameters = new ArrayList<>();
1781 for (Parameter sourceParameter : executable.getSignatureParameters()) {
1782 Parameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
1783 if (targetParameter != null) {
1784 executeParameters.add(targetParameter);
1785 }
1786 }
1787
1788 // execute names are enforced no cast
1789 String[] executeParameterNames = new String[executeParameters.size()];
1790 for (int i = 0; i < executeParameterNames.length; i++) {
1791 executeParameterNames[i] = valueName(executeParameters.get(i));
1792 }
1793
1794 builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null));
1795 boolean hasUnexpected = executable.hasUnexpectedValue(getContext());
1796
1797 CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null, executeParameterNames);
1798 if (needsTry) {
1799 if (!returnVoid) {
1800 builder.declaration(primaryType.getPrimitiveType(), "value");
1801 }
1802 builder.startTryBlock();
1803
1804 if (returnVoid) {
1805 builder.statement(primaryExecuteCall);
1806 } else {
1807 builder.startStatement();
1808 builder.string("value = ");
1809 builder.tree(primaryExecuteCall);
1810 builder.end();
1811 }
1812
1813 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
1814 if (returnVoid) {
1815 builder.string("// ignore").newLine();
1816 } else {
1817 builder.startReturn();
1818 builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), hasUnexpected, executable.getType(),
1819 CodeTreeBuilder.singleString("ex.getResult()")));
1820 builder.end();
1821 }
1822 builder.end();
1823
1824 if (!returnVoid) {
1825 builder.startReturn();
1826 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), CodeTreeBuilder.singleString("value")));
1827 builder.end();
1828 }
1829 } else {
1830 if (returnVoid) {
1831 builder.statement(primaryExecuteCall);
1832 } else {
1833 builder.startReturn();
1834 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), hasUnexpected, executable.getType(), primaryExecuteCall));
1835 builder.end();
1836 }
1837 }
1838
1839 return builder.getRoot();
1840 }
1841
1842 protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, boolean hasUnexpected, TypeData exepctedType, CodeTree value) {
1843 return createCastType(node.getTypeSystem(), sourceType, exepctedType, hasUnexpected, value);
1844 }
1845
1846 protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<Parameter> targetParameters,
1847 Parameter unexpectedParameter) {
1848 CodeTreeBuilder builder = parent.create();
1849 for (Parameter targetParameter : targetParameters) {
1850 if (!targetParameter.getSpecification().isSignature()) {
1851 continue;
1852 }
1853 NodeExecutionData execution = targetParameter.getSpecification().getExecution();
1854 CodeTree executionExpressions = createExecuteChild(builder, execution, sourceExecutable, targetParameter, unexpectedParameter);
1855 CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, specialization, sourceExecutable, targetParameter, execution.isShortCircuit(), unexpectedParameter);
1856 CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, specialization, targetParameter, unexpectedParameter);
1857
1858 if (shortCircuitTree == executionExpressions) {
1859 if (containsNewLine(executionExpressions)) {
1860 builder.declaration(targetParameter.getType(), valueName(targetParameter));
1861 builder.tree(shortCircuitTree);
1862 } else {
1863 builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end();
1864 }
1865 } else {
1866 builder.tree(shortCircuitTree);
1867 }
1868
1869 }
1870 return builder.getRoot();
1871 }
1872
1873 private ExecutableTypeData resolveExecutableType(NodeExecutionData execution, TypeData type) {
1874 ExecutableTypeData targetExecutable = execution.getChild().findExecutableType(getContext(), type);
1875 if (targetExecutable == null) {
1876 targetExecutable = execution.getChild().findAnyGenericExecutableType(getContext());
1877 }
1878 return targetExecutable;
1879 }
1880
1881 private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter targetParameter, Parameter unexpectedParameter) {
1882 SpecializationData specialization = getModel();
1883 TreeSet<TypeData> possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter);
1884 if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null && possiblePolymorphicTypes.size() > 1) {
1885
1886 CodeTreeBuilder builder = parent.create();
1887
1888 boolean elseIf = false;
1889 for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) {
1890 if (possiblePolymoprhicType.isGeneric()) {
1891 continue;
1892 }
1893 elseIf = builder.startIf(elseIf);
1894
1895 Parameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
1896 TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
1897 builder.string(polymorphicTypeName(targetParameter.getSpecification().getExecution())).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType());
1898 builder.end().startBlock();
1899 builder.startStatement();
1900 builder.tree(createExecuteChildExpression(parent, execution, sourceType, new Parameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null));
1901 builder.end();
1902 builder.end();
1903 }
1904
1905 builder.startElseBlock();
1906 builder.startStatement().tree(createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter)).end();
1907 builder.end();
1908
1909 return builder.getRoot();
1910 } else {
1911 return createExecuteChildImplicit(parent, execution, sourceExecutable, targetParameter, unexpectedParameter);
1912 }
1913 }
1914
1915 protected final List<Parameter> getImplicitTypeParameters(SpecializationData model) {
1916 List<Parameter> parameter = new ArrayList<>();
1917 for (Parameter param : model.getSignatureParameters()) {
1918 NodeChildData child = param.getSpecification().getExecution().getChild();
1919 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
1920 if (types.size() > 1) {
1921 parameter.add(param);
1922 }
1923 }
1924 return parameter;
1925 }
1926
1927 protected final TreeSet<TypeData> lookupPolymorphicTargetTypes(Parameter param) {
1928 SpecializationData specialization = getModel();
1929 TreeSet<TypeData> possiblePolymorphicTypes = new TreeSet<>();
1930 for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) {
1931 if (!otherSpecialization.isSpecialized()) {
1932 continue;
1933 }
1934 Parameter otherParameter = otherSpecialization.findParameter(param.getLocalName());
1935 if (otherParameter != null) {
1936 possiblePolymorphicTypes.add(otherParameter.getTypeSystemType());
1937 }
1938 }
1939 return possiblePolymorphicTypes;
1940 }
1941
1942 private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData sourceExecutable, Parameter param, Parameter unexpectedParameter) {
1943 CodeTreeBuilder builder = parent.create();
1944 Parameter sourceParameter = sourceExecutable.findParameter(param.getLocalName());
1945 String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null);
1946 if (childExecuteName != null) {
1947 builder.string(valueName(param));
1948 builder.string(" = ");
1949 builder.startCall(childExecuteName);
1950
1951 for (Parameter parameters : sourceExecutable.getParameters()) {
1952 if (parameters.getSpecification().isSignature()) {
1953 continue;
1954 }
1955 builder.string(parameters.getLocalName());
1956 }
1957
1958 if (sourceParameter != null) {
1959 builder.string(valueNameEvaluated(sourceParameter));
1960 }
1961
1962 builder.string(implicitTypeName(param));
1963
1964 builder.end();
1965 } else {
1966 List<TypeData> sourceTypes = execution.getChild().getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
1967 TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
1968 if (sourceTypes.size() > 1) {
1969 builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType));
1970 } else {
1971 builder.tree(createExecuteChildExpression(parent, execution, expectType, param, unexpectedParameter, null));
1972 }
1973 }
1974 return builder.getRoot();
1975 }
1976
1977 private String createExecuteChildMethodName(Parameter param, boolean expect) {
1978 NodeExecutionData execution = param.getSpecification().getExecution();
1979 NodeChildData child = execution.getChild();
1980 if (child.getExecuteWith().size() > 0) {
1981 return null;
1982 }
1983 List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
1984 if (sourceTypes.size() <= 1) {
1985 return null;
1986 }
1987 String prefix = expect ? "expect" : "execute";
1988 String suffix = execution.getIndex() > -1 ? String.valueOf(execution.getIndex()) : "";
1989 return prefix + ElementUtils.firstLetterUpperCase(child.getName()) + ElementUtils.firstLetterUpperCase(ElementUtils.getSimpleName(param.getType())) + suffix;
1990 }
1991
1992 private List<CodeExecutableElement> createExecuteChilds(Parameter param, Set<TypeData> expectTypes) {
1993 CodeExecutableElement executeMethod = createExecuteChild(param, null);
1994 if (executeMethod == null) {
1995 return Collections.emptyList();
1996 }
1997 List<CodeExecutableElement> childs = new ArrayList<>();
1998 childs.add(executeMethod);
1999
2000 for (TypeData expectType : expectTypes) {
2001 CodeExecutableElement method = createExecuteChild(param, expectType);
2002 if (method != null) {
2003 childs.add(method);
2004 }
2005 }
2006 return childs;
2007 }
2008
2009 private CodeExecutableElement createExecuteChild(Parameter param, TypeData expectType) {
2010 String childExecuteName = createExecuteChildMethodName(param, expectType != null);
2011 if (childExecuteName == null) {
2012 return null;
2013 }
2014
2015 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, expectType != null ? STATIC : FINAL), param.getType(), childExecuteName);
2016 method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException());
2017 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
2018 if (expectType != null) {
2019 method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param)));
2020 }
2021 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
2022
2023 CodeTreeBuilder builder = method.createBuilder();
2024 builder.declaration(param.getType(), valueName(param));
2025 builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType));
2026 builder.startReturn().string(valueName(param)).end();
2027
2028 return method;
2029 }
2030
2031 private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, Parameter targetParameter, TypeData expectType) {
2032 CodeTreeBuilder builder = parent.create();
2033 NodeData node = getModel().getNode();
2034 NodeExecutionData execution = targetParameter.getSpecification().getExecution();
2035 List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType());
2036 boolean elseIf = false;
2037 int index = 0;
2038 for (TypeData sourceType : sourceTypes) {
2039 if (index < sourceTypes.size() - 1) {
2040 elseIf = builder.startIf(elseIf);
2041 builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType());
2042 builder.end();
2043 builder.startBlock();
2044 } else {
2045 builder.startElseBlock();
2046 }
2047
2048 ExecutableTypeData implictExecutableTypeData = execution.getChild().findExecutableType(getContext(), sourceType);
2049 if (implictExecutableTypeData == null) {
2050 /*
2051 * For children with executeWith.size() > 0 an executable type may not exist so
2052 * use the generic executable type which is guaranteed to exist. An expect call
2053 * is inserted automatically by #createExecuteExpression.
2054 */
2055 implictExecutableTypeData = execution.getChild().getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), execution.getChild().getExecuteWith().size());
2056 }
2057
2058 ImplicitCastData cast = execution.getChild().getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType());
2059 CodeTree execute = createExecuteChildExpression(builder, execution, expectType, targetParameter, null, cast);
2060 builder.statement(execute);
2061 builder.end();
2062 index++;
2063 }
2064 return builder.getRoot();
2065 }
2066
2067 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData execution, TypeData sourceParameterType, Parameter targetParameter, Parameter unexpectedParameter,
2068 ImplicitCastData cast) {
2069 // assignments: targetType <- castTargetType <- castSourceType <- sourceType
2070 TypeData sourceType = sourceParameterType;
2071 TypeData targetType = targetParameter.getTypeSystemType();
2072 TypeData castSourceType = targetType;
2073 TypeData castTargetType = targetType;
2074
2075 if (cast != null) {
2076 castSourceType = cast.getSourceType();
2077 castTargetType = cast.getTargetType();
2078 }
2079
2080 CodeTree expression;
2081 if (sourceType == null) {
2082 ExecutableTypeData targetExecutable = resolveExecutableType(execution, castSourceType);
2083 expression = createExecuteChildExpression(parent, execution, targetExecutable, unexpectedParameter);
2084 sourceType = targetExecutable.getType();
2085 } else {
2086 expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter));
2087 }
2088
2089 // target = expectTargetType(implicitCast(expectCastSourceType(source)))
2090 TypeSystemData typeSystem = execution.getChild().getNodeData().getTypeSystem();
2091 expression = createExpectType(typeSystem, sourceType, castSourceType, expression);
2092 expression = createImplicitCast(parent, typeSystem, cast, expression);
2093 expression = createExpectType(typeSystem, castTargetType, targetType, expression);
2094
2095 CodeTreeBuilder builder = parent.create();
2096 builder.string(valueName(targetParameter));
2097 builder.string(" = ");
2098 builder.tree(expression);
2099 return builder.getRoot();
2100 }
2101
2102 private CodeTree createImplicitCast(CodeTreeBuilder parent, TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) {
2103 if (cast == null) {
2104 return expression;
2105 }
2106 CodeTreeBuilder builder = parent.create();
2107 startCallTypeSystemMethod(builder, typeSystem, cast.getMethodName());
2108 builder.tree(expression);
2109 builder.end().end();
2110 return builder.getRoot();
2111 }
2112
2113 private boolean containsNewLine(CodeTree tree) {
2114 if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) {
2115 return true;
2116 }
2117
2118 for (CodeTree codeTree : tree.getEnclosedElements()) {
2119 if (containsNewLine(codeTree)) {
2120 return true;
2121 }
2122 }
2123 return false;
2124 }
2125
2126 private boolean hasUnexpected(Parameter sourceParameter, Parameter targetParameter, Parameter unexpectedParameter) {
2127 NodeExecutionData execution = targetParameter.getSpecification().getExecution();
2128
2129 if (getModel().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) {
2130 // check for other polymorphic types
2131 TreeSet<TypeData> polymorphicTargetTypes = lookupPolymorphicTargetTypes(targetParameter);
2132 if (polymorphicTargetTypes.size() > 1) {
2133 for (TypeData polymorphicTargetType : polymorphicTargetTypes) {
2134 if (hasUnexpectedType(execution, sourceParameter, polymorphicTargetType)) {
2135 return true;
2136 }
2137 }
2138 }
2139 }
2140
2141 if (hasUnexpectedType(execution, sourceParameter, targetParameter.getTypeSystemType())) {
2142 return true;
2143 }
2144 return false;
2145 }
2146
2147 private boolean hasUnexpectedType(NodeExecutionData execution, Parameter sourceParameter, TypeData targetType) {
2148 List<TypeData> implicitSourceTypes = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
2149
2150 for (TypeData implicitSourceType : implicitSourceTypes) {
2151 TypeData sourceType;
2152 ExecutableTypeData targetExecutable = resolveExecutableType(execution, implicitSourceType);
2153 if (sourceParameter != null) {
2154 sourceType = sourceParameter.getTypeSystemType();
2155 } else {
2156 if (targetExecutable.hasUnexpectedValue(getContext())) {
2157 return true;
2158 }
2159 sourceType = targetExecutable.getType();
2160 }
2161
2162 ImplicitCastData cast = getModel().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType);
2163 if (cast != null) {
2164 if (cast.getSourceType().needsCastTo(targetType)) {
2165 return true;
2166 }
2167 }
2168
2169 if (sourceType.needsCastTo(targetType)) {
2170 return true;
2171 }
2172 }
2173 return false;
2174 }
2175
2176 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ExecutableTypeData currentExecutable, Parameter param,
2177 boolean shortCircuit, Parameter unexpectedParameter) {
2178 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2179 Parameter sourceParameter = currentExecutable.findParameter(param.getLocalName());
2180 boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter);
2181 if (!unexpected) {
2182 return body;
2183 }
2184
2185 if (!shortCircuit) {
2186 builder.declaration(param.getType(), valueName(param));
2187 }
2188 builder.startTryBlock();
2189
2190 if (containsNewLine(body)) {
2191 builder.tree(body);
2192 } else {
2193 builder.statement(body);
2194 }
2195
2196 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
2197 SpecializationData generic = specialization.getNode().getGenericSpecialization();
2198 Parameter genericParameter = generic.findParameter(param.getLocalName());
2199
2200 List<Parameter> genericParameters = generic.getParametersAfter(genericParameter);
2201 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter));
2202 if (specialization.isPolymorphic()) {
2203 builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param));
2204 } else {
2205 builder.tree(createCallRewriteMonomorphic(builder, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), specialization, param,
2206 "Expected " + param.getLocalName() + " instanceof " + ElementUtils.getSimpleName(param.getType())));
2207 }
2208 builder.end(); // catch block
2209
2210 return builder.getRoot();
2211 }
2212
2213 private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, ExecutableTypeData currentExecutable, SpecializationData specialization, Parameter param) {
2214 NodeData node = specialization.getNode();
2215 SpecializationData polymorphic = node.getPolymorphicSpecialization();
2216
2217 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2218 builder.startStatement().string(polymorphicTypeName(param.getSpecification().getExecution())).string(" = ").typeLiteral(getContext().getType(Object.class)).end();
2219
2220 builder.startReturn();
2221
2222 CodeTreeBuilder execute = new CodeTreeBuilder(builder);
2223 execute.startCall("next0", EXECUTE_CHAINED);
2224 addInternalValueParameterNames(execute, specialization, polymorphic, param.getLocalName(), true, null);
2225 execute.end();
2226
2227 TypeData sourceType = polymorphic.getReturnType().getTypeSystemType();
2228
2229 builder.tree(createExpectExecutableType(node, sourceType, currentExecutable.hasUnexpectedValue(context), currentExecutable.getType(), execute.getRoot()));
2230
2231 builder.end();
2232 return builder.getRoot();
2233 }
2234
2235 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeExecutionData targetExecution, ExecutableTypeData targetExecutable, Parameter unexpectedParameter) {
2236 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2237 if (targetExecution != null) {
2238 builder.tree(createAccessChild(targetExecution, null));
2239 builder.string(".");
2240 }
2241
2242 builder.startCall(targetExecutable.getMethodName());
2243
2244 // TODO this should be merged with #createTemplateMethodCall
2245 int index = 0;
2246 for (Parameter parameter : targetExecutable.getParameters()) {
2247
2248 if (!parameter.getSpecification().isSignature()) {
2249 builder.string(parameter.getLocalName());
2250 } else {
2251
2252 if (index < targetExecution.getChild().getExecuteWith().size()) {
2253 NodeChildData child = targetExecution.getChild().getExecuteWith().get(index);
2254
2255 ParameterSpec spec = getModel().getSpecification().findParameterSpec(child.getName());
2256 List<Parameter> specializationParams = getModel().findParameters(spec);
2257
2258 if (specializationParams.isEmpty()) {
2259 builder.defaultValue(parameter.getType());
2260 continue;
2261 }
2262
2263 Parameter specializationParam = specializationParams.get(0);
2264
2265 TypeData targetType = parameter.getTypeSystemType();
2266 TypeData sourceType = specializationParam.getTypeSystemType();
2267 String localName = specializationParam.getLocalName();
2268
2269 if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) {
2270 localName = "ex.getResult()";
2271 sourceType = getModel().getNode().getTypeSystem().getGenericTypeData();
2272 }
2273
2274 CodeTree value = CodeTreeBuilder.singleString(localName);
2275
2276 if (sourceType.needsCastTo(targetType)) {
2277 value = createCallTypeSystemMethod(builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value);
2278 }
2279 builder.tree(value);
2280 } else {
2281 builder.defaultValue(parameter.getType());
2282 }
2283 index++;
2284 }
2285 }
2286
2287 builder.end();
2288
2289 return builder.getRoot();
2290 }
2291
2292 private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, Parameter parameter, Parameter exceptionParam) {
2293 NodeExecutionData execution = parameter.getSpecification().getExecution();
2294 if (execution == null || !execution.isShortCircuit()) {
2295 return body;
2296 }
2297
2298 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2299 Parameter shortCircuitParam = specialization.getPreviousParam(parameter);
2300 builder.tree(createShortCircuitValue(builder, specialization, execution, shortCircuitParam, exceptionParam));
2301 builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
2302 builder.startIf().string(shortCircuitParam.getLocalName()).end();
2303 builder.startBlock();
2304
2305 if (containsNewLine(body)) {
2306 builder.tree(body);
2307 } else {
2308 builder.statement(body);
2309 }
2310 builder.end();
2311
2312 return builder.getRoot();
2313 }
2314
2315 private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeExecutionData execution, Parameter shortCircuitParam, Parameter exceptionParam) {
2316 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2317 int shortCircuitIndex = 0;
2318 for (NodeExecutionData otherExectuion : specialization.getNode().getChildExecutions()) {
2319 if (otherExectuion.isShortCircuit()) {
2320 if (otherExectuion == execution) {
2321 break;
2322 }
2323 shortCircuitIndex++;
2324 }
2325 }
2326
2327 builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
2328 ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
2329 builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
2330 builder.end(); // statement
2331
2332 return builder.getRoot();
2333 }
2334
2335 protected CodeTree createCallRewriteMonomorphic(CodeTreeBuilder parent, boolean hasUnexpected, TypeData returnType, SpecializationData current, Parameter exceptionParam, String reason) {
2336 NodeData node = current.getNode();
2337 SpecializationData generic = node.getGenericSpecialization();
2338 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
2339 specializeCall.startCall(REWRITE);
2340 addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, null);
2341 specializeCall.doubleQuote(reason);
2342 specializeCall.end().end();
2343
2344 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2345
2346 builder.startReturn();
2347 builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), hasUnexpected, returnType, specializeCall.getRoot()));
2348 builder.end();
2349
2350 return builder.getRoot();
2351 }
2352
2353 }
2354
2355 private class PolymorphicNodeFactory extends SpecializedNodeFactory {
2356
2357 public PolymorphicNodeFactory(CodeTypeElement nodeGen) {
2358 super(nodeGen);
2359 }
2360
2361 @Override
2362 public CodeTypeElement create(SpecializationData polymorph) {
2363 NodeData node = polymorph.getNode();
2364 TypeMirror baseType = node.getNodeType();
2365 if (nodeGen != null) {
2366 baseType = nodeGen.asType();
2367 }
2368 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node), baseType, false);
2369
2370 clazz.getAnnotationMirrors().add(createNodeInfo(node, NodeCost.POLYMORPHIC));
2371
2372 for (Parameter polymorphParameter : polymorph.getSignatureParameters()) {
2373 if (!polymorphParameter.getTypeSystemType().isGeneric()) {
2374 continue;
2375 }
2376 Set<TypeData> types = new HashSet<>();
2377 for (SpecializationData specialization : node.getSpecializations()) {
2378 if (!specialization.isSpecialized()) {
2379 continue;
2380 }
2381 Parameter parameter = specialization.findParameter(polymorphParameter.getLocalName());
2382 assert parameter != null;
2383 types.add(parameter.getTypeSystemType());
2384 }
2385
2386 }
2387
2388 for (NodeExecutionData execution : getModel().getNode().getChildExecutions()) {
2389 String fieldName = polymorphicTypeName(execution);
2390 CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), getContext().getType(Class.class), fieldName);
2391 var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getCompilationFinal()));
2392 clazz.add(var);
2393 }
2394
2395 return clazz;
2396 }
2397
2398 @Override
2399 protected void createChildren(SpecializationData specialization) {
2400 CodeTypeElement clazz = getElement();
2401
2402 createConstructors(clazz);
2403 createExecuteMethods(specialization);
2404
2405 clazz.add(createUpdateTypes0());
2406 createCachedExecuteMethods(specialization);
2407 }
2408
2409 }
2410
2411 private class SpecializedNodeFactory extends NodeBaseFactory {
2412
2413 protected final CodeTypeElement nodeGen;
2414
2415 public SpecializedNodeFactory(CodeTypeElement nodeGen) {
2416 this.nodeGen = nodeGen;
2417 }
2418
2419 @Override
2420 public CodeTypeElement create(SpecializationData specialization) {
2421 NodeData node = specialization.getNode();
2422 TypeMirror baseType = node.getNodeType();
2423 if (nodeGen != null) {
2424 baseType = nodeGen.asType();
2425 }
2426 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false);
2427
2428 if (specialization.isSpecialized() || specialization.isUninitialized()) {
2429 clazz.add(createGetMetadata0(false));
2430 clazz.add(createMetadataLiteral());
2431 }
2432
2433 NodeCost cost;
2434 if (specialization.isGeneric()) {
2435 cost = NodeCost.MEGAMORPHIC;
2436 } else if (specialization.isUninitialized()) {
2437 cost = NodeCost.UNINITIALIZED;
2438 } else if (specialization.isPolymorphic()) {
2439 cost = NodeCost.POLYMORPHIC;
2440 } else if (specialization.isSpecialized()) {
2441 cost = NodeCost.MONOMORPHIC;
2442 } else {
2443 throw new AssertionError();
2444 }
2445 clazz.getAnnotationMirrors().add(createNodeInfo(node, cost));
2446
2447 if (specialization.isUninitialized() && node.getGenericSpecialization().isReachable()) {
2448 clazz.add(createUninitializedGetCostOverride());
2449 }
2450
2451 return clazz;
2452 }
2453
2454 private Element createUninitializedGetCostOverride() {
2455 TypeMirror returnType = context.getTruffleTypes().getNodeCost();
2456 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost");
2457 CodeTreeBuilder builder = method.createBuilder();
2458 builder.startIf().string(CONTAINS_FALLBACK).end().startBlock();
2459 builder.startReturn().staticReference(returnType, "MONOMORPHIC").end();
2460 builder.end();
2461 builder.startReturn().string("super.getCost()").end();
2462 return method;
2463 }
2464
2465 private CodeVariableElement createMetadataLiteral() {
2466 CodeVariableElement includes = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), context.getTruffleTypes().getDslMetadata(), METADATA_FIELD_NAME);
2467
2468 CodeTreeBuilder builder = includes.createInitBuilder();
2469
2470 SpecializationData specialization = getModel();
2471 NodeData node = specialization.getNode();
2472
2473 Set<SpecializationData> contains = specialization.getContains();
2474 if (specialization.isUninitialized()) {
2475 contains = new HashSet<>();
2476
2477 SpecializationData polymorphic = node.getPolymorphicSpecialization();
2478 if (polymorphic != null) {
2479 contains.addAll(polymorphic.getContains());
2480 }
2481 SpecializationData generic = node.getGenericSpecialization();
2482 if (generic != null) {
2483 contains.addAll(generic.getContains());
2484 }
2485 }
2486
2487 builder.startNew(context.getTruffleTypes().getDslMetadata());
2488 builder.startGroup().string(nodeSpecializationClassName(getModel()), ".class").end();
2489 builder.tree(createSpecializationListLiteral(builder, contains));
2490 builder.tree(createSpecializationListLiteral(builder, getModel().getExcludedBy()));
2491 builder.tree(createSpecializationTypeLiteral(builder, SpecializationData.getSignatureTypes(getModel())));
2492 builder.string("0").string("0");
2493 builder.end();
2494 return includes;
2495 }
2496
2497 private CodeTree createSpecializationTypeLiteral(CodeTreeBuilder parent, List<TypeMirror> list) {
2498 ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
2499 CodeTreeBuilder builder = parent.create();
2500
2501 if (list.isEmpty()) {
2502 builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
2503 } else {
2504 builder.startNewArray(classArray, null);
2505 for (TypeMirror type : list) {
2506 builder.typeLiteral(type);
2507 }
2508 builder.end();
2509 }
2510
2511 return builder.getRoot();
2512 }
2513
2514 private CodeTree createSpecializationListLiteral(CodeTreeBuilder parent, Set<SpecializationData> list) {
2515 ArrayType classArray = new ArrayCodeTypeMirror(context.getType(Class.class));
2516 CodeTreeBuilder builder = parent.create();
2517
2518 if (list.isEmpty()) {
2519 builder.staticReference(context.getTruffleTypes().getDslMetadata(), EMPTY_CLASS_ARRAY);
2520 } else {
2521 builder.startNewArray(classArray, null);
2522 for (SpecializationData specialization : list) {
2523 if (specialization.isGeneric() || specialization.isPolymorphic()) {
2524 specialization = getModel().getNode().getUninitializedSpecialization();
2525 }
2526 builder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end();
2527 }
2528 builder.end();
2529 }
2530
2531 return builder.getRoot();
2532 }
2533
2534 protected CodeAnnotationMirror createNodeInfo(NodeData node, NodeCost cost) {
2535 String shortName = node.getShortName();
2536 CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation());
2537 if (shortName != null) {
2538 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName));
2539 }
2540
2541 DeclaredType nodeinfoCost = getContext().getTruffleTypes().getNodeCost();
2542 VariableElement varKind = ElementUtils.findVariableElement(nodeinfoCost, cost.name());
2543
2544 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("cost"), new CodeAnnotationValue(varKind));
2545 return nodeInfoMirror;
2546 }
2547
2548 @Override
2549 protected void createChildren(SpecializationData specialization) {
2550 CodeTypeElement clazz = getElement();
2551 createConstructors(clazz);
2552
2553 createExecuteMethods(specialization);
2554 createCachedExecuteMethods(specialization);
2555
2556 if (specialization.isUninitialized()) {
2557 if (specialization.getNode().isFallbackReachable()) {
2558 CodeVariableElement var = new CodeVariableElement(modifiers(Modifier.PRIVATE), context.getType(boolean.class), CONTAINS_FALLBACK);
2559 var.addAnnotationMirror(new CodeAnnotationMirror(context.getTruffleTypes().getCompilationFinal()));
2560 clazz.add(var);
2561 }
2562 clazz.add(createExecuteUninitialized());
2563 }
2564
2565 if (!specialization.isUninitialized() && specialization.getNode().needsRewrites(context)) {
2566 clazz.add(createCopyConstructorFactoryMethod(nodeGen.asType(), specialization));
2567 } else {
2568 for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
2569 if (constructor.getParameters().size() == 1 && ((CodeVariableElement) constructor.getParameters().get(0)).getType().equals(nodeGen.asType())) {
2570 // skip copy constructor - not used
2571 continue;
2572 }
2573 clazz.add(createConstructorFactoryMethod(specialization, constructor));
2574 }
2575 }
2576 }
2577
2578 protected void createConstructors(CodeTypeElement clazz) {
2579 TypeElement superTypeElement = ElementUtils.fromTypeMirror(clazz.getSuperclass());
2580 SpecializationData specialization = getModel();
2581 NodeData node = specialization.getNode();
2582 for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) {
2583 if (specialization.isUninitialized()) {
2584 // ignore copy constructors for uninitialized if not polymorphic
2585 if (isCopyConstructor(constructor) && !node.isPolymorphic(context)) {
2586 continue;
2587 }
2588 } else if (node.getUninitializedSpecialization() != null) {
2589 // ignore others than copy constructors for specialized nodes
2590 if (!isCopyConstructor(constructor)) {
2591 continue;
2592 }
2593 }
2594
2595 CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor);
2596 if (superConstructor == null) {
2597 continue;
2598 }
2599 CodeTree body = superConstructor.getBodyTree();
2600 CodeTreeBuilder builder = superConstructor.createBuilder();
2601 builder.tree(body);
2602
2603 if (superConstructor != null) {
2604 for (Parameter param : getImplicitTypeParameters(getModel())) {
2605 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
2606 superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
2607
2608 builder.startStatement();
2609 builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
2610 builder.end();
2611 }
2612
2613 clazz.add(superConstructor);
2614 }
2615 }
2616 }
2617
2618 protected void createExecuteMethods(SpecializationData specialization) {
2619 NodeData node = specialization.getNode();
2620 CodeTypeElement clazz = getElement();
2621
2622 for (ExecutableTypeData execType : node.getExecutableTypes()) {
2623 if (execType.isFinal()) {
2624 continue;
2625 }
2626 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true);
2627 clazz.add(executeMethod);
2628 CodeTreeBuilder builder = executeMethod.getBuilder();
2629 CodeTree result = createExecuteBody(builder, specialization, execType);
2630 if (result != null) {
2631 builder.tree(result);
2632 } else {
2633 clazz.remove(executeMethod);
2634 }
2635 }
2636 }
2637
2638 protected void createCachedExecuteMethods(SpecializationData specialization) {
2639 NodeData node = specialization.getNode();
2640 if (!node.isPolymorphic(context)) {
2641 return;
2642 }
2643
2644 CodeTypeElement clazz = getElement();
2645
2646 final SpecializationData polymorphic = node.getPolymorphicSpecialization();
2647 ExecutableElement executeCached = nodeGen.getMethod(EXECUTE_CHAINED);
2648 CodeExecutableElement executeMethod = CodeExecutableElement.clone(getContext().getEnvironment(), executeCached);
2649 executeMethod.getModifiers().remove(Modifier.ABSTRACT);
2650 CodeTreeBuilder builder = executeMethod.createBuilder();
2651
2652 if (specialization.isPolymorphic()) {
2653 builder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
2654 addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null);
2655 builder.end().end();
2656 } else if (specialization.isUninitialized()) {
2657 if (node.getGenericSpecialization().isReachable()) {
2658 builder.startIf().string("!containsFallback").end().startBlock();
2659 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
2660 builder.end();
2661 } else {
2662 builder.startStatement().startStaticCall(context.getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
2663 }
2664 builder.startReturn().startCall("this", EXECUTE_UNINITIALIZED);
2665 addInternalValueParameterNames(builder, polymorphic, polymorphic, null, true, null);
2666 builder.end().end();
2667 } else {
2668 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
2669 elseBuilder.startReturn().startCall("this.next0", EXECUTE_CHAINED);
2670 addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, null);
2671 elseBuilder.end().end();
2672
2673 builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
2674
2675 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
2676 return createGenericInvoke(b, polymorphic, current);
2677 }
2678 }, elseBuilder.getRoot(), false, true, true, false));
2679 }
2680 clazz.add(executeMethod);
2681 }
2682
2683 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
2684 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2685
2686 List<ExecutableTypeData> primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount());
2687
2688 if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) {
2689 builder.tree(createFunctionalExecute(builder, specialization, execType));
2690 } else if (needsCastingExecuteMethod(execType)) {
2691 assert !primaryExecutes.isEmpty();
2692 builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0)));
2693 } else {
2694 return null;
2695 }
2696
2697 return builder.getRoot();
2698 }
2699
2700 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) {
2701 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
2702
2703 method.getAnnotationMirrors().clear();
2704 for (VariableElement variable : method.getParameters()) {
2705 variable.getAnnotationMirrors().clear();
2706 }
2707
2708 CodeTreeBuilder builder = method.createBuilder();
2709 int i = 0;
2710 int signatureIndex = -1;
2711 for (VariableElement param : method.getParameters()) {
2712 CodeVariableElement var = CodeVariableElement.clone(param);
2713 Parameter actualParameter = i < execType.getParameters().size() ? execType.getParameters().get(i) : null;
2714 String name;
2715 if (actualParameter != null) {
2716 if (actualParameter.getSpecification().isSignature()) {
2717 signatureIndex++;
2718 }
2719
2720 if (evaluated && actualParameter.getSpecification().isSignature()) {
2721 name = valueNameEvaluated(actualParameter);
2722 } else {
2723 name = valueName(actualParameter);
2724 }
2725
2726 int varArgCount = getModel().getSignatureSize() - signatureIndex;
2727 if (evaluated && actualParameter.isTypeVarArgs()) {
2728 Parameter baseVarArgs = actualParameter;
2729 name = valueName(baseVarArgs) + "Args";
2730
2731 builder.startAssert().string(name).string(" != null").end();
2732 builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end();
2733 if (varArgCount > 0) {
2734 List<Parameter> varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size());
2735 for (Parameter varArg : varArgsParameter) {
2736 if (varArgCount <= 0) {
2737 break;
2738 }
2739 TypeMirror type = baseVarArgs.getType();
2740 if (type.getKind() == TypeKind.ARRAY) {
2741 type = ((ArrayType) type).getComponentType();
2742 }
2743 builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getTypeVarArgsIndex() + "]");
2744 varArgCount--;
2745 }
2746 }
2747 }
2748 } else {
2749 name = "arg" + i;
2750 }
2751 var.setName(name);
2752 method.getParameters().set(i, var);
2753 i++;
2754 }
2755
2756 method.getAnnotationMirrors().clear();
2757 method.getModifiers().remove(Modifier.ABSTRACT);
2758 return method;
2759 }
2760
2761 private boolean needsCastingExecuteMethod(ExecutableTypeData execType) {
2762 if (execType.isAbstract()) {
2763 return true;
2764 }
2765 if (execType.getType().isGeneric()) {
2766 return true;
2767 }
2768 return false;
2769 }
2770
2771 private List<ExecutableTypeData> findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) {
2772 TypeData primaryType = specialization.getReturnType().getTypeSystemType();
2773 List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
2774
2775 List<ExecutableTypeData> filteredTypes = new ArrayList<>();
2776 for (ExecutableTypeData compareType : otherTypes) {
2777 if (!ElementUtils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
2778 continue;
2779 }
2780 filteredTypes.add(compareType);
2781 }
2782
2783 // no direct matches found use generic where the type is Object
2784 if (filteredTypes.isEmpty()) {
2785 for (ExecutableTypeData compareType : otherTypes) {
2786 if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) {
2787 filteredTypes.add(compareType);
2788 }
2789 }
2790 }
2791
2792 if (filteredTypes.isEmpty()) {
2793 for (ExecutableTypeData compareType : otherTypes) {
2794 if (compareType.getType().isGeneric()) {
2795 filteredTypes.add(compareType);
2796 }
2797 }
2798 }
2799
2800 return filteredTypes;
2801 }
2802
2803 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, final SpecializationData specialization, final ExecutableTypeData executable) {
2804 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2805 if (specialization.isUninitialized()) {
2806 builder.tree(createDeoptimize(builder));
2807 }
2808
2809 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null));
2810
2811 CodeTree returnSpecialized = null;
2812
2813 if (specialization.findNextSpecialization() != null) {
2814 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
2815 returnBuilder.tree(createDeoptimize(builder));
2816 returnBuilder.tree(createCallRewriteMonomorphic(builder, executable.hasUnexpectedValue(context), executable.getType(), specialization, null,
2817 "One of guards " + specialization.getGuards() + " failed"));
2818 returnSpecialized = returnBuilder.getRoot();
2819 }
2820
2821 builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), new CodeBlock<SpecializationData>() {
2822
2823 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
2824 return createExecute(b, executable, specialization);
2825 }
2826 }, returnSpecialized, false, false, false, false));
2827
2828 return builder.getRoot();
2829 }
2830
2831 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
2832 NodeData node = specialization.getNode();
2833 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2834 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) {
2835 builder.startTryBlock();
2836 }
2837
2838 for (String assumption : specialization.getAssumptions()) {
2839 builder.startStatement();
2840 builder.string("this.").string(assumption).string(".check()");
2841 builder.end();
2842 }
2843
2844 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
2845 if (specialization.isPolymorphic()) {
2846 returnBuilder.startCall("next0", EXECUTE_CHAINED);
2847 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null);
2848 returnBuilder.end();
2849 } else if (specialization.isUninitialized()) {
2850 returnBuilder.startCall(EXECUTE_UNINITIALIZED);
2851 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, null);
2852 returnBuilder.end();
2853 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
2854 emitEncounteredSynthetic(builder, specialization);
2855 } else {
2856 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
2857 }
2858
2859 if (!returnBuilder.isEmpty()) {
2860 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
2861 TypeData sourceType = specialization.getReturnType().getTypeSystemType();
2862
2863 builder.startReturn();
2864 if (targetType == null || sourceType == null) {
2865 builder.tree(returnBuilder.getRoot());
2866 } else if (sourceType.needsCastTo(targetType)) {
2867 String castMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
2868 if (!executable.hasUnexpectedValue(context)) {
2869 castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
2870 }
2871 builder.tree(createCallTypeSystemMethod(parent, node, castMethodName, returnBuilder.getRoot()));
2872 } else {
2873 builder.tree(returnBuilder.getRoot());
2874 }
2875 builder.end();
2876 }
2877
2878 if (!specialization.getExceptions().isEmpty()) {
2879 for (SpecializationThrowsData exception : specialization.getExceptions()) {
2880 builder.end().startCatchBlock(exception.getJavaClass(), "ex");
2881 builder.tree(createDeoptimize(builder));
2882 builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null,
2883 "Thrown " + ElementUtils.getSimpleName(exception.getJavaClass())));
2884 }
2885 builder.end();
2886 }
2887 if (!specialization.getAssumptions().isEmpty()) {
2888 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex");
2889 builder.tree(createCallRewriteMonomorphic(parent, executable.hasUnexpectedValue(context), executable.getType(), specialization, null, "Assumption failed"));
2890 builder.end();
2891 }
2892
2893 return builder.getRoot();
2894 }
2895
2896 protected CodeExecutableElement createCopyConstructorFactoryMethod(TypeMirror baseType, SpecializationData specialization) {
2897 List<Parameter> implicitTypeParams = getImplicitTypeParameters(specialization);
2898 String baseName = "current";
2899 CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME);
2900 method.addParameter(new CodeVariableElement(specialization.getNode().getNodeType(), baseName));
2901 for (Parameter implicitTypeParam : implicitTypeParams) {
2902 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(implicitTypeParam)));
2903 }
2904 CodeTreeBuilder builder = method.createBuilder();
2905 builder.startReturn();
2906 builder.startNew(getElement().asType());
2907 builder.startGroup().cast(baseType, CodeTreeBuilder.singleString(baseName)).end();
2908 for (Parameter param : implicitTypeParams) {
2909 builder.string(implicitTypeName(param));
2910 }
2911 builder.end().end();
2912 return method;
2913 }
2914
2915 protected CodeExecutableElement createConstructorFactoryMethod(SpecializationData specialization, ExecutableElement constructor) {
2916 List<? extends VariableElement> parameters = constructor.getParameters();
2917 CodeExecutableElement method = new CodeExecutableElement(modifiers(STATIC), specialization.getNode().getNodeType(), FACTORY_METHOD_NAME,
2918 parameters.toArray(new CodeVariableElement[parameters.size()]));
2919 CodeTreeBuilder builder = method.createBuilder();
2920 builder.startReturn();
2921 builder.startNew(getElement().asType());
2922 for (VariableElement param : parameters) {
2923 builder.string(((CodeVariableElement) param).getName());
2924 }
2925 builder.end().end();
2926 return method;
2927 }
2928 }
2929
2930 private interface CodeBlock<T> {
2931
2932 CodeTree create(CodeTreeBuilder parent, T value);
2933
2934 }
2935 }