Mercurial > hg > graal-compiler
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 } |