comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java @ 12395:8e8347ecabbc

Truffle-DSL: implemented new polymorphic more compact generation strategy
author Christian Humer <christian.humer@gmail.com>
date Fri, 11 Oct 2013 20:05:55 +0200
parents 4e26955b6da2
children c78612fb0120
comparison
equal deleted inserted replaced
12394:df3af5e007ad 12395:8e8347ecabbc
38 import com.oracle.truffle.dsl.processor.ast.*; 38 import com.oracle.truffle.dsl.processor.ast.*;
39 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; 39 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality;
40 import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind; 40 import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind;
41 import com.oracle.truffle.dsl.processor.node.SpecializationGroup.TypeGuard; 41 import com.oracle.truffle.dsl.processor.node.SpecializationGroup.TypeGuard;
42 import com.oracle.truffle.dsl.processor.template.*; 42 import com.oracle.truffle.dsl.processor.template.*;
43 import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature;
44 import com.oracle.truffle.dsl.processor.typesystem.*; 43 import com.oracle.truffle.dsl.processor.typesystem.*;
45 44
46 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> { 45 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> {
47 46
48 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; 47 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
49 48
50 private static final String EXECUTE_GENERIC_NAME = "executeGeneric0"; 49 private static final String EXECUTE_GENERIC_NAME = "executeGeneric0";
51 private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize0"; 50 private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize0";
52 51
52 private static final String UPDATE_TYPES_NAME = "updateTypes";
53
53 public NodeCodeGenerator(ProcessorContext context) { 54 public NodeCodeGenerator(ProcessorContext context) {
54 super(context); 55 super(context);
55 } 56 }
56 57
57 private TypeMirror getUnexpectedValueException() { 58 private TypeMirror getUnexpectedValueException() {
58 return getContext().getTruffleTypes().getUnexpectedValueException(); 59 return getContext().getTruffleTypes().getUnexpectedValueException();
59 } 60 }
60 61
61 private static String factoryClassName(NodeData node) { 62 private static String factoryClassName(NodeData node) {
62 return node.getNodeId() + "Factory"; 63 return node.getNodeId() + "Factory";
63 }
64
65 private static String nodeCastClassName(NodeData node, TypeData type) {
66 String nodeid = resolveNodeId(node);
67 if (type == null) {
68 return nodeid + "ImplicitCast";
69 } else {
70 return Utils.firstLetterUpperCase(Utils.getSimpleName(type.getPrimitiveType())) + "Cast";
71 }
72 } 64 }
73 65
74 private static String nodeSpecializationClassName(SpecializationData specialization) { 66 private static String nodeSpecializationClassName(SpecializationData specialization) {
75 String nodeid = resolveNodeId(specialization.getNode()); 67 String nodeid = resolveNodeId(specialization.getNode());
76 String name = Utils.firstLetterUpperCase(nodeid); 68 String name = Utils.firstLetterUpperCase(nodeid);
101 93
102 private static String valueNameEvaluated(ActualParameter targetParameter) { 94 private static String valueNameEvaluated(ActualParameter targetParameter) {
103 return valueName(targetParameter) + "Evaluated"; 95 return valueName(targetParameter) + "Evaluated";
104 } 96 }
105 97
106 private static String typeName(ActualParameter param) { 98 private static String implicitTypeName(ActualParameter param) {
107 return param.getLocalName() + "Type"; 99 return param.getLocalName() + "ImplicitType";
100 }
101
102 private static String polymorphicTypeName(ActualParameter param) {
103 return param.getLocalName() + "PolymorphicType";
108 } 104 }
109 105
110 private static String valueName(ActualParameter param) { 106 private static String valueName(ActualParameter param) {
111 return param.getLocalName(); 107 return param.getLocalName();
112 } 108 }
297 builder.string("this."); 293 builder.string("this.");
298 } 294 }
299 builder.string(targetParameter.getSpecification().getName()); 295 builder.string(targetParameter.getSpecification().getName());
300 builder.end(); 296 builder.end();
301 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { 297 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
302 builder.string("ex.getResult()"); 298 builder.cast(targetParameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
303 } else if (!Utils.needsCastTo(getContext(), valueType, targetType)) { 299 } else if (!Utils.needsCastTo(getContext(), valueType, targetType)) {
304 builder.startGroup(); 300 builder.startGroup();
305 builder.string(valueName(targetParameter)); 301 builder.string(valueName(targetParameter));
306 builder.end(); 302 builder.end();
307 } else { 303 } else {
319 String name = Utils.firstLetterUpperCase(nodeid); 315 String name = Utils.firstLetterUpperCase(nodeid);
320 name += "BaseNode"; 316 name += "BaseNode";
321 return name; 317 return name;
322 } 318 }
323 319
324 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { 320 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree... args) {
325 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 321 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
326 startCallTypeSystemMethod(context, builder, node, methodName); 322 startCallTypeSystemMethod(context, builder, node.getTypeSystem(), methodName);
327 builder.tree(value); 323 for (CodeTree arg : args) {
324 builder.tree(arg);
325 }
328 builder.end().end(); 326 builder.end().end();
329 return builder.getRoot(); 327 return builder.getRoot();
330 } 328 }
331 329
332 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { 330 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, TypeSystemData typeSystem, String methodName) {
333 VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); 331 VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, typeSystem);
334 assert singleton != null; 332 assert singleton != null;
335 333
336 body.startGroup(); 334 body.startGroup();
337 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); 335 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString());
338 body.string(".").startCall(methodName); 336 body.string(".").startCall(methodName);
454 add(factory, node); 452 add(factory, node);
455 factory.getElement().getEnclosedElements().addAll(casts); 453 factory.getElement().getEnclosedElements().addAll(casts);
456 } 454 }
457 } 455 }
458 456
459 protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { 457 protected CodeTree createCastType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
460 if (targetType == null) { 458 if (targetType == null) {
461 return value; 459 return value;
462 } else if (sourceType != null && !sourceType.needsCastTo(getContext(), targetType)) { 460 } else if (sourceType != null && !sourceType.needsCastTo(getContext(), targetType)) {
463 return value; 461 return value;
464 } 462 }
468 if (expect) { 466 if (expect) {
469 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); 467 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
470 } else { 468 } else {
471 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); 469 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
472 } 470 }
473 startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); 471 startCallTypeSystemMethod(getContext(), builder, typeSystem, targetMethodName);
474 builder.tree(value); 472 builder.tree(value);
475 builder.end().end(); 473 builder.end().end();
476 return builder.getRoot(); 474 return builder.getRoot();
475 }
476
477 protected CodeTree createExpectType(TypeSystemData typeSystem, TypeData sourceType, TypeData targetType, CodeTree expression) {
478 return createCastType(typeSystem, sourceType, targetType, true, expression);
477 } 479 }
478 480
479 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { 481 private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
480 482
481 private final Map<NodeData, List<TypeElement>> childTypes; 483 private final Map<NodeData, List<TypeElement>> childTypes;
502 protected void createChildren(NodeData node) { 504 protected void createChildren(NodeData node) {
503 CodeTypeElement clazz = getElement(); 505 CodeTypeElement clazz = getElement();
504 506
505 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); 507 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
506 508
509 CodeTypeElement polymorphicNode = null;
507 if (node.needsFactory()) { 510 if (node.needsFactory()) {
508 NodeBaseFactory factory = new NodeBaseFactory(context); 511 NodeBaseFactory factory = new NodeBaseFactory(context);
509 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); 512 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization());
510 generatedNode = factory.getElement(); 513 generatedNode = factory.getElement();
511 514
514 } 517 }
515 518
516 createFactoryMethods(node, clazz, createVisibility); 519 createFactoryMethods(node, clazz, createVisibility);
517 520
518 if (node.isPolymorphic()) { 521 if (node.isPolymorphic()) {
519 PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode, true); 522 PolymorphicNodeFactory generic = new PolymorphicNodeFactory(getContext(), generatedNode);
520 add(generic, node.getGenericPolymorphicSpecialization()); 523 add(generic, node.getGenericPolymorphicSpecialization());
521 524 polymorphicNode = generic.getElement();
522 for (SpecializationData specialization : node.getPolymorphicSpecializations()) {
523 if (specialization == node.getGenericPolymorphicSpecialization()) {
524 continue;
525 }
526 add(new PolymorphicNodeFactory(context, generic.getElement(), false), specialization);
527 }
528 } 525 }
529 for (SpecializationData specialization : node.getSpecializations()) { 526 for (SpecializationData specialization : node.getSpecializations()) {
530 if (!specialization.isReachable()) { 527 if (!specialization.isReachable()) {
531 continue; 528 continue;
532 } 529 }
542 clazz.add(createGetChildrenSignatureMethod(node)); 539 clazz.add(createGetChildrenSignatureMethod(node));
543 clazz.add(createGetInstanceMethod(node, createVisibility)); 540 clazz.add(createGetInstanceMethod(node, createVisibility));
544 clazz.add(createInstanceConstant(node, clazz.asType())); 541 clazz.add(createInstanceConstant(node, clazz.asType()));
545 } 542 }
546 543
544 if (polymorphicNode != null) {
545 patchParameterType(clazz, UPDATE_TYPES_NAME, generatedNode.asType(), polymorphicNode.asType());
546 }
547
547 for (NodeData childNode : childTypes.keySet()) { 548 for (NodeData childNode : childTypes.keySet()) {
548 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { 549 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
549 continue; 550 continue;
550 } 551 }
551 552
566 List<NodeData> children = node.getNodeDeclaringChildren(); 567 List<NodeData> children = node.getNodeDeclaringChildren();
567 if (node.getParent() == null && children.size() > 0) { 568 if (node.getParent() == null && children.size() > 0) {
568 clazz.add(createGetFactories(node)); 569 clazz.add(createGetFactories(node));
569 } 570 }
570 571
572 }
573
574 private void patchParameterType(CodeTypeElement enclosingClass, String methodName, TypeMirror originalType, TypeMirror newType) {
575 for (TypeElement enclosedType : ElementFilter.typesIn(enclosingClass.getEnclosedElements())) {
576 CodeTypeElement type = (CodeTypeElement) enclosedType;
577 ExecutableElement method = type.getMethod(methodName);
578 for (VariableElement v : method.getParameters()) {
579 CodeVariableElement var = (CodeVariableElement) v;
580 if (Utils.typeEquals(var.getType(), originalType)) {
581 var.setType(newType);
582 }
583 }
584 }
571 } 585 }
572 586
573 private CodeExecutableElement createGetNodeClassMethod(NodeData node) { 587 private CodeExecutableElement createGetNodeClassMethod(NodeData node) {
574 TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); 588 TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType());
575 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); 589 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass");
939 setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0")); 953 setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0"));
940 CodeTreeBuilder builder = setter.createBuilder(); 954 CodeTreeBuilder builder = setter.createBuilder();
941 builder.statement("this.next0 = adoptChild(next0)"); 955 builder.statement("this.next0 = adoptChild(next0)");
942 clazz.add(setter); 956 clazz.add(setter);
943 957
944 createIsCompatible(clazz, null); 958 CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecialization());
945
946 CodeExecutableElement genericCachedExecute = createCachedExecute(node, node.getGenericPolymorphicSpecialization(), null);
947 clazz.add(genericCachedExecute); 959 clazz.add(genericCachedExecute);
948 for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { 960
949 if (polymorph == node.getGenericPolymorphicSpecialization()) { 961 getElement().add(createUpdateTypes(clazz.asType()));
950 continue;
951 }
952 clazz.add(createCachedExecute(node, polymorph, genericCachedExecute));
953 }
954 } 962 }
955 963
956 for (CodeExecutableElement method : createImplicitChildrenAccessors()) { 964 for (CodeExecutableElement method : createImplicitChildrenAccessors()) {
957 clazz.add(method); 965 clazz.add(method);
958 } 966 }
966 } 974 }
967 } 975 }
968 976
969 private List<CodeExecutableElement> createImplicitChildrenAccessors() { 977 private List<CodeExecutableElement> createImplicitChildrenAccessors() {
970 NodeData node = getModel().getNode(); 978 NodeData node = getModel().getNode();
971 List<CodeExecutableElement> methods = new ArrayList<>(); 979 // Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>();
972 Map<NodeChildData, Set<TypeData>> expectTypes = new HashMap<>(); 980 @SuppressWarnings("unchecked")
981 List<Set<TypeData>> expectTypes = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
982
973 for (ExecutableTypeData executableType : node.getExecutableTypes()) { 983 for (ExecutableTypeData executableType : node.getExecutableTypes()) {
974 for (int i = 0; i < executableType.getEvaluatedCount(); i++) { 984 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
975 ActualParameter parameter = executableType.getSignatureParameter(i); 985 ActualParameter parameter = executableType.getSignatureParameter(i);
976 NodeChildData child = node.findChild(parameter.getSpecification().getName()); 986 if (i >= expectTypes.size()) {
977 Set<TypeData> types = expectTypes.get(child); 987 break;
988 }
989 Set<TypeData> types = expectTypes.get(i);
978 if (types == null) { 990 if (types == null) {
979 types = new TreeSet<>(); 991 types = new TreeSet<>();
980 expectTypes.put(child, types); 992 expectTypes.set(i, types);
981 } 993 }
982 types.add(parameter.getTypeSystemType()); 994 types.add(parameter.getTypeSystemType());
983 } 995 }
984 } 996 }
985 997
986 Map<NodeChildData, Set<TypeData>> visitedMap = new HashMap<>(); 998 List<CodeExecutableElement> methods = new ArrayList<>();
999 @SuppressWarnings("unchecked")
1000 List<Set<TypeData>> visitedList = Arrays.<Set<TypeData>> asList(new Set[node.getGenericSpecialization().getParameters().size()]);
987 for (SpecializationData spec : node.getSpecializations()) { 1001 for (SpecializationData spec : node.getSpecializations()) {
1002 int signatureIndex = -1;
988 for (ActualParameter param : spec.getParameters()) { 1003 for (ActualParameter param : spec.getParameters()) {
989 if (!param.getSpecification().isSignature()) { 1004 if (!param.getSpecification().isSignature()) {
990 continue; 1005 continue;
991 } 1006 }
992 NodeChildData child = node.findChild(param.getSpecification().getName()); 1007 signatureIndex++;
993 Set<TypeData> visitedTypeData = visitedMap.get(child); 1008 Set<TypeData> visitedTypeData = visitedList.get(signatureIndex);
994 if (visitedTypeData == null) { 1009 if (visitedTypeData == null) {
995 visitedTypeData = new TreeSet<>(); 1010 visitedTypeData = new TreeSet<>();
996 visitedMap.put(child, visitedTypeData); 1011 visitedList.set(signatureIndex, visitedTypeData);
997 } 1012 }
1013
998 if (visitedTypeData.contains(param.getTypeSystemType())) { 1014 if (visitedTypeData.contains(param.getTypeSystemType())) {
999 continue; 1015 continue;
1000 } 1016 }
1001 visitedTypeData.add(param.getTypeSystemType()); 1017 visitedTypeData.add(param.getTypeSystemType());
1002 1018
1003 Set<TypeData> expect = expectTypes.get(child); 1019 Set<TypeData> expect = expectTypes.get(signatureIndex);
1004 if (expect == null) { 1020 if (expect == null) {
1005 expect = Collections.emptySet(); 1021 expect = Collections.emptySet();
1006 } 1022 }
1007 1023
1008 methods.addAll(createExecuteChilds(param, expect)); 1024 methods.addAll(createExecuteChilds(param, expect));
1075 builder.end(); 1091 builder.end();
1076 1092
1077 return method; 1093 return method;
1078 } 1094 }
1079 1095
1080 protected void createIsCompatible(CodeTypeElement clazz, SpecializationData specialization) { 1096 private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph) {
1081 CodeExecutableElement isCompatible = new CodeExecutableElement(modifiers(PROTECTED), context.getType(boolean.class), "isCompatible0");
1082 isCompatible.addParameter(new CodeVariableElement(getContext().getType(Class.class), "type"));
1083
1084 if (specialization == null) {
1085 isCompatible.getModifiers().add(ABSTRACT);
1086 } else if (specialization.isGeneric()) {
1087 isCompatible.createBuilder().startThrow().startNew(getContext().getType(AssertionError.class)).end().end();
1088 } else if (specialization.isPolymorphic()) {
1089 isCompatible.createBuilder().startReturn().string("type != getClass() && next0.isCompatible0(type)").end();
1090 } else if (specialization.isUninitialized()) {
1091 isCompatible.createBuilder().returnTrue();
1092 } else {
1093 NodeData node = specialization.getNode();
1094 CodeTreeBuilder builder = isCompatible.createBuilder();
1095
1096 Signature specializationSignature = specialization.getSignature();
1097 List<SpecializationData> compatible = new ArrayList<>();
1098 for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) {
1099 if (specializationSignature.isCompatibleTo(polymorphic.getSignature())) {
1100 compatible.add(polymorphic);
1101 }
1102 }
1103
1104 if (compatible.isEmpty()) {
1105 builder.returnFalse();
1106 } else {
1107 builder.startIf();
1108 String and = "";
1109 for (SpecializationData polymorphic : compatible) {
1110 builder.string(and);
1111 builder.string("type == ").string(nodePolymorphicClassName(node, polymorphic)).string(".class");
1112 and = " || ";
1113 }
1114 builder.end().startBlock();
1115 builder.startReturn().startCall("next0", "isCompatible0").string("type").end().end();
1116 builder.end();
1117 builder.returnFalse();
1118 }
1119 }
1120
1121 clazz.add(isCompatible);
1122 }
1123
1124 private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) {
1125 String name = executeCachedName(polymorph); 1097 String name = executeCachedName(polymorph);
1126 CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name); 1098 CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED, ABSTRACT), polymorph.getReturnType().getType(), name);
1099 addInternalValueParameters(cachedExecute, polymorph, true, true);
1127 1100
1128 ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0); 1101 ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0);
1129 boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); 1102 boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext());
1130 if (sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) { 1103 if (sourceExecutableType.getType().equals(node.getGenericSpecialization().getReturnType().getTypeSystemType())) {
1131 sourceThrowsUnexpected = false; 1104 sourceThrowsUnexpected = false;
1132 } 1105 }
1133 if (sourceThrowsUnexpected) { 1106 if (sourceThrowsUnexpected) {
1134 cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class)); 1107 cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class));
1135 } 1108 }
1136 addInternalValueParameters(cachedExecute, polymorph, true, true);
1137
1138 if (polymorph == node.getGenericPolymorphicSpecialization()) {
1139 cachedExecute.getModifiers().add(ABSTRACT);
1140 } else {
1141 SpecializationData genericPolymorph = node.getGenericPolymorphicSpecialization();
1142 CodeTreeBuilder builder = cachedExecute.createBuilder();
1143 ExecutableTypeData genericExecutable = new ExecutableTypeData(genericPolymorph, genericPolymorphMethod, node.getTypeSystem(), genericPolymorph.getReturnType().getTypeSystemType());
1144 ExecutableTypeData specificExecutable = new ExecutableTypeData(polymorph, cachedExecute, node.getTypeSystem(), polymorph.getReturnType().getTypeSystemType());
1145 builder.tree(createCastingExecute(builder, polymorph, specificExecutable, genericExecutable));
1146 }
1147
1148 return cachedExecute; 1109 return cachedExecute;
1149 1110
1150 } 1111 }
1151 1112
1152 private void createConstructors(NodeData node, CodeTypeElement clazz) { 1113 private void createConstructors(NodeData node, CodeTypeElement clazz) {
1318 builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), rootGroup, true, new CodeBlock<SpecializationData>() { 1279 builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), rootGroup, true, new CodeBlock<SpecializationData>() {
1319 1280
1320 public CodeTree create(CodeTreeBuilder b, SpecializationData current) { 1281 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
1321 return createGenericInvokeAndSpecialize(b, node.getGenericSpecialization(), current, currentNodeVar); 1282 return createGenericInvokeAndSpecialize(b, node.getGenericSpecialization(), current, currentNodeVar);
1322 } 1283 }
1323 }, null, false, true)); 1284 }, null, false, true, false));
1324 1285
1325 boolean firstUnreachable = true; 1286 boolean firstUnreachable = true;
1326 for (SpecializationData current : node.getSpecializations()) { 1287 for (SpecializationData current : node.getSpecializations()) {
1327 if (current.isUninitialized() || current.isReachable()) { 1288 if (current.isUninitialized() || current.isReachable()) {
1328 continue; 1289 continue;
1362 builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, false, new CodeBlock<SpecializationData>() { 1323 builder.tree(createExecuteTree(builder, node.getGenericSpecialization(), group, false, new CodeBlock<SpecializationData>() {
1363 1324
1364 public CodeTree create(CodeTreeBuilder b, SpecializationData current) { 1325 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
1365 return createGenericInvoke(builder, current.getNode().getGenericSpecialization(), current); 1326 return createGenericInvoke(builder, current.getNode().getGenericSpecialization(), current);
1366 } 1327 }
1367 }, null, false, true)); 1328 }, null, false, true, false));
1368 1329
1369 emitUnreachableSpecializations(builder, node); 1330 emitUnreachableSpecializations(builder, node);
1370 1331
1371 return method; 1332 return method;
1372 } 1333 }
1379 builder.string("// unreachable ").string(current.getId()).newLine(); 1340 builder.string("// unreachable ").string(current.getId()).newLine();
1380 } 1341 }
1381 } 1342 }
1382 1343
1383 protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final boolean checkMinimumState, 1344 protected CodeTree createExecuteTree(CodeTreeBuilder outerParent, final SpecializationData source, final SpecializationGroup group, final boolean checkMinimumState,
1384 final CodeBlock<SpecializationData> guardedblock, final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions) { 1345 final CodeBlock<SpecializationData> guardedblock, final CodeTree elseBlock, boolean forceElse, final boolean emitAssumptions, final boolean typedCasts) {
1385 return guard(outerParent, source, group, checkMinimumState, new CodeBlock<Integer>() { 1346 return guard(outerParent, source, group, checkMinimumState, new CodeBlock<Integer>() {
1386 1347
1387 public CodeTree create(CodeTreeBuilder parent, Integer ifCount) { 1348 public CodeTree create(CodeTreeBuilder parent, Integer ifCount) {
1388 CodeTreeBuilder builder = parent.create(); 1349 CodeTreeBuilder builder = parent.create();
1389 1350
1392 1353
1393 assert group.getChildren().isEmpty() : "missed a specialization"; 1354 assert group.getChildren().isEmpty() : "missed a specialization";
1394 1355
1395 } else { 1356 } else {
1396 for (SpecializationGroup childGroup : group.getChildren()) { 1357 for (SpecializationGroup childGroup : group.getChildren()) {
1397 builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock, null, false, emitAssumptions)); 1358 builder.tree(createExecuteTree(builder, source, childGroup, checkMinimumState, guardedblock, null, false, emitAssumptions, typedCasts));
1398 } 1359 }
1399 } 1360 }
1400 1361
1401 return builder.getRoot(); 1362 return builder.getRoot();
1402 } 1363 }
1403 }, elseBlock, forceElse, emitAssumptions); 1364 }, elseBlock, forceElse, emitAssumptions, typedCasts);
1404 } 1365 }
1405 1366
1406 private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, CodeBlock<Integer> bodyBlock, CodeTree elseBlock, 1367 private CodeTree guard(CodeTreeBuilder parent, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, CodeBlock<Integer> bodyBlock, CodeTree elseBlock,
1407 boolean forceElse, boolean emitAssumptions) { 1368 boolean forceElse, boolean emitAssumptions, boolean typedCasts) {
1408 CodeTreeBuilder builder = parent.create(); 1369 CodeTreeBuilder builder = parent.create();
1409 1370
1410 int ifCount = emitGuards(builder, source, group, checkMinimumState, emitAssumptions); 1371 int ifCount = emitGuards(builder, source, group, checkMinimumState, emitAssumptions, typedCasts);
1411 1372
1412 if (isReachableGroup(group, ifCount, checkMinimumState)) { 1373 if (isReachableGroup(group, ifCount, checkMinimumState)) {
1413 builder.tree(bodyBlock.create(builder, ifCount)); 1374 builder.tree(bodyBlock.create(builder, ifCount));
1414 } 1375 }
1415 1376
1443 } 1404 }
1444 1405
1445 return true; 1406 return true;
1446 } 1407 }
1447 1408
1448 private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, boolean emitAssumptions) { 1409 private int emitGuards(CodeTreeBuilder builder, SpecializationData source, SpecializationGroup group, boolean checkMinimumState, boolean emitAssumptions, boolean typedCasts) {
1449 NodeData node = source.getNode(); 1410 NodeData node = source.getNode();
1450 1411
1451 CodeTreeBuilder guardsBuilder = builder.create(); 1412 CodeTreeBuilder guardsBuilder = builder.create();
1452 CodeTreeBuilder castBuilder = builder.create(); 1413 CodeTreeBuilder castBuilder = builder.create();
1453 CodeTreeBuilder guardsCastBuilder = builder.create(); 1414 CodeTreeBuilder guardsCastBuilder = builder.create();
1513 NodeChildData child = node.findChild(valueParam.getSpecification().getName()); 1474 NodeChildData child = node.findChild(valueParam.getSpecification().getName());
1514 if (child == null) { 1475 if (child == null) {
1515 throw new IllegalStateException(); 1476 throw new IllegalStateException();
1516 } 1477 }
1517 1478
1518 CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeGuard.getType()); 1479 CodeTree implicitGuard = createTypeGuard(guardsBuilder, child, valueParam, typeGuard.getType(), typedCasts);
1519 if (implicitGuard != null) { 1480 if (implicitGuard != null) {
1520 guardsBuilder.string(guardsAnd); 1481 guardsBuilder.string(guardsAnd);
1521 guardsBuilder.tree(implicitGuard); 1482 guardsBuilder.tree(implicitGuard);
1522 guardsAnd = " && "; 1483 guardsAnd = " && ";
1523 } 1484 }
1524 1485
1525 CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), checkMinimumState); 1486 CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), checkMinimumState, typedCasts);
1526 if (cast != null) { 1487 if (cast != null) {
1527 castBuilder.tree(cast); 1488 castBuilder.tree(cast);
1528 } 1489 }
1529 } 1490 }
1530 1491
1591 signatureIndex++; 1552 signatureIndex++;
1592 } 1553 }
1593 return false; 1554 return false;
1594 } 1555 }
1595 1556
1596 private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { 1557 private CodeTree createTypeGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean typedCasts) {
1597 NodeData node = field.getNodeData(); 1558 NodeData node = field.getNodeData();
1598 1559
1599 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1560 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1600 1561
1601 TypeData sourceType = source.getTypeSystemType(); 1562 TypeData sourceType = source.getTypeSystemType();
1613 builder.string("!").string(valueName(shortCircuit)); 1574 builder.string("!").string(valueName(shortCircuit));
1614 builder.string(" || "); 1575 builder.string(" || ");
1615 } 1576 }
1616 1577
1617 String castMethodName; 1578 String castMethodName;
1579 String castTypeName = null;
1618 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); 1580 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
1619 if (types.size() > 1) { 1581 if (types.size() > 1) {
1620 castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType); 1582 castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType);
1583 if (typedCasts) {
1584 castTypeName = implicitTypeName(source);
1585 }
1621 } else { 1586 } else {
1622 castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType); 1587 castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType);
1623 } 1588 }
1624 1589
1625 startCallTypeSystemMethod(getContext(), builder, node, castMethodName); 1590 startCallTypeSystemMethod(getContext(), builder, node.getTypeSystem(), castMethodName);
1626 builder.string(valueName(source)); 1591 builder.string(valueName(source));
1592 if (castTypeName != null) {
1593 builder.string(castTypeName);
1594 }
1627 builder.end().end(); // call 1595 builder.end().end(); // call
1628 1596
1629 if (field.isShortCircuit()) { 1597 if (field.isShortCircuit()) {
1630 builder.string(")"); 1598 builder.string(")");
1631 } 1599 }
1633 builder.end(); // group 1601 builder.end(); // group
1634 1602
1635 return builder.getRoot(); 1603 return builder.getRoot();
1636 } 1604 }
1637 1605
1638 private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean checkMinimumState) { 1606 // TODO merge redundancies with #createTypeGuard
1607 private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean checkMinimumState, boolean typedCasts) {
1639 NodeData node = field.getNodeData(); 1608 NodeData node = field.getNodeData();
1640 TypeData sourceType = source.getTypeSystemType(); 1609 TypeData sourceType = source.getTypeSystemType();
1641 1610
1642 if (!sourceType.needsCastTo(getContext(), targetType)) { 1611 if (!sourceType.needsCastTo(getContext(), targetType)) {
1643 return null; 1612 return null;
1649 assert shortCircuit != null; 1618 assert shortCircuit != null;
1650 condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); 1619 condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
1651 } 1620 }
1652 1621
1653 String castMethodName; 1622 String castMethodName;
1623 String castTypeName = null;
1654 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); 1624 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
1655 if (types.size() > 1) { 1625 if (types.size() > 1) {
1656 castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType); 1626 castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType);
1627 if (typedCasts) {
1628 castTypeName = implicitTypeName(source);
1629 }
1657 } else { 1630 } else {
1658 castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); 1631 castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
1659 } 1632 }
1660 1633
1661 CodeTree value = createCallTypeSystemMethod(context, parent, node, castMethodName, CodeTreeBuilder.singleString(valueName(source))); 1634 List<CodeTree> args = new ArrayList<>();
1635 args.add(CodeTreeBuilder.singleString(valueName(source)));
1636 if (castTypeName != null) {
1637 args.add(CodeTreeBuilder.singleString(castTypeName));
1638 }
1639
1640 CodeTree value = createCallTypeSystemMethod(context, parent, node, castMethodName, args.toArray(new CodeTree[0]));
1662 1641
1663 CodeTreeBuilder builder = parent.create(); 1642 CodeTreeBuilder builder = parent.create();
1664 builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value)); 1643 builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value));
1665 if (checkMinimumState && types.size() > 1) { 1644 if (checkMinimumState && types.size() > 1) {
1666 CodeTree castType = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.getImplicitClass(targetType), CodeTreeBuilder.singleString(valueName(source))); 1645 CodeTree castType = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.getImplicitClass(targetType), CodeTreeBuilder.singleString(valueName(source)));
1667 builder.tree(createLazyAssignment(builder, typeName(source), getContext().getType(Class.class), condition, castType)); 1646 builder.tree(createLazyAssignment(builder, implicitTypeName(source), getContext().getType(Class.class), condition, castType));
1668 } 1647 }
1669 1648
1670 return builder.getRoot(); 1649 return builder.getRoot();
1671 } 1650 }
1672 1651
1812 continue; 1791 continue;
1813 } 1792 }
1814 NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); 1793 NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
1815 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); 1794 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
1816 if (types.size() > 1) { 1795 if (types.size() > 1) {
1817 replaceCall.string(typeName(param)); 1796 replaceCall.string(implicitTypeName(param));
1818 } 1797 }
1819 } 1798 }
1820 replaceCall.end().end(); 1799 replaceCall.end().end();
1821 1800
1822 if (message == null) { 1801 if (message == null) {
1944 return builder.getRoot(); 1923 return builder.getRoot();
1945 } 1924 }
1946 1925
1947 protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { 1926 protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) {
1948 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); 1927 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext());
1949 return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); 1928 return createCastType(node.getTypeSystem(), sourceType, castedType.getType(), hasUnexpected, value);
1950 } 1929 }
1951 1930
1952 protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters, 1931 protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters,
1953 ActualParameter unexpectedParameter) { 1932 ActualParameter unexpectedParameter) {
1954 CodeTreeBuilder builder = parent.create(); 1933 CodeTreeBuilder builder = parent.create();
1956 for (ActualParameter targetParameter : targetParameters) { 1935 for (ActualParameter targetParameter : targetParameters) {
1957 NodeChildData child = node.findChild(targetParameter.getSpecification().getName()); 1936 NodeChildData child = node.findChild(targetParameter.getSpecification().getName());
1958 if (!targetParameter.getSpecification().isSignature()) { 1937 if (!targetParameter.getSpecification().isSignature()) {
1959 continue; 1938 continue;
1960 } 1939 }
1961 TypeData targetType = targetParameter.getTypeSystemType(); 1940 CodeTree executionExpressions = createExecuteChild(builder, child, sourceExecutable, targetParameter, unexpectedParameter);
1962 ExecutableTypeData targetExecutable = null; 1941 CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, specialization, sourceExecutable, targetParameter, isShortCircuit(child), unexpectedParameter);
1963 if (child != null) { 1942 CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, specialization, targetParameter, unexpectedParameter);
1964 targetExecutable = child.findExecutableType(getContext(), targetType);
1965 }
1966
1967 if (targetExecutable == null) {
1968 // TODO what to do? assertion?
1969 continue;
1970 }
1971
1972 CodeTree executionExpressions = createExecutionExpresssions(builder, child, sourceExecutable, targetExecutable, targetParameter, unexpectedParameter);
1973
1974 String targetVarName = valueName(targetParameter);
1975 CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, targetVarName, specialization, sourceExecutable, targetExecutable, targetParameter,
1976 isShortCircuit(child));
1977 CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, targetVarName, specialization, targetParameter, unexpectedParameter);
1978 1943
1979 if (shortCircuitTree == executionExpressions) { 1944 if (shortCircuitTree == executionExpressions) {
1980 if (containsNewLine(executionExpressions)) { 1945 if (containsNewLine(executionExpressions)) {
1981 builder.declaration(sourceExecutable.getType().getPrimitiveType(), targetVarName); 1946 builder.declaration(targetParameter.getType(), valueName(targetParameter));
1982 builder.tree(shortCircuitTree); 1947 builder.tree(shortCircuitTree);
1983 } else { 1948 } else {
1984 builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end(); 1949 builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end();
1985 } 1950 }
1986 } else { 1951 } else {
1989 1954
1990 } 1955 }
1991 return builder.getRoot(); 1956 return builder.getRoot();
1992 } 1957 }
1993 1958
1994 private CodeTree createExecutionExpresssions(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, ActualParameter param, 1959 private ExecutableTypeData resolveExecutableType(NodeChildData child, TypeData type) {
1995 ActualParameter unexpectedParameter) { 1960 ExecutableTypeData targetExecutable = child.findExecutableType(getContext(), type);
1961 if (targetExecutable == null) {
1962 targetExecutable = child.findAnyGenericExecutableType(getContext());
1963 }
1964 return targetExecutable;
1965 }
1966
1967 private CodeTree createExecuteChild(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ActualParameter targetParameter, ActualParameter unexpectedParameter) {
1968 SpecializationData specialization = getModel();
1969 if (specialization.isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) {
1970 TreeSet<TypeData> possiblePolymorphicTypes = lookupPolymorphicTargetTypes(targetParameter);
1971
1972 CodeTreeBuilder builder = parent.create();
1973
1974 boolean elseIf = false;
1975 for (TypeData possiblePolymoprhicType : possiblePolymorphicTypes) {
1976 if (possiblePolymoprhicType.isGeneric()) {
1977 continue;
1978 }
1979 elseIf = builder.startIf(elseIf);
1980
1981 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
1982 TypeData sourceType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
1983 builder.string(polymorphicTypeName(targetParameter)).string(" == ").typeLiteral(possiblePolymoprhicType.getPrimitiveType());
1984 builder.end().startBlock();
1985 builder.startStatement();
1986 builder.tree(createExecuteChildExpression(parent, child, sourceType, new ActualParameter(targetParameter, possiblePolymoprhicType), unexpectedParameter, null));
1987 builder.end();
1988 builder.end();
1989 }
1990
1991 builder.startElseBlock();
1992 builder.startStatement().tree(createExecuteChildImplicit(parent, child, sourceExecutable, targetParameter, unexpectedParameter)).end();
1993 builder.end();
1994
1995 return builder.getRoot();
1996 } else {
1997 return createExecuteChildImplicit(parent, child, sourceExecutable, targetParameter, unexpectedParameter);
1998 }
1999 }
2000
2001 protected final TreeSet<TypeData> lookupPolymorphicTargetTypes(ActualParameter param) {
2002 SpecializationData specialization = getModel();
2003 TreeSet<TypeData> possiblePolymorphicTypes = new TreeSet<>();
2004 for (SpecializationData otherSpecialization : specialization.getNode().getSpecializations()) {
2005 if (!otherSpecialization.isSpecialized()) {
2006 continue;
2007 }
2008 ActualParameter otherParameter = otherSpecialization.findParameter(param.getLocalName());
2009 if (otherParameter != null) {
2010 possiblePolymorphicTypes.add(otherParameter.getTypeSystemType());
2011 }
2012 }
2013 return possiblePolymorphicTypes;
2014 }
2015
2016 private CodeTree createExecuteChildImplicit(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ActualParameter param, ActualParameter unexpectedParameter) {
1996 CodeTreeBuilder builder = parent.create(); 2017 CodeTreeBuilder builder = parent.create();
1997
1998 ActualParameter sourceParameter = sourceExecutable.findParameter(param.getLocalName()); 2018 ActualParameter sourceParameter = sourceExecutable.findParameter(param.getLocalName());
1999
2000 String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null); 2019 String childExecuteName = createExecuteChildMethodName(param, sourceParameter != null);
2001 if (childExecuteName != null) { 2020 if (childExecuteName != null) {
2002 builder.string(valueName(param)); 2021 builder.string(valueName(param));
2003 builder.string(" = "); 2022 builder.string(" = ");
2004 builder.startCall(childExecuteName); 2023 builder.startCall(childExecuteName);
2012 2031
2013 if (sourceParameter != null) { 2032 if (sourceParameter != null) {
2014 builder.string(valueNameEvaluated(sourceParameter)); 2033 builder.string(valueNameEvaluated(sourceParameter));
2015 } 2034 }
2016 2035
2017 builder.string(typeName(param)); 2036 builder.string(implicitTypeName(param));
2018 2037
2019 builder.end(); 2038 builder.end();
2020 } else { 2039 } else {
2021 List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); 2040 List<TypeData> sourceTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
2022 TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null; 2041 TypeData expectType = sourceParameter != null ? sourceParameter.getTypeSystemType() : null;
2023 if (sourceTypes.size() > 1) { 2042 if (sourceTypes.size() > 1) {
2024 builder.tree(createExecuteExpressions(parent, param, expectType)); 2043 builder.tree(createExecuteChildImplicitExpressions(parent, param, expectType));
2025 } else { 2044 } else {
2026 builder.tree(createExecuteExpression(parent, child, expectType, targetExecutable, param, unexpectedParameter, null)); 2045 builder.tree(createExecuteChildExpression(parent, child, expectType, param, unexpectedParameter, null));
2027 } 2046 }
2028 } 2047 }
2029 return builder.getRoot(); 2048 return builder.getRoot();
2030 } 2049 }
2031 2050
2069 method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException()); 2088 method.getThrownTypes().add(getContext().getTruffleTypes().getUnexpectedValueException());
2070 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); 2089 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue"));
2071 if (expectType != null) { 2090 if (expectType != null) {
2072 method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param))); 2091 method.addParameter(new CodeVariableElement(expectType.getPrimitiveType(), valueNameEvaluated(param)));
2073 } 2092 }
2074 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), typeName(param))); 2093 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
2075 2094
2076 CodeTreeBuilder builder = method.createBuilder(); 2095 CodeTreeBuilder builder = method.createBuilder();
2077 builder.declaration(param.getType(), valueName(param)); 2096 builder.declaration(param.getType(), valueName(param));
2078 builder.tree(createExecuteExpressions(builder, param, expectType)); 2097 builder.tree(createExecuteChildImplicitExpressions(builder, param, expectType));
2079 builder.startReturn().string(valueName(param)).end(); 2098 builder.startReturn().string(valueName(param)).end();
2080 2099
2081 return method; 2100 return method;
2082 } 2101 }
2083 2102
2084 private CodeTree createExecuteExpressions(CodeTreeBuilder parent, ActualParameter param, TypeData expectType) { 2103 private CodeTree createExecuteChildImplicitExpressions(CodeTreeBuilder parent, ActualParameter targetParameter, TypeData expectType) {
2085 CodeTreeBuilder builder = parent.create(); 2104 CodeTreeBuilder builder = parent.create();
2086 NodeData node = getModel().getNode(); 2105 NodeData node = getModel().getNode();
2087 NodeChildData child = node.findChild(param.getSpecification().getName()); 2106 NodeChildData child = node.findChild(targetParameter.getSpecification().getName());
2088 List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); 2107 List<TypeData> sourceTypes = node.getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType());
2089 boolean elseIf = false; 2108 boolean elseIf = false;
2090 int index = 0; 2109 int index = 0;
2091 for (TypeData sourceType : sourceTypes) { 2110 for (TypeData sourceType : sourceTypes) {
2092 if (index < sourceTypes.size() - 1) { 2111 if (index < sourceTypes.size() - 1) {
2093 elseIf = builder.startIf(elseIf); 2112 elseIf = builder.startIf(elseIf);
2094 builder.string(typeName(param)).string(" == ").typeLiteral(sourceType.getPrimitiveType()); 2113 builder.string(implicitTypeName(targetParameter)).string(" == ").typeLiteral(sourceType.getPrimitiveType());
2095 builder.end(); 2114 builder.end();
2096 builder.startBlock(); 2115 builder.startBlock();
2097 } else { 2116 } else {
2098 builder.startElseBlock(); 2117 builder.startElseBlock();
2099 } 2118 }
2100 2119
2101 ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(sourceType, child.getExecuteWith().size()); 2120 ExecutableTypeData implictExecutableTypeData = child.findExecutableType(getContext(), sourceType);
2102 if (implictExecutableTypeData == null) { 2121 if (implictExecutableTypeData == null) {
2103 /* 2122 /*
2104 * For children with executeWith.size() > 0 an executable type may not exist so 2123 * For children with executeWith.size() > 0 an executable type may not exist so
2105 * use the generic executable type which is guaranteed to exist. An expect call 2124 * use the generic executable type which is guaranteed to exist. An expect call
2106 * is inserted automatically by #createExecuteExpression. 2125 * is inserted automatically by #createExecuteExpression.
2107 */ 2126 */
2108 implictExecutableTypeData = child.getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), child.getExecuteWith().size()); 2127 implictExecutableTypeData = child.getNodeData().findExecutableType(node.getTypeSystem().getGenericTypeData(), child.getExecuteWith().size());
2109 } 2128 }
2110 2129
2111 ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(sourceType, param.getTypeSystemType()); 2130 ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(sourceType, targetParameter.getTypeSystemType());
2112 CodeTree execute = createExecuteExpression(builder, child, expectType, implictExecutableTypeData, param, null, cast); 2131 CodeTree execute = createExecuteChildExpression(builder, child, expectType, targetParameter, null, cast);
2113 builder.statement(execute); 2132 builder.statement(execute);
2114 builder.end(); 2133 builder.end();
2115 index++; 2134 index++;
2116 } 2135 }
2117 return builder.getRoot(); 2136 return builder.getRoot();
2118 } 2137 }
2119 2138
2120 private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, TypeData expectType, ExecutableTypeData targetExecutable, ActualParameter targetParameter, 2139 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData child, TypeData sourceParameterType, ActualParameter targetParameter, ActualParameter unexpectedParameter,
2121 ActualParameter unexpectedParameter, ImplicitCastData cast) { 2140 ImplicitCastData cast) {
2141 // assignments: targetType <- castTargetType <- castSourceType <- sourceType
2142 TypeData sourceType = sourceParameterType;
2143 TypeData targetType = targetParameter.getTypeSystemType();
2144 TypeData castSourceType = targetType;
2145 TypeData castTargetType = targetType;
2146
2147 if (cast != null) {
2148 castSourceType = cast.getSourceType();
2149 castTargetType = cast.getTargetType();
2150 }
2151
2152 CodeTree expression;
2153 if (sourceType == null) {
2154 ExecutableTypeData targetExecutable = resolveExecutableType(child, targetType);
2155 expression = createExecuteChildExpression(parent, child, targetParameter, targetExecutable, unexpectedParameter);
2156 sourceType = targetExecutable.getType();
2157 } else {
2158 expression = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter));
2159 }
2160
2161 // target = expectTargetType(implicitCast(expectCastSourceType(source)))
2162 TypeSystemData typeSystem = child.getNodeData().getTypeSystem();
2163 expression = createExpectType(typeSystem, sourceType, castSourceType, expression);
2164 expression = createImplicitCast(parent, typeSystem, cast, expression);
2165 expression = createExpectType(typeSystem, castTargetType, targetType, expression);
2166
2122 CodeTreeBuilder builder = parent.create(); 2167 CodeTreeBuilder builder = parent.create();
2123 builder.string(valueName(targetParameter)); 2168 builder.string(valueName(targetParameter));
2124 builder.string(" = "); 2169 builder.string(" = ");
2125 if (cast != null) { 2170 builder.tree(expression);
2126 startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), cast.getMethodName()); 2171 return builder.getRoot();
2127 } 2172 }
2128 2173
2129 TypeData expectTarget = targetParameter.getTypeSystemType(); 2174 private CodeTree createImplicitCast(CodeTreeBuilder parent, TypeSystemData typeSystem, ImplicitCastData cast, CodeTree expression) {
2130 if (cast != null) { 2175 if (cast == null) {
2131 expectTarget = cast.getSourceType(); 2176 return expression;
2132 } 2177 }
2133 2178 CodeTreeBuilder builder = parent.create();
2134 if (targetExecutable.getType().needsCastTo(context, expectTarget)) { 2179 startCallTypeSystemMethod(getContext(), builder, typeSystem, cast.getMethodName());
2135 startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), TypeSystemCodeGenerator.expectTypeMethodName(expectTarget)); 2180 builder.tree(expression);
2136 } 2181 builder.end().end();
2137
2138 NodeData node = getModel().getNode();
2139 if (expectType == null) {
2140 builder.tree(createExecuteChildExpression(builder, child, targetParameter, targetExecutable, unexpectedParameter));
2141 } else {
2142 CodeTree var = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter));
2143 builder.tree(createExpectExecutableType(node, expectType, targetExecutable, var));
2144 }
2145
2146 if (targetExecutable.getType().needsCastTo(context, targetParameter.getTypeSystemType())) {
2147 builder.end().end();
2148 }
2149
2150 if (cast != null) {
2151 builder.end().end();
2152 }
2153
2154 return builder.getRoot(); 2182 return builder.getRoot();
2155 } 2183 }
2156 2184
2157 private boolean containsNewLine(CodeTree tree) { 2185 private boolean containsNewLine(CodeTree tree) {
2158 if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) { 2186 if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) {
2165 } 2193 }
2166 } 2194 }
2167 return false; 2195 return false;
2168 } 2196 }
2169 2197
2170 private boolean hasUnexpected(ExecutableTypeData target, ActualParameter sourceParameter, ActualParameter targetParameter) { 2198 private boolean hasUnexpected(ActualParameter sourceParameter, ActualParameter targetParameter, ActualParameter unexpectedParameter) {
2171 List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType());
2172 NodeChildData child = getModel().getNode().findChild(targetParameter.getSpecification().getName()); 2199 NodeChildData child = getModel().getNode().findChild(targetParameter.getSpecification().getName());
2173 boolean hasUnexpected = false; 2200
2174 for (TypeData type : types) { 2201 if (getModel().isPolymorphic() && targetParameter.getTypeSystemType().isGeneric() && unexpectedParameter == null) {
2175 if (hasUnexpected) { 2202 // check for other polymorphic types
2176 continue; 2203 for (TypeData polymorphicTargetType : lookupPolymorphicTargetTypes(targetParameter)) {
2177 } 2204 if (hasUnexpectedType(child, sourceParameter, polymorphicTargetType)) {
2178 ExecutableTypeData execTarget = target; 2205 return true;
2179 if (type != execTarget.getType()) { 2206 }
2180 execTarget = child.findExecutableType(getContext(), type); 2207 }
2181 } 2208 }
2182 hasUnexpected = hasUnexpected || hasUnexpectedType(execTarget, sourceParameter, type); 2209
2183 } 2210 if (hasUnexpectedType(child, sourceParameter, targetParameter.getTypeSystemType())) {
2184 return hasUnexpected;
2185 }
2186
2187 private boolean hasUnexpectedType(ExecutableTypeData target, ActualParameter sourceParameter, TypeData type) {
2188 boolean targetCast = target.getType().needsCastTo(context, type);
2189 if (targetCast && getModel().getNode().getTypeSystem().lookupCast(target.getType(), type) == null) {
2190 return true; 2211 return true;
2191 } 2212 }
2192 if (sourceParameter == null) { 2213 return false;
2193 return target.hasUnexpectedValue(getContext()); 2214 }
2194 } else { 2215
2195 if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), type)) { 2216 private boolean hasUnexpectedType(NodeChildData child, ActualParameter sourceParameter, TypeData targetType) {
2196 return target.hasUnexpectedValue(getContext()); 2217 List<TypeData> implicitSourceTypes = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType);
2197 } 2218
2198 return false; 2219 for (TypeData implicitSourceType : implicitSourceTypes) {
2199 } 2220 TypeData sourceType;
2200 } 2221 if (sourceParameter != null) {
2201 2222 sourceType = sourceParameter.getTypeSystemType();
2202 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, 2223 } else {
2203 ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { 2224 ExecutableTypeData targetExecutable = resolveExecutableType(child, implicitSourceType);
2225 if (targetExecutable.hasUnexpectedValue(getContext())) {
2226 return true;
2227 }
2228 sourceType = targetExecutable.getType();
2229 }
2230
2231 ImplicitCastData cast = getModel().getNode().getTypeSystem().lookupCast(implicitSourceType, targetType);
2232 if (cast != null) {
2233 if (cast.getSourceType().needsCastTo(getContext(), targetType)) {
2234 return true;
2235 }
2236 }
2237
2238 if (sourceType.needsCastTo(getContext(), targetType)) {
2239 return true;
2240 }
2241 }
2242 return false;
2243 }
2244
2245 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ExecutableTypeData currentExecutable, ActualParameter param,
2246 boolean shortCircuit, ActualParameter unexpectedParameter) {
2204 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 2247 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2205 ActualParameter sourceParameter = currentExecutable.findParameter(param.getLocalName()); 2248 ActualParameter sourceParameter = currentExecutable.findParameter(param.getLocalName());
2206 boolean unexpected = hasUnexpected(targetExecutable, sourceParameter, param); 2249 boolean unexpected = hasUnexpected(sourceParameter, param, unexpectedParameter);
2207 if (!unexpected) { 2250 if (!unexpected) {
2208 return body; 2251 return body;
2209 } 2252 }
2210 2253
2211 if (!shortCircuit) { 2254 if (!shortCircuit) {
2212 builder.declaration(param.getType(), targetVariableName); 2255 builder.declaration(param.getType(), valueName(param));
2213 } 2256 }
2214 builder.startTryBlock(); 2257 builder.startTryBlock();
2215 2258
2216 if (containsNewLine(body)) { 2259 if (containsNewLine(body)) {
2217 builder.tree(body); 2260 builder.tree(body);
2222 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); 2265 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
2223 SpecializationData generic = specialization.getNode().getGenericSpecialization(); 2266 SpecializationData generic = specialization.getNode().getGenericSpecialization();
2224 ActualParameter genericParameter = generic.findParameter(param.getLocalName()); 2267 ActualParameter genericParameter = generic.findParameter(param.getLocalName());
2225 2268
2226 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); 2269 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
2227 builder.tree(createDeoptimize(builder));
2228 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter)); 2270 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter));
2229 if (specialization.isPolymorphic()) { 2271 if (specialization.isPolymorphic()) {
2230 builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); 2272 builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param));
2231 } else { 2273 } else {
2232 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization, param, 2274 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization, param,
2241 NodeData node = specialization.getNode(); 2283 NodeData node = specialization.getNode();
2242 assert !node.getPolymorphicSpecializations().isEmpty(); 2284 assert !node.getPolymorphicSpecializations().isEmpty();
2243 SpecializationData generic = node.getGenericPolymorphicSpecialization(); 2285 SpecializationData generic = node.getGenericPolymorphicSpecialization();
2244 2286
2245 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 2287 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2288 builder.startStatement().string(polymorphicTypeName(param)).string(" = ").typeLiteral(getContext().getType(Object.class)).end();
2289
2246 builder.startReturn(); 2290 builder.startReturn();
2247 2291
2248 CodeTreeBuilder execute = new CodeTreeBuilder(builder); 2292 CodeTreeBuilder execute = new CodeTreeBuilder(builder);
2249 execute.startCall("next0", executeCachedName(generic)); 2293 execute.startCall("next0", executeCachedName(generic));
2250 addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true, null); 2294 addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true, null);
2330 builder.string("[" + targetParameter.getIndex() + "]"); 2374 builder.string("[" + targetParameter.getIndex() + "]");
2331 } 2375 }
2332 return builder.getRoot(); 2376 return builder.getRoot();
2333 } 2377 }
2334 2378
2335 private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, 2379 private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) {
2336 ActualParameter exceptionParam) {
2337 NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); 2380 NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName());
2338 if (!isShortCircuit(forField)) { 2381 if (!isShortCircuit(forField)) {
2339 return body; 2382 return body;
2340 } 2383 }
2341 2384
2342 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 2385 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
2343 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); 2386 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
2344 builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); 2387 builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam));
2345 builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); 2388 builder.declaration(parameter.getType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
2346 builder.startIf().string(shortCircuitParam.getLocalName()).end(); 2389 builder.startIf().string(shortCircuitParam.getLocalName()).end();
2347 builder.startBlock(); 2390 builder.startBlock();
2348 2391
2349 if (containsNewLine(body)) { 2392 if (containsNewLine(body)) {
2350 builder.tree(body); 2393 builder.tree(body);
2404 builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot())); 2447 builder.tree(createExpectExecutableType(node, generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot()));
2405 builder.end(); 2448 builder.end();
2406 2449
2407 return builder.getRoot(); 2450 return builder.getRoot();
2408 } 2451 }
2452
2453 protected final CodeExecutableElement createUpdateTypes(TypeMirror polymorphicType) {
2454 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), UPDATE_TYPES_NAME);
2455 method.getParameters().add(new CodeVariableElement(polymorphicType, "polymorphic"));
2456 CodeTreeBuilder builder = method.createBuilder();
2457
2458 if (getModel().isPolymorphic()) {
2459 builder.startStatement();
2460 builder.startCall("next0", "updateTypes").string("polymorphic").end();
2461 builder.end();
2462 } else if (getModel().isSpecialized()) {
2463 for (ActualParameter parameter : getModel().getParameters()) {
2464 if (!parameter.getSpecification().isSignature()) {
2465 continue;
2466 }
2467 if (lookupPolymorphicTargetTypes(parameter).size() <= 1) {
2468 continue;
2469 }
2470 builder.startStatement();
2471 builder.startCall("polymorphic", createUpdateTypeName(parameter));
2472 builder.typeLiteral(parameter.getType());
2473 builder.end().end();
2474 }
2475
2476 builder.startStatement().startCall("super", UPDATE_TYPES_NAME).string("polymorphic").end().end();
2477 }
2478 return method;
2479 }
2480
2481 protected String createUpdateTypeName(ActualParameter parameter) {
2482 return "update" + Utils.firstLetterUpperCase(parameter.getLocalName()) + "Type";
2483 }
2409 } 2484 }
2410 2485
2411 private class PolymorphicNodeFactory extends SpecializedNodeFactory { 2486 private class PolymorphicNodeFactory extends SpecializedNodeFactory {
2412 2487
2413 private final boolean generic; 2488 public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) {
2414
2415 public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen, boolean generic) {
2416 super(context, nodeGen); 2489 super(context, nodeGen);
2417 this.generic = generic; 2490 }
2491
2492 @Override
2493 public CodeTypeElement create(SpecializationData polymorph) {
2494 NodeData node = polymorph.getNode();
2495 TypeMirror baseType = node.getNodeType();
2496 if (nodeGen != null) {
2497 baseType = nodeGen.asType();
2498 }
2499 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodePolymorphicClassName(node, polymorph), baseType, false);
2500
2501 clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC));
2502
2503 for (ActualParameter polymorphParameter : polymorph.getParameters()) {
2504 if (!polymorphParameter.getSpecification().isSignature()) {
2505 continue;
2506 }
2507 if (!polymorphParameter.getTypeSystemType().isGeneric()) {
2508 continue;
2509 }
2510 Set<TypeData> types = new HashSet<>();
2511 for (SpecializationData specialization : node.getSpecializations()) {
2512 if (!specialization.isSpecialized()) {
2513 continue;
2514 }
2515 ActualParameter parameter = specialization.findParameter(polymorphParameter.getLocalName());
2516 assert parameter != null;
2517 types.add(parameter.getTypeSystemType());
2518 }
2519 CodeVariableElement var = new CodeVariableElement(modifiers(PRIVATE), getContext().getType(Class.class), polymorphicTypeName(polymorphParameter));
2520 var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getCompilationFinal()));
2521 clazz.add(var);
2522 }
2523
2524 return clazz;
2525 }
2526
2527 @Override
2528 protected void createChildren(SpecializationData specialization) {
2529 CodeTypeElement clazz = getElement();
2530
2531 createConstructors(clazz);
2532 createExecuteMethods(specialization);
2533
2534 getElement().add(createUpdateTypes(nodeGen.asType()));
2535
2536 for (ActualParameter parameter : specialization.getParameters()) {
2537 if (!parameter.getSpecification().isSignature()) {
2538 continue;
2539 }
2540 if (lookupPolymorphicTargetTypes(parameter).size() <= 1) {
2541 continue;
2542 }
2543 getElement().add(createUpdateType(parameter));
2544 }
2545
2546 createCachedExecuteMethods(specialization);
2547
2548 }
2549
2550 private ExecutableElement createUpdateType(ActualParameter parameter) {
2551 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), createUpdateTypeName(parameter));
2552 method.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), "type"));
2553 CodeTreeBuilder builder = method.createBuilder();
2554
2555 String fieldName = polymorphicTypeName(parameter);
2556 builder.startIf().string(fieldName).isNull().end().startBlock();
2557 builder.startStatement().string(fieldName).string(" = ").string("type").end();
2558 builder.end();
2559 builder.startElseIf().string(fieldName).string(" != ").string("type").end();
2560 builder.startBlock();
2561 builder.startStatement().string(fieldName).string(" = ").typeLiteral(getContext().getType(Object.class)).end();
2562 builder.end();
2563
2564 return method;
2565 }
2566
2567 }
2568
2569 private class SpecializedNodeFactory extends NodeBaseFactory {
2570
2571 protected final CodeTypeElement nodeGen;
2572
2573 public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) {
2574 super(context);
2575 this.nodeGen = nodeGen;
2418 } 2576 }
2419 2577
2420 @Override 2578 @Override
2421 public CodeTypeElement create(SpecializationData specialization) { 2579 public CodeTypeElement create(SpecializationData specialization) {
2422 NodeData node = specialization.getNode(); 2580 NodeData node = specialization.getNode();
2423 TypeMirror baseType = node.getNodeType(); 2581 TypeMirror baseType = node.getNodeType();
2424 if (nodeGen != null) { 2582 if (nodeGen != null) {
2425 baseType = nodeGen.asType(); 2583 baseType = nodeGen.asType();
2426 } 2584 }
2427 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC), nodePolymorphicClassName(node, specialization), baseType, false);
2428
2429 if (!generic) {
2430 clazz.getModifiers().add(Modifier.FINAL);
2431 }
2432
2433 clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC));
2434
2435 return clazz;
2436 }
2437
2438 @Override
2439 protected void createChildren(SpecializationData specialization) {
2440 CodeTypeElement clazz = getElement();
2441
2442 createConstructors(clazz);
2443 createExecuteMethods(specialization);
2444
2445 if (generic) {
2446 getElement().add(createOptimizeTypes());
2447 createCachedExecuteMethods(specialization);
2448 createIsCompatible(clazz, specialization);
2449 }
2450 }
2451
2452 private CodeExecutableElement createOptimizeTypes() {
2453 NodeData node = getModel().getNode();
2454 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), getContext().getType(void.class), "optimizeTypes");
2455 CodeTreeBuilder builder = method.createBuilder();
2456
2457 boolean elseIf = false;
2458 for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) {
2459 String className = nodePolymorphicClassName(node, polymorphic);
2460
2461 String sep = "";
2462 StringBuilder reason = new StringBuilder("Optimized polymorphic types for (");
2463 for (ActualParameter parameter : polymorphic.getReturnTypeAndParameters()) {
2464 if (!parameter.getSpecification().isSignature()) {
2465 continue;
2466 }
2467 reason.append(sep).append(Utils.getSimpleName(parameter.getType()));
2468 sep = ", ";
2469 }
2470 reason.append(")");
2471
2472 elseIf = builder.startIf(elseIf);
2473 builder.startCall("isCompatible0");
2474 builder.startGroup().string(className).string(".class").end();
2475 builder.end().end().startBlock();
2476
2477 builder.startStatement().startCall("super", "replace");
2478 builder.startNew(className).string("this").end();
2479 builder.doubleQuote(reason.toString());
2480 builder.end().end(); // call
2481 builder.end();
2482 }
2483 return method;
2484 }
2485 }
2486
2487 private class BaseCastNodeFactory extends ClassElementFactory<NodeData> {
2488
2489 protected final Set<TypeData> usedTargetTypes;
2490
2491 public BaseCastNodeFactory(ProcessorContext context, Set<TypeData> usedTargetTypes) {
2492 super(context);
2493 this.usedTargetTypes = usedTargetTypes;
2494 }
2495
2496 @Override
2497 protected CodeTypeElement create(NodeData m) {
2498 CodeTypeElement type = createClass(m, modifiers(STATIC), nodeCastClassName(m, null), context.getTruffleTypes().getNode(), false);
2499
2500 CodeVariableElement delegate = new CodeVariableElement(m.getNodeType(), "delegate");
2501 delegate.getModifiers().add(PROTECTED);
2502 delegate.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation()));
2503
2504 type.add(delegate);
2505 type.add(createConstructorUsingFields(modifiers(), type));
2506 return type;
2507 }
2508
2509 @Override
2510 protected void createChildren(NodeData m) {
2511 CodeTypeElement type = getElement();
2512 type.add(createExecute(EXECUTE_SPECIALIZE_NAME, true));
2513 type.add(createExecute(EXECUTE_GENERIC_NAME, false));
2514
2515 for (ExecutableTypeData targetExecutable : m.getExecutableTypes()) {
2516 if (!usedTargetTypes.contains(targetExecutable.getType()) && targetExecutable.hasUnexpectedValue(getContext())) {
2517 continue;
2518 }
2519 CodeExecutableElement execute = createCastExecute(targetExecutable, targetExecutable, false);
2520 CodeExecutableElement expect = createCastExecute(targetExecutable, targetExecutable, true);
2521 if (execute != null) {
2522 getElement().add(execute);
2523 }
2524 if (expect != null) {
2525 getElement().add(expect);
2526 }
2527 }
2528 Set<TypeData> sourceTypes = new TreeSet<>();
2529 List<ImplicitCastData> casts = getModel().getTypeSystem().getImplicitCasts();
2530 for (ImplicitCastData cast : casts) {
2531 sourceTypes.add(cast.getSourceType());
2532 }
2533
2534 CodeTypeElement baseType = getElement();
2535 for (TypeData sourceType : sourceTypes) {
2536 add(new SpecializedCastNodeFactory(context, baseType, sourceType, usedTargetTypes), getModel());
2537 }
2538 }
2539
2540 private CodeExecutableElement createExecute(String name, boolean specialize) {
2541 NodeData node = getModel();
2542 TypeMirror objectType = node.getTypeSystem().getGenericType();
2543 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), objectType, name, new CodeVariableElement(objectType, "value"));
2544 if (specialize) {
2545 method.getModifiers().add(FINAL);
2546 }
2547 CodeTreeBuilder builder = method.createBuilder();
2548
2549 List<ImplicitCastData> casts = node.getTypeSystem().getImplicitCasts();
2550 boolean elseIf = false;
2551 for (ImplicitCastData cast : casts) {
2552 elseIf = builder.startIf(elseIf);
2553 startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.isTypeMethodName(cast.getSourceType()));
2554 builder.string("value");
2555 builder.end().end();
2556 builder.end();
2557 builder.startBlock();
2558
2559 if (specialize) {
2560 builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), cast.getSourceType())).string("delegate").end().doubleQuote("Added cast").end().end();
2561 }
2562 builder.startReturn();
2563
2564 startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName());
2565 startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.asTypeMethodName(cast.getSourceType()));
2566 builder.string("value");
2567 builder.end().end();
2568 builder.end().end();
2569
2570 builder.end();
2571 builder.end();
2572 }
2573
2574 builder.startReturn().string("value").end();
2575
2576 return method;
2577 }
2578
2579 protected CodeExecutableElement createCastExecute(ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, boolean expect) {
2580 ImplicitCastData cast = null;
2581 if (!sourceExecutable.getType().equals(targetExecutable.getType())) {
2582 cast = getModel().getTypeSystem().lookupCast(sourceExecutable.getType(), targetExecutable.getType());
2583 if (cast == null) {
2584 return null;
2585 }
2586 }
2587
2588 if (expect) {
2589 if (targetExecutable.getEvaluatedCount() > 0) {
2590 return null;
2591 } else if (Utils.isObject(targetExecutable.getType().getPrimitiveType())) {
2592 return null;
2593 }
2594 }
2595
2596 boolean hasTargetUnexpected = targetExecutable.hasUnexpectedValue(getContext());
2597 boolean hasSourceUnexpected = sourceExecutable.hasUnexpectedValue(getContext());
2598
2599 CodeExecutableElement method = copyTemplateMethod(targetExecutable);
2600 method.getModifiers().add(PUBLIC);
2601
2602 CodeTreeBuilder builder = method.createBuilder();
2603
2604 if (hasSourceUnexpected && cast != null) {
2605 builder.startTryBlock();
2606 }
2607
2608 if (expect) {
2609 method.getParameters().clear();
2610 String expectMethodName;
2611 if (hasTargetUnexpected) {
2612 expectMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetExecutable.getType());
2613 } else {
2614 expectMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetExecutable.getType());
2615 }
2616 method.setSimpleName(CodeNames.of(expectMethodName));
2617 method.addParameter(new CodeVariableElement(getModel().getTypeSystem().getGenericType(), "value"));
2618 }
2619
2620 builder.startReturn();
2621 CodeTree executeCall;
2622 if (expect) {
2623 executeCall = createCastType(getModel(), getModel().getTypeSystem().getGenericTypeData(), sourceExecutable.getType(), hasSourceUnexpected, CodeTreeBuilder.singleString("value"));
2624 } else {
2625 executeCall = createTemplateMethodCall(builder, CodeTreeBuilder.singleString("delegate."), targetExecutable, sourceExecutable, null);
2626 }
2627 if (cast != null) {
2628 startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName());
2629 builder.tree(executeCall);
2630 builder.end().end();
2631 } else {
2632 builder.tree(executeCall);
2633 }
2634 builder.end();
2635
2636 if (hasSourceUnexpected && cast != null) {
2637 builder.end();
2638 builder.startCatchBlock(getContext().getTruffleTypes().getUnexpectedValueException(), "ex");
2639 builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), null)).string("delegate").end().doubleQuote("Removed cast").end().end();
2640
2641 if (hasTargetUnexpected) {
2642 builder.startThrow().string("ex").end();
2643 } else {
2644 builder.startThrow().startNew(getContext().getType(AssertionError.class)).end().end();
2645 }
2646 builder.end();
2647 }
2648
2649 return method;
2650 }
2651
2652 private CodeExecutableElement copyTemplateMethod(TemplateMethod targetExecutable) {
2653 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), targetExecutable.getMethod());
2654 method.getModifiers().remove(ABSTRACT);
2655 method.getAnnotationMirrors().clear();
2656 Modifier visibility = Utils.getVisibility(method.getModifiers());
2657 if (visibility != null) {
2658 method.getModifiers().remove(visibility);
2659 }
2660 int index = 0;
2661 for (ActualParameter parameter : targetExecutable.getParameters()) {
2662 ((CodeVariableElement) method.getParameters().get(index)).setName(parameter.getLocalName());
2663 index++;
2664 }
2665 return method;
2666 }
2667
2668 }
2669
2670 private class SpecializedCastNodeFactory extends BaseCastNodeFactory {
2671
2672 private final CodeTypeElement baseType;
2673 private final TypeData sourceType;
2674
2675 public SpecializedCastNodeFactory(ProcessorContext context, CodeTypeElement baseType, TypeData type, Set<TypeData> usedTargetTypes) {
2676 super(context, usedTargetTypes);
2677 this.baseType = baseType;
2678 this.sourceType = type;
2679 }
2680
2681 @Override
2682 protected CodeTypeElement create(NodeData m) {
2683 CodeTypeElement type = createClass(m, modifiers(PRIVATE, STATIC, FINAL), nodeCastClassName(m, sourceType), baseType.asType(), false);
2684 type.add(createConstructorUsingFields(modifiers(), type));
2685 return type;
2686 }
2687
2688 @Override
2689 protected void createChildren(NodeData node) {
2690 for (TypeData targetType : usedTargetTypes) {
2691 for (ExecutableTypeData targetExecutable : node.getExecutableTypes()) {
2692 if (targetExecutable.getType().equals(targetType)) {
2693 ExecutableTypeData sourceExecutable = node.findExecutableType(sourceType, targetExecutable.getEvaluatedCount());
2694 if (sourceExecutable == null) {
2695 // TODO what if there is no evaluated version?
2696 continue;
2697 }
2698 CodeExecutableElement execute = createCastExecute(sourceExecutable, targetExecutable, false);
2699 CodeExecutableElement expect = createCastExecute(sourceExecutable, targetExecutable, true);
2700 if (execute != null) {
2701 getElement().add(execute);
2702 }
2703 if (expect != null) {
2704 getElement().add(expect);
2705 }
2706 }
2707 }
2708
2709 }
2710 }
2711
2712 }
2713
2714 private class SpecializedNodeFactory extends NodeBaseFactory {
2715
2716 protected final CodeTypeElement nodeGen;
2717
2718 public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) {
2719 super(context);
2720 this.nodeGen = nodeGen;
2721 }
2722
2723 @Override
2724 public CodeTypeElement create(SpecializationData specialization) {
2725 NodeData node = specialization.getNode();
2726 TypeMirror baseType = node.getNodeType();
2727 if (nodeGen != null) {
2728 baseType = nodeGen.asType();
2729 }
2730 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); 2585 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false);
2731 2586
2732 Kind kind; 2587 Kind kind;
2733 if (specialization.isGeneric()) { 2588 if (specialization.isGeneric()) {
2734 kind = Kind.GENERIC; 2589 kind = Kind.GENERIC;
2759 @Override 2614 @Override
2760 protected void createChildren(SpecializationData specialization) { 2615 protected void createChildren(SpecializationData specialization) {
2761 CodeTypeElement clazz = getElement(); 2616 CodeTypeElement clazz = getElement();
2762 createConstructors(clazz); 2617 createConstructors(clazz);
2763 2618
2764 NodeData node = specialization.getNode();
2765
2766 if (node.needsRewrites(getContext()) && node.isPolymorphic()) {
2767 createIsCompatible(clazz, specialization);
2768 }
2769
2770 createExecuteMethods(specialization); 2619 createExecuteMethods(specialization);
2771 createCachedExecuteMethods(specialization); 2620 createCachedExecuteMethods(specialization);
2621 if (specialization.getNode().isPolymorphic()) {
2622 getElement().add(createUpdateTypes(nodeGen.asType()));
2623 }
2772 } 2624 }
2773 2625
2774 protected void createConstructors(CodeTypeElement clazz) { 2626 protected void createConstructors(CodeTypeElement clazz) {
2775 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); 2627 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass());
2776 SpecializationData specialization = getModel(); 2628 SpecializationData specialization = getModel();
2803 continue; 2655 continue;
2804 } 2656 }
2805 NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); 2657 NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName());
2806 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); 2658 List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType());
2807 if (types.size() > 1) { 2659 if (types.size() > 1) {
2808 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), typeName(param))); 2660 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), implicitTypeName(param)));
2809 superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), typeName(param))); 2661 superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), implicitTypeName(param)));
2810 2662
2811 builder.startStatement(); 2663 builder.startStatement();
2812 builder.string("this.").string(typeName(param)).string(" = ").string(typeName(param)); 2664 builder.string("this.").string(implicitTypeName(param)).string(" = ").string(implicitTypeName(param));
2813 builder.end(); 2665 builder.end();
2814 } 2666 }
2815 } 2667 }
2816 2668
2817 clazz.add(superConstructor); 2669 clazz.add(superConstructor);
2839 } 2691 }
2840 } 2692 }
2841 2693
2842 protected void createCachedExecuteMethods(SpecializationData specialization) { 2694 protected void createCachedExecuteMethods(SpecializationData specialization) {
2843 NodeData node = specialization.getNode(); 2695 NodeData node = specialization.getNode();
2696 if (!node.isPolymorphic()) {
2697 return;
2698 }
2699
2844 CodeTypeElement clazz = getElement(); 2700 CodeTypeElement clazz = getElement();
2845 for (final SpecializationData polymorphic : node.getPolymorphicSpecializations()) { 2701
2846 if (!specialization.getSignature().isCompatibleTo(polymorphic.getSignature())) { 2702 final SpecializationData polymorphic = node.getGenericPolymorphicSpecialization();
2847 continue; 2703
2848 } 2704 ExecutableElement executeCached = nodeGen.getMethod(executeCachedName(polymorphic));
2849 ExecutableElement executeCached = nodeGen.getMethod(executeCachedName(polymorphic)); 2705 // ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached,
2850 ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType()); 2706 // node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType());
2851 2707
2852 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); 2708 ExecutableTypeMethodParser parser = new ExecutableTypeMethodParser(getContext(), node);
2853 CodeTreeBuilder builder = executeMethod.createBuilder(); 2709 ExecutableTypeData execType = parser.parse(Arrays.asList(executeCached)).get(0);
2854 2710
2855 if (specialization.isGeneric() || specialization.isPolymorphic()) { 2711 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false);
2856 builder.startThrow().startNew(getContext().getType(AssertionError.class)); 2712 CodeTreeBuilder builder = executeMethod.createBuilder();
2857 builder.doubleQuote("Should not be reached."); 2713
2858 builder.end().end(); 2714 if (specialization.isGeneric() || specialization.isPolymorphic()) {
2859 } else if (specialization.isUninitialized()) { 2715 builder.startThrow().startNew(getContext().getType(AssertionError.class));
2860 builder.tree(createAppendPolymorphic(builder, specialization)); 2716 builder.doubleQuote("Should not be reached.");
2861 } else { 2717 builder.end().end();
2862 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); 2718 } else if (specialization.isUninitialized()) {
2863 elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic)); 2719 builder.tree(createAppendPolymorphic(builder, specialization));
2864 addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true, null); 2720 } else {
2865 elseBuilder.end().end(); 2721 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder);
2866 2722 elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic));
2867 boolean forceElse = specialization.getExceptions().size() > 0; 2723 addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true, null);
2868 builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), false, new CodeBlock<SpecializationData>() { 2724 elseBuilder.end().end();
2869 2725
2870 public CodeTree create(CodeTreeBuilder b, SpecializationData current) { 2726 boolean forceElse = specialization.getExceptions().size() > 0;
2871 return createGenericInvoke(b, polymorphic, current); 2727 builder.tree(createExecuteTree(builder, polymorphic, SpecializationGroup.create(specialization), false, new CodeBlock<SpecializationData>() {
2872 } 2728
2873 }, elseBuilder.getRoot(), forceElse, true)); 2729 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
2874 } 2730 return createGenericInvoke(b, polymorphic, current);
2875 clazz.add(executeMethod); 2731 }
2876 } 2732 }, elseBuilder.getRoot(), forceElse, true, true));
2733 }
2734 clazz.add(executeMethod);
2877 } 2735 }
2878 2736
2879 private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) { 2737 private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) {
2880 NodeData node = specialization.getNode(); 2738 NodeData node = specialization.getNode();
2881 2739
2907 specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end(); 2765 specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end();
2908 specializeCall.end().end(); 2766 specializeCall.end().end();
2909 2767
2910 builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot()); 2768 builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot());
2911 2769
2770 CodeTree root = builder.create().cast(nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).string("root").getRoot();
2912 builder.startIf().string("this.next0 != null").end().startBlock(); 2771 builder.startIf().string("this.next0 != null").end().startBlock();
2913 builder.startStatement().string("(").cast(nodePolymorphicClassName(node, node.getGenericPolymorphicSpecialization())).string("root).optimizeTypes()").end(); 2772 builder.startStatement().string("(").tree(root).string(").").startCall(UPDATE_TYPES_NAME).tree(root).end().end();
2914 builder.end(); 2773 builder.end();
2915 2774
2916 if (Utils.isVoid(builder.findMethod().getReturnType())) { 2775 if (Utils.isVoid(builder.findMethod().getReturnType())) {
2917 builder.returnStatement(); 2776 builder.returnStatement();
2918 } else { 2777 } else {
3024 builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), false, new CodeBlock<SpecializationData>() { 2883 builder.tree(createExecuteTree(builder, specialization, SpecializationGroup.create(specialization), false, new CodeBlock<SpecializationData>() {
3025 2884
3026 public CodeTree create(CodeTreeBuilder b, SpecializationData current) { 2885 public CodeTree create(CodeTreeBuilder b, SpecializationData current) {
3027 return createExecute(b, executable, specialization); 2886 return createExecute(b, executable, specialization);
3028 } 2887 }
3029 }, returnSpecialized, false, false)); 2888 }, returnSpecialized, false, false, false));
3030 2889
3031 return builder.getRoot(); 2890 return builder.getRoot();
3032 } 2891 }
3033 2892
3034 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { 2893 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {