comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 9345:0a8bf24d660a

Implemented improvements to the generated source code.
author Christian Humer <christian.humer@gmail.com>
date Fri, 26 Apr 2013 22:43:23 +0200
parents e6251a86e8e3
children 86d981cd8e22
comparison
equal deleted inserted replaced
9306:2e12f1719a42 9345:0a8bf24d660a
41 41
42 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> { 42 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> {
43 43
44 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; 44 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode";
45 45
46 private static final String EXECUTE_GENERIC_NAME = "executeGeneric_";
47 private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize_";
48
46 public NodeCodeGenerator(ProcessorContext context) { 49 public NodeCodeGenerator(ProcessorContext context) {
47 super(context); 50 super(context);
48 } 51 }
49 52
50 private TypeMirror getUnexpectedValueException() { 53 private TypeMirror getUnexpectedValueException() {
241 builder.end().end(); 244 builder.end().end();
242 245
243 return builder.getRoot(); 246 return builder.getRoot();
244 } 247 }
245 248
246 private static String genClassName(NodeData node) { 249 private static String baseClassName(NodeData node) {
247 String nodeid = node.getNodeId(); 250 String nodeid = node.getNodeId();
248 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { 251 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) {
249 nodeid = nodeid.substring(0, nodeid.length() - 4); 252 nodeid = nodeid.substring(0, nodeid.length() - 4);
250 } 253 }
251 String name = Utils.firstLetterUpperCase(nodeid); 254 String name = Utils.firstLetterUpperCase(nodeid);
252 name += "GenNode"; 255 name += "BaseNode";
253 return name; 256 return name;
254 }
255
256 private String generatedGenericMethodName(SpecializationData specialization) {
257 final String prefix = "generic";
258
259 if (specialization == null) {
260 return prefix;
261 }
262
263 if (!specialization.getNode().needsRewrites(context)) {
264 return prefix;
265 }
266
267 SpecializationData prev = null;
268 for (SpecializationData current : specialization.getNode().getSpecializations()) {
269 if (specialization == current) {
270 if (prev == null || prev.isUninitialized()) {
271 return prefix;
272 } else {
273 return prefix + current.getId();
274 }
275 }
276 prev = current;
277 }
278 return prefix;
279 } 257 }
280 258
281 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { 259 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
282 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 260 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
283 startCallTypeSystemMethod(context, builder, node, methodName); 261 startCallTypeSystemMethod(context, builder, node, methodName);
417 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 395 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
418 // Implict guards based on method signature 396 // Implict guards based on method signature
419 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; 397 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
420 398
421 if (emitAssumptions) { 399 if (emitAssumptions) {
422 boolean isStatic = parent.findMethod().getModifiers().contains(STATIC);
423
424 for (String assumption : guardedSpecialization.getAssumptions()) { 400 for (String assumption : guardedSpecialization.getAssumptions()) {
425 builder.string(andOperator); 401 builder.string(andOperator);
426 if (isStatic) { 402 builder.string("this");
427 builder.string(THIS_NODE_LOCAL_VAR_NAME);
428 } else {
429 builder.string("this");
430 }
431 builder.string(".").string(assumption).string(".isValid()"); 403 builder.string(".").string(assumption).string(".isValid()");
432 andOperator = " && "; 404 andOperator = " && ";
433 } 405 }
434 } 406 }
435 407
597 return false; 569 return false;
598 } 570 }
599 return true; 571 return true;
600 } 572 }
601 573
574 private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
575 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
576 builder.startReturn().startNew(nodeSpecializationClassName(specialization));
577 if (hasCopyConstructor) {
578 builder.string(thisLocalVariableName);
579 }
580 builder.end().end();
581 return builder.getRoot();
582 }
583
602 @Override 584 @Override
603 protected void createChildren(NodeData node) { 585 protected void createChildren(NodeData node) {
604 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); 586 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
605 if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) { 587 if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) {
606 for (NodeData nodeChild : node.getDeclaredNodes()) { 588 for (NodeData nodeChild : node.getDeclaredNodes()) {
612 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { 594 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) {
613 add(new NodeFactoryFactory(context, childTypes), node); 595 add(new NodeFactoryFactory(context, childTypes), node);
614 } 596 }
615 } 597 }
616 598
617 private class NodeGenFactory extends ClassElementFactory<NodeData> { 599 private class NodeBaseFactory extends ClassElementFactory<NodeData> {
618 600
619 public NodeGenFactory(ProcessorContext context) { 601 public NodeBaseFactory(ProcessorContext context) {
620 super(context); 602 super(context);
621 } 603 }
622 604
623 @Override 605 @Override
624 protected CodeTypeElement create(NodeData node) { 606 protected CodeTypeElement create(NodeData node) {
625 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), genClassName(node), node.getNodeType(), false); 607 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false);
626 608
627 for (NodeChildData child : node.getChildren()) { 609 for (NodeChildData child : node.getChildren()) {
628 clazz.add(createChildField(child)); 610 clazz.add(createChildField(child));
629 611
630 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { 612 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) {
645 if (node.getExtensionElements() != null) { 627 if (node.getExtensionElements() != null) {
646 clazz.getEnclosedElements().addAll(node.getExtensionElements()); 628 clazz.getEnclosedElements().addAll(node.getExtensionElements());
647 } 629 }
648 630
649 return clazz; 631 return clazz;
632 }
633
634 @Override
635 protected void createChildren(NodeData node) {
636 CodeTypeElement clazz = getElement();
637
638 if (node.needsRewrites(context)) {
639 clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true));
640 }
641
642 if (node.getGenericSpecialization() != null) {
643 clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false));
644 }
650 } 645 }
651 646
652 private void createConstructors(NodeData node, CodeTypeElement clazz) { 647 private void createConstructors(NodeData node, CodeTypeElement clazz) {
653 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType()); 648 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType());
654 if (constructors.isEmpty()) { 649 if (constructors.isEmpty()) {
747 } 742 }
748 743
749 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); 744 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType));
750 return var; 745 return var;
751 } 746 }
747
748 private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) {
749 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
750
751 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name);
752 CodeTreeBuilder builder = method.createBuilder();
753
754 String prefix = null;
755 if (specialize) {
756 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
757
758 builder.startStatement();
759 builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end();
760 builder.end();
761
762 emitSpecializationListeners(builder, node);
763 builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
764 prefix = "allowed";
765 }
766
767 addInternalValueParameters(method, node.getGenericSpecialization(), true);
768
769 List<SpecializationData> specializations = node.getSpecializations();
770 if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) {
771 specializations = Arrays.asList(node.getGenericSpecialization());
772 }
773
774 // group specializations for reachabiltiy
775 List<SpecializationData> unreachableSpecializations = new ArrayList<>();
776 List<SpecializationData> filteredSpecializations = new ArrayList<>();
777 if (!specialize) {
778 unreachableSpecializations = new ArrayList<>();
779 filteredSpecializations = new ArrayList<>();
780 boolean unreachable = false;
781 for (SpecializationData specialization : specializations) {
782 if (unreachable) {
783 unreachableSpecializations.add(specialization);
784 } else {
785 filteredSpecializations.add(specialization);
786 if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) {
787 unreachable = true;
788 }
789 }
790 }
791 } else {
792 unreachableSpecializations = Collections.emptyList();
793 filteredSpecializations = specializations;
794 }
795
796 for (SpecializationData current : filteredSpecializations) {
797 if (current.isUninitialized()) {
798 continue;
799 }
800 CodeTreeBuilder execute = new CodeTreeBuilder(builder);
801
802 execute.tree(createGenericInvoke(builder, current, specialize));
803
804 if (specialize) {
805 builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end();
806 }
807 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true));
808 }
809
810 for (SpecializationData specializationData : unreachableSpecializations) {
811 builder.string("// unreachable ").string(specializationData.getId()).newLine();
812 }
813
814 if (specialize) {
815 builder.startThrow().startNew(getContext().getType(AssertionError.class)).end().end();
816 }
817
818 return method;
819 }
820
821 private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) {
822 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
823
824 if (!current.getExceptions().isEmpty()) {
825 builder.startTryBlock();
826 }
827
828 if (current.getMethod() == null) {
829 emitEncounteredSynthetic(builder);
830 } else {
831 CodeTree executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null);
832
833 if (specialize) {
834 builder.declaration(current.getReturnSignature().getPrimitiveType(), "result", executeCall);
835 builder.startStatement().startCall("super", "replace");
836 builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end();
837 builder.end().end();
838 if (current.getReturnSignature().isVoid()) {
839 builder.returnStatement();
840 } else {
841 builder.startReturn().string("result").end();
842 }
843 } else {
844 builder.startReturn().tree(executeCall).end();
845 }
846 }
847
848 if (!current.getExceptions().isEmpty()) {
849 for (SpecializationThrowsData exception : current.getExceptions()) {
850 builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx");
851 builder.string("// fall through").newLine();
852 }
853 builder.end();
854 }
855
856 return builder.getRoot();
857 }
858
859 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
860 for (TemplateMethod listener : node.getSpecializationListeners()) {
861 builder.startStatement();
862 builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
863 builder.end(); // statement
864 }
865 }
752 } 866 }
753 867
754 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { 868 private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
755 869
756 private final Map<NodeData, List<TypeElement>> childTypes; 870 private final Map<NodeData, List<TypeElement>> childTypes;
779 CodeTypeElement clazz = getElement(); 893 CodeTypeElement clazz = getElement();
780 894
781 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); 895 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers());
782 896
783 if (node.needsFactory()) { 897 if (node.needsFactory()) {
784 NodeGenFactory factory = new NodeGenFactory(context); 898 NodeBaseFactory factory = new NodeBaseFactory(context);
785 add(factory, node); 899 add(factory, node);
786 generatedNode = factory.getElement(); 900 generatedNode = factory.getElement();
787 901
788 createFactoryMethods(node, clazz, createVisibility);
789
790 if (node.needsRewrites(context)) { 902 if (node.needsRewrites(context)) {
791 clazz.add(createCreateSpecializedMethod(node, createVisibility)); 903 clazz.add(createCreateSpecializedMethod(node, createVisibility));
792 clazz.add(createSpecializeMethod(node)); 904 }
793 } 905
794 906 createFactoryMethods(node, clazz, createVisibility);
795 if (node.getGenericSpecialization() != null) {
796 List<CodeExecutableElement> genericMethods = createGeneratedGenericMethod(node);
797 for (CodeExecutableElement method : genericMethods) {
798 clazz.add(method);
799 }
800 }
801 907
802 for (SpecializationData specialization : node.getSpecializations()) { 908 for (SpecializationData specialization : node.getSpecializations()) {
803 add(new SpecializedNodeFactory(context, generatedNode), specialization); 909 add(new SpecializedNodeFactory(context, generatedNode), specialization);
804 } 910 }
805 911
1172 } 1278 }
1173 body.tree(createReturnNewSpecialization(body, node.getGenericSpecialization(), thisLocalVariableName, hasCopyConstructor)); 1279 body.tree(createReturnNewSpecialization(body, node.getGenericSpecialization(), thisLocalVariableName, hasCopyConstructor));
1174 return method; 1280 return method;
1175 } 1281 }
1176 1282
1177 private CodeExecutableElement createSpecializeMethod(NodeData node) {
1178 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize");
1179 method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
1180 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
1181 addInternalValueParameters(method, node.getGenericSpecialization(), true);
1182
1183 CodeTreeBuilder body = method.createBuilder();
1184 body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end();
1185
1186 boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null;
1187
1188 for (int i = 1; i < node.getSpecializations().size(); i++) {
1189 SpecializationData specialization = node.getSpecializations().get(i);
1190 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end();
1191
1192 CodeTree guarded = createReturnNewSpecialization(body, specialization, THIS_NODE_LOCAL_VAR_NAME, hasCopyConstructor);
1193
1194 body.tree(createGuardAndCast(body, "allowed", node.getGenericSpecialization(), specialization, false, guarded, null, true));
1195 }
1196 body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end();
1197
1198 return method;
1199 }
1200
1201 private CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) {
1202 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1203 builder.startReturn().startNew(nodeSpecializationClassName(specialization));
1204 if (hasCopyConstructor) {
1205 builder.string(thisLocalVariableName);
1206 }
1207 builder.end().end();
1208 return builder.getRoot();
1209 }
1210
1211 private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
1212 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
1213 if (node.needsRewrites(context)) {
1214 List<CodeExecutableElement> methods = new ArrayList<>();
1215
1216 List<SpecializationData> specializations = node.getSpecializations();
1217 SpecializationData prev = null;
1218 for (int i = 0; i < specializations.size(); i++) {
1219 SpecializationData current = specializations.get(i);
1220 SpecializationData next = i + 1 < specializations.size() ? specializations.get(i + 1) : null;
1221 if (prev == null || current.isUninitialized()) {
1222 prev = current;
1223 continue;
1224 } else {
1225 String methodName = generatedGenericMethodName(current);
1226 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName);
1227 method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
1228 addInternalValueParameters(method, node.getGenericSpecialization(), true);
1229
1230 emitGeneratedGenericSpecialization(method.createBuilder(), current, next);
1231
1232 methods.add(method);
1233 }
1234 prev = current;
1235 }
1236
1237 return methods;
1238 } else {
1239 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null));
1240 method.addParameter(new CodeVariableElement(generatedNode.asType(), THIS_NODE_LOCAL_VAR_NAME));
1241 addInternalValueParameters(method, node.getGenericSpecialization(), true);
1242 emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0);
1243 return Arrays.asList(method);
1244 }
1245 }
1246
1247 private void emitGeneratedGenericSpecialization(CodeTreeBuilder builder, SpecializationData current, SpecializationData next) {
1248 CodeTreeBuilder invokeMethodBuilder = new CodeTreeBuilder(builder);
1249 emitInvokeDoMethod(invokeMethodBuilder, current, 0);
1250 CodeTree invokeMethod = invokeMethodBuilder.getRoot();
1251
1252 if (next != null) {
1253 CodeTreeBuilder nextBuilder = builder.create();
1254
1255 nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
1256 nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
1257 addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
1258 nextBuilder.end().end();
1259
1260 invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot(), true);
1261 }
1262
1263 builder.tree(invokeMethod);
1264
1265 if (next != null) {
1266 builder.end();
1267 }
1268 }
1269
1270 private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) {
1271 if (!specialization.getExceptions().isEmpty()) {
1272 builder.startTryBlock();
1273 }
1274
1275 if (specialization.getMethod() == null) {
1276 emitEncounteredSynthetic(builder);
1277 } else {
1278 builder.startReturn();
1279 builder.tree(createTemplateMethodCall(builder, null, specialization.getNode().getGenericSpecialization(), specialization, null));
1280 builder.end(); // return
1281 }
1282
1283 if (!specialization.getExceptions().isEmpty()) {
1284 for (SpecializationThrowsData exception : specialization.getExceptions()) {
1285 builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level);
1286
1287 builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
1288 builder.string(THIS_NODE_LOCAL_VAR_NAME);
1289 addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
1290 builder.end().end();
1291 }
1292 builder.end();
1293 }
1294 }
1295
1296 } 1283 }
1297 1284
1298 private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> { 1285 private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
1299 1286
1300 private final CodeTypeElement nodeGen; 1287 private final CodeTypeElement nodeGen;
1340 builder.tree(result); 1327 builder.tree(result);
1341 } else { 1328 } else {
1342 clazz.remove(executeMethod); 1329 clazz.remove(executeMethod);
1343 } 1330 }
1344 } 1331 }
1345
1346 if (specialization.hasRewrite(getContext())) {
1347 buildSpecializeAndExecute(clazz, specialization);
1348 }
1349 } 1332 }
1350 1333
1351 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { 1334 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
1352 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); 1335 TypeData primaryType = specialization.getReturnType().getTypeSystemType();
1353 1336
1472 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); 1455 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
1473 if (returnVoid) { 1456 if (returnVoid) {
1474 builder.string("// ignore").newLine(); 1457 builder.string("// ignore").newLine();
1475 } else { 1458 } else {
1476 builder.startReturn(); 1459 builder.startReturn();
1477 builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("ex.getResult()"))); 1460 builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()")));
1478 builder.end(); 1461 builder.end();
1479 } 1462 }
1480 builder.end(); 1463 builder.end();
1481 1464
1482 if (!returnVoid) { 1465 if (!returnVoid) {
1483 builder.startReturn(); 1466 builder.startReturn();
1484 builder.tree(createExpectType(node, castedType, CodeTreeBuilder.singleString("value"))); 1467 builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value")));
1485 builder.end(); 1468 builder.end();
1486 } 1469 }
1487 } else { 1470 } else {
1488 if (returnVoid) { 1471 if (returnVoid) {
1489 builder.statement(primaryExecuteCall); 1472 builder.statement(primaryExecuteCall);
1490 } else { 1473 } else {
1491 builder.startReturn(); 1474 builder.startReturn();
1492 builder.tree(createExpectType(node, castedType, primaryExecuteCall)); 1475 builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall));
1493 builder.end(); 1476 builder.end();
1494 } 1477 }
1495 } 1478 }
1496 1479
1497 return builder.getRoot(); 1480 return builder.getRoot();
1498 } 1481 }
1499 1482
1500 private CodeTree createExpectType(NodeData node, ExecutableTypeData castedType, CodeTree value) { 1483 private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) {
1501 if (castedType == null) { 1484 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext());
1485 return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value);
1486 }
1487
1488 private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) {
1489 if (targetType == null) {
1502 return value; 1490 return value;
1503 } else if (castedType.getType().isVoid()) { 1491 } else if (!sourceType.needsCastTo(getContext(), targetType)) {
1504 return value;
1505 } else if (castedType.getType().isGeneric()) {
1506 return value; 1492 return value;
1507 } 1493 }
1508 1494
1509 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 1495 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1510 String targetMethodName; 1496 String targetMethodName;
1511 if (castedType.hasUnexpectedValue(getContext())) { 1497 if (expect) {
1512 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType.getType()); 1498 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType);
1513 } else { 1499 } else {
1514 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(castedType.getType()); 1500 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType);
1515 } 1501 }
1516 startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
1517
1518 builder.tree(value);
1519 builder.end().end();
1520 return builder.getRoot();
1521 }
1522
1523 private CodeTree createExpectType(NodeData node, TypeData castedType, CodeTree value) {
1524 if (castedType == null) {
1525 return value;
1526 } else if (castedType.isVoid()) {
1527 return value;
1528 } else if (castedType.isGeneric()) {
1529 return value;
1530 }
1531
1532 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1533 String targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(castedType);
1534 startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); 1502 startCallTypeSystemMethod(getContext(), builder, node, targetMethodName);
1535 1503
1536 builder.tree(value); 1504 builder.tree(value);
1537 builder.end().end(); 1505 builder.end().end();
1538 return builder.getRoot(); 1506 return builder.getRoot();
1545 } 1513 }
1546 1514
1547 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); 1515 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
1548 1516
1549 CodeTree executeNode; 1517 CodeTree executeNode;
1550 if (specialization.isUninitialized()) {
1551 builder.tree(createSpecializeCall(builder, specialization));
1552 }
1553 executeNode = createExecute(builder, executable, specialization); 1518 executeNode = createExecute(builder, executable, specialization);
1554 1519
1555 SpecializationData next = specialization.findNextSpecialization(); 1520 SpecializationData next = specialization.findNextSpecialization();
1556 CodeTree returnSpecialized = null; 1521 CodeTree returnSpecialized = null;
1557 if (next != null) { 1522 if (next != null) {
1558 returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null); 1523 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder);
1524 returnBuilder.tree(createDeoptimize(builder));
1525 returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null));
1526 returnSpecialized = returnBuilder.getRoot();
1559 } 1527 }
1560 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); 1528 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false));
1561 1529
1562 return builder.getRoot(); 1530 return builder.getRoot();
1563 } 1531 }
1568 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); 1536 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end();
1569 builder.end(); 1537 builder.end();
1570 return builder.getRoot(); 1538 return builder.getRoot();
1571 } 1539 }
1572 1540
1573 private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) {
1574 NodeData node = specialization.getNode();
1575
1576 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1577 emitSpecializationListeners(builder, node);
1578
1579 builder.startStatement();
1580 builder.startCall("replace");
1581 if (node.needsRewrites(getContext())) {
1582 builder.startCall(factoryClassName(node), "specialize");
1583 builder.string("this");
1584 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
1585 addInternalValueParameterNames(builder, specialization, specialization, null, true, true);
1586 builder.end(); // call replace, call specialize
1587 } else {
1588 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
1589 }
1590 builder.end().end();
1591 emitSpecializationListeners(builder, node);
1592 return builder.getRoot();
1593 }
1594
1595 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { 1541 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
1596 NodeData node = specialization.getNode(); 1542 NodeData node = specialization.getNode();
1597 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1543 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1598 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { 1544 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) {
1599 builder.startTryBlock(); 1545 builder.startTryBlock();
1605 builder.end(); 1551 builder.end();
1606 } 1552 }
1607 1553
1608 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); 1554 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
1609 if (specialization.isUninitialized()) { 1555 if (specialization.isUninitialized()) {
1610 String genericMethodName = generatedGenericMethodName(null); 1556 returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME);
1611 returnBuilder.startCall(factoryClassName(node), genericMethodName); 1557 returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end();
1612 returnBuilder.string("this");
1613 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); 1558 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
1614 returnBuilder.end(); 1559 returnBuilder.end();
1615 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { 1560 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
1616 emitEncounteredSynthetic(builder); 1561 emitEncounteredSynthetic(builder);
1617 } else if (specialization.isGeneric()) { 1562 } else if (specialization.isGeneric()) {
1618 String genericMethodName; 1563 returnBuilder.startCall("super", EXECUTE_GENERIC_NAME);
1619 if (!specialization.isUseSpecializationsForGeneric()) {
1620 genericMethodName = generatedGenericMethodName(specialization);
1621 } else {
1622 genericMethodName = generatedGenericMethodName(null);
1623 }
1624
1625 returnBuilder.startCall(factoryClassName(node), genericMethodName);
1626 returnBuilder.string("this");
1627 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); 1564 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
1628 returnBuilder.end(); 1565 returnBuilder.end();
1629 } else { 1566 } else {
1630 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); 1567 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null));
1631 } 1568 }
1647 } 1584 }
1648 1585
1649 if (!specialization.getExceptions().isEmpty()) { 1586 if (!specialization.getExceptions().isEmpty()) {
1650 for (SpecializationThrowsData exception : specialization.getExceptions()) { 1587 for (SpecializationThrowsData exception : specialization.getExceptions()) {
1651 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); 1588 builder.end().startCatchBlock(exception.getJavaClass(), "ex");
1652 builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null)); 1589 builder.tree(createDeoptimize(builder));
1590 builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null));
1653 } 1591 }
1654 builder.end(); 1592 builder.end();
1655 } 1593 }
1656 if (!specialization.getAssumptions().isEmpty()) { 1594 if (!specialization.getAssumptions().isEmpty()) {
1657 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); 1595 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex");
1658 builder.tree(createReturnSpecializeAndExecute(parent, executable, specialization.findNextSpecialization(), null)); 1596 builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null));
1659 builder.end(); 1597 builder.end();
1660 } 1598 }
1661 1599
1662 return builder.getRoot(); 1600 return builder.getRoot();
1663 } 1601 }
1691 builder.type(targetParameter.getType()).string(" "); 1629 builder.type(targetParameter.getType()).string(" ");
1692 builder.string(valueName(targetParameter)).string(" = "); 1630 builder.string(valueName(targetParameter)).string(" = ");
1693 builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); 1631 builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
1694 builder.end(); 1632 builder.end();
1695 } else { 1633 } else {
1696 executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); 1634 executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)));
1697 } 1635 }
1698 } else if (sourceParameter == null) { 1636 } else if (sourceParameter == null) {
1699 executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); 1637 executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter);
1700 } 1638 }
1701 1639
1708 executionVar.set(unexpectedTree); 1646 executionVar.set(unexpectedTree);
1709 builder.tree(shortCircuitTree); 1647 builder.tree(shortCircuitTree);
1710 } 1648 }
1711 } 1649 }
1712 return builder.getRoot(); 1650 return builder.getRoot();
1713 }
1714
1715 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
1716 for (TemplateMethod listener : node.getSpecializationListeners()) {
1717 builder.startStatement();
1718 builder.tree(createTemplateMethodCall(builder, null, listener, listener, null));
1719 builder.end(); // statement
1720 }
1721 } 1651 }
1722 1652
1723 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, 1653 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
1724 ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { 1654 ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
1725 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1655 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1747 builder.startStatement(); 1677 builder.startStatement();
1748 builder.string(targetVariableName); 1678 builder.string(targetVariableName);
1749 } 1679 }
1750 builder.string(" = "); 1680 builder.string(" = ");
1751 if (cast) { 1681 if (cast) {
1752 builder.tree(createExpectType(specialization.getNode(), param.getTypeSystemType(), body)); 1682 builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body));
1753 } else { 1683 } else {
1754 builder.tree(body); 1684 builder.tree(body);
1755 } 1685 }
1756 builder.end(); 1686 builder.end();
1757 1687
1759 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); 1689 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
1760 SpecializationData generic = specialization.getNode().getGenericSpecialization(); 1690 SpecializationData generic = specialization.getNode().getGenericSpecialization();
1761 ActualParameter genericParameter = generic.findParameter(param.getLocalName()); 1691 ActualParameter genericParameter = generic.findParameter(param.getLocalName());
1762 1692
1763 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); 1693 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
1694 builder.tree(createDeoptimize(builder));
1764 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); 1695 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
1765 builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param)); 1696 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param));
1766 builder.end(); // catch block 1697 builder.end(); // catch block
1767 } 1698 }
1768 1699
1769 return builder.getRoot(); 1700 return builder.getRoot();
1770 } 1701 }
1876 builder.end(); // statement 1807 builder.end(); // statement
1877 1808
1878 return builder.getRoot(); 1809 return builder.getRoot();
1879 } 1810 }
1880 1811
1881 private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) { 1812 private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
1813
1814 SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization();
1882 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); 1815 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
1883 specializeCall.startCall("specializeAndExecute"); 1816 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME);
1884 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); 1817 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
1885 addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), nextSpecialization.getNode().getGenericSpecialization(), 1818 addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
1886 exceptionParam != null ? exceptionParam.getLocalName() : null, true, true);
1887 specializeCall.end().end(); 1819 specializeCall.end().end();
1888 1820
1889 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1821 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1822
1890 builder.startReturn(); 1823 builder.startReturn();
1891 builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot())); 1824 builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot()));
1892 builder.end(); 1825 builder.end();
1893 1826
1894 return builder.getRoot(); 1827 return builder.getRoot();
1895 } 1828 }
1896 1829
1897 private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
1898 NodeData node = specialization.getNode();
1899 TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
1900
1901 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
1902 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
1903 addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
1904 clazz.add(method);
1905
1906 CodeTreeBuilder builder = method.createBuilder();
1907
1908 builder.tree(createDeoptimize(builder));
1909 emitSpecializationListeners(builder, specialization.getNode());
1910
1911 builder.startStatement();
1912 builder.startCall("replace");
1913 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
1914 addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
1915 builder.end();
1916 builder.end(); // call replace
1917 builder.end(); // statement
1918
1919 String generatedMethodName;
1920 if (specialization.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
1921 generatedMethodName = generatedGenericMethodName(null);
1922 } else {
1923 generatedMethodName = generatedGenericMethodName(specialization.findNextSpecialization());
1924 }
1925 ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName);
1926
1927 CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
1928 genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
1929 genericExecute.string("this");
1930 addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
1931 genericExecute.end(); // call generated generic
1932
1933 CodeTree genericInvocation = genericExecute.getRoot();
1934
1935 if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
1936 builder.statement(genericInvocation);
1937
1938 if (!Utils.isVoid(builder.findMethod().asType())) {
1939 builder.startReturn().defaultValue(returnType.getPrimitiveType()).end();
1940 }
1941 } else {
1942 builder.startReturn().tree(genericInvocation).end();
1943 }
1944 }
1945
1946 } 1830 }
1947 1831
1948 } 1832 }