comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeCodeGenerator.java @ 18752:1acaa69ff61b

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