Mercurial > hg > graal-jvmci-8
comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 10596:f43eb2f1bbbc
Truffle-DSL: code-generation of polymorphic caching
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 01 Jul 2013 20:32:20 +0200 |
parents | 00b70a864d3b |
children |
comparison
equal
deleted
inserted
replaced
10595:47233c73ca58 | 10596:f43eb2f1bbbc |
---|---|
30 import javax.lang.model.element.*; | 30 import javax.lang.model.element.*; |
31 import javax.lang.model.type.*; | 31 import javax.lang.model.type.*; |
32 import javax.lang.model.util.*; | 32 import javax.lang.model.util.*; |
33 | 33 |
34 import com.oracle.truffle.api.codegen.*; | 34 import com.oracle.truffle.api.codegen.*; |
35 import com.oracle.truffle.api.nodes.NodeInfo.Kind; | |
35 import com.oracle.truffle.codegen.processor.*; | 36 import com.oracle.truffle.codegen.processor.*; |
36 import com.oracle.truffle.codegen.processor.ast.*; | 37 import com.oracle.truffle.codegen.processor.ast.*; |
37 import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality; | 38 import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality; |
38 import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind; | 39 import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind; |
39 import com.oracle.truffle.codegen.processor.template.*; | 40 import com.oracle.truffle.codegen.processor.template.*; |
68 name += Utils.firstLetterUpperCase(specialization.getId()); | 69 name += Utils.firstLetterUpperCase(specialization.getId()); |
69 name += "Node"; | 70 name += "Node"; |
70 return name; | 71 return name; |
71 } | 72 } |
72 | 73 |
74 private static String nodePolymorphicClassName(NodeData node, SpecializationData specialization) { | |
75 String nodeid = node.getNodeId(); | |
76 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
77 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
78 } | |
79 | |
80 String name = Utils.firstLetterUpperCase(nodeid); | |
81 int index = specialization == null ? 0 : node.getPolymorphicSpecializations().indexOf(specialization); | |
82 if (index == 0) { | |
83 name += "PolymorphicNode"; | |
84 } else { | |
85 name += "Polymorphic" + index + "Node"; | |
86 } | |
87 return name; | |
88 } | |
89 | |
73 private static String valueNameEvaluated(ActualParameter targetParameter) { | 90 private static String valueNameEvaluated(ActualParameter targetParameter) { |
74 return valueName(targetParameter) + "Evaluated"; | 91 return valueName(targetParameter) + "Evaluated"; |
75 } | 92 } |
76 | 93 |
77 private static String valueName(ActualParameter param) { | 94 private static String valueName(ActualParameter param) { |
80 | 97 |
81 private static String castValueName(ActualParameter parameter) { | 98 private static String castValueName(ActualParameter parameter) { |
82 return valueName(parameter) + "Cast"; | 99 return valueName(parameter) + "Cast"; |
83 } | 100 } |
84 | 101 |
85 private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { | 102 private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) { |
86 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { | 103 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { |
87 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); | 104 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); |
88 } | 105 } |
89 for (ActualParameter parameter : specialization.getParameters()) { | 106 for (ActualParameter parameter : specialization.getParameters()) { |
90 ParameterSpec spec = parameter.getSpecification(); | 107 ParameterSpec spec = parameter.getSpecification(); |
93 } | 110 } |
94 if (spec.isLocal()) { | 111 if (spec.isLocal()) { |
95 continue; | 112 continue; |
96 } | 113 } |
97 | 114 |
98 method.addParameter(new CodeVariableElement(parameter.getType(), valueName(parameter))); | 115 String name = valueName(parameter); |
116 if (evaluated && spec.isSignature()) { | |
117 name = valueNameEvaluated(parameter); | |
118 } | |
119 | |
120 method.addParameter(new CodeVariableElement(parameter.getType(), name)); | |
99 } | 121 } |
100 } | 122 } |
101 | 123 |
102 private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { | 124 private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { |
103 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { | 125 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { |
150 boolean castedValues = sourceMethod != targetMethod; | 172 boolean castedValues = sourceMethod != targetMethod; |
151 | 173 |
152 builder.startGroup(); | 174 builder.startGroup(); |
153 ExecutableElement method = targetMethod.getMethod(); | 175 ExecutableElement method = targetMethod.getMethod(); |
154 if (method == null) { | 176 if (method == null) { |
155 throw new IllegalStateException("Cannot call synthetic operation methods."); | 177 throw new UnsupportedOperationException(); |
156 } | 178 } |
157 TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); | 179 TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); |
158 NodeData node = (NodeData) targetMethod.getTemplate(); | 180 NodeData node = (NodeData) targetMethod.getTemplate(); |
159 | 181 |
160 if (target == null) { | 182 if (target == null) { |
281 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); | 303 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); |
282 body.string(".").startCall(methodName); | 304 body.string(".").startCall(methodName); |
283 } | 305 } |
284 | 306 |
285 private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, | 307 private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, |
286 CodeTree guardedStatements, CodeTree elseStatements, boolean emitAssumptions) { | 308 CodeTree guardedStatements, CodeTree elseStatements, boolean emitAssumptions, boolean forceElse) { |
287 | 309 |
288 NodeData node = targetSpecialization.getNode(); | 310 NodeData node = targetSpecialization.getNode(); |
289 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 311 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
290 CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization, emitAssumptions); | 312 CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization, emitAssumptions); |
291 CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); | 313 CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); |
345 } | 367 } |
346 | 368 |
347 builder.tree(guardedStatements); | 369 builder.tree(guardedStatements); |
348 | 370 |
349 builder.end(ifCount); | 371 builder.end(ifCount); |
350 if (elseStatements != null && ifCount > 0) { | 372 if (elseStatements != null && (forceElse || ifCount > 0)) { |
351 builder.tree(elseStatements); | 373 builder.tree(elseStatements); |
352 } | 374 } |
353 return builder.getRoot(); | 375 return builder.getRoot(); |
354 } | 376 } |
355 | 377 |
529 builder.end(); // block | 551 builder.end(); // block |
530 } | 552 } |
531 return builder.getRoot(); | 553 return builder.getRoot(); |
532 } | 554 } |
533 | 555 |
534 private void emitEncounteredSynthetic(CodeTreeBuilder builder, SpecializationData current) { | 556 protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { |
535 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); | 557 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); |
536 builder.startGroup(); | 558 builder.startCall("createInfo0"); |
537 String sep = null; | 559 builder.doubleQuote("Unsupported values"); |
538 for (ActualParameter parameters : current.getParameters()) { | 560 addInternalValueParameterNames(builder, current, current, null, false, true); |
539 if (parameters.getSpecification().isSignature()) { | 561 builder.end().end().end(); |
540 if (sep == null) { | |
541 builder.doubleQuote("Unsupported values: " + parameters.getLocalName() + " = "); | |
542 sep = ", "; | |
543 } else { | |
544 builder.string(" + "); | |
545 builder.doubleQuote(sep + parameters.getLocalName() + " = "); | |
546 } | |
547 builder.string(" + "); | |
548 builder.string(parameters.getLocalName()); | |
549 } | |
550 } | |
551 builder.end(); | |
552 builder.end().end(); | |
553 } | 562 } |
554 | 563 |
555 private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) { | 564 private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) { |
556 List<ExecutableElement> constructors = new ArrayList<>(); | 565 List<ExecutableElement> constructors = new ArrayList<>(); |
557 for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) { | 566 for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) { |
593 | 602 |
594 if (!Utils.typeEquals(var.asType(), type.asType())) { | 603 if (!Utils.typeEquals(var.asType(), type.asType())) { |
595 return false; | 604 return false; |
596 } | 605 } |
597 return true; | 606 return true; |
598 } | |
599 | |
600 private static CodeTree createReturnNewSpecialization(CodeTreeBuilder parent, SpecializationData specialization, String thisLocalVariableName, boolean hasCopyConstructor) { | |
601 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
602 builder.startReturn().startNew(nodeSpecializationClassName(specialization)); | |
603 if (hasCopyConstructor) { | |
604 builder.string(thisLocalVariableName); | |
605 } | |
606 builder.end().end(); | |
607 return builder.getRoot(); | |
608 } | 607 } |
609 | 608 |
610 @Override | 609 @Override |
611 protected void createChildren(NodeData node) { | 610 protected void createChildren(NodeData node) { |
612 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); | 611 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); |
620 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { | 619 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { |
621 add(new NodeFactoryFactory(context, childTypes), node); | 620 add(new NodeFactoryFactory(context, childTypes), node); |
622 } | 621 } |
623 } | 622 } |
624 | 623 |
625 private class NodeBaseFactory extends ClassElementFactory<NodeData> { | |
626 | |
627 public NodeBaseFactory(ProcessorContext context) { | |
628 super(context); | |
629 } | |
630 | |
631 @Override | |
632 protected CodeTypeElement create(NodeData node) { | |
633 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); | |
634 | |
635 for (NodeChildData child : node.getChildren()) { | |
636 clazz.add(createChildField(child)); | |
637 | |
638 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { | |
639 ExecutableElement getter = (ExecutableElement) child.getAccessElement(); | |
640 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); | |
641 method.getModifiers().remove(Modifier.ABSTRACT); | |
642 method.createBuilder().startReturn().string("this.").string(child.getName()).end(); | |
643 clazz.add(method); | |
644 } | |
645 } | |
646 | |
647 for (String assumption : node.getAssumptions()) { | |
648 clazz.add(createAssumptionField(assumption)); | |
649 } | |
650 | |
651 createConstructors(node, clazz); | |
652 | |
653 if (node.getExtensionElements() != null) { | |
654 clazz.getEnclosedElements().addAll(node.getExtensionElements()); | |
655 } | |
656 | |
657 return clazz; | |
658 } | |
659 | |
660 @Override | |
661 protected void createChildren(NodeData node) { | |
662 CodeTypeElement clazz = getElement(); | |
663 | |
664 if (node.needsRewrites(context)) { | |
665 clazz.add(createGenericExecute(node, EXECUTE_SPECIALIZE_NAME, true)); | |
666 } | |
667 | |
668 if (node.getGenericSpecialization() != null) { | |
669 clazz.add(createGenericExecute(node, EXECUTE_GENERIC_NAME, false)); | |
670 } | |
671 } | |
672 | |
673 private void createConstructors(NodeData node, CodeTypeElement clazz) { | |
674 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType()); | |
675 if (constructors.isEmpty()) { | |
676 clazz.add(createUserConstructor(clazz, null)); | |
677 } else { | |
678 for (ExecutableElement constructor : constructors) { | |
679 clazz.add(createUserConstructor(clazz, constructor)); | |
680 } | |
681 } | |
682 if (node.needsRewrites(getContext())) { | |
683 clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()))); | |
684 } | |
685 } | |
686 | |
687 private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
688 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
689 CodeTreeBuilder builder = method.createBuilder(); | |
690 | |
691 if (superConstructor != null) { | |
692 for (VariableElement param : superConstructor.getParameters()) { | |
693 method.getParameters().add(CodeVariableElement.clone(param)); | |
694 } | |
695 } | |
696 | |
697 for (VariableElement var : type.getFields()) { | |
698 NodeChildData child = getModel().findChild(var.getSimpleName().toString()); | |
699 if (child != null) { | |
700 method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); | |
701 } else { | |
702 method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); | |
703 } | |
704 } | |
705 | |
706 if (superConstructor != null) { | |
707 builder.startStatement().startSuperCall(); | |
708 for (VariableElement param : superConstructor.getParameters()) { | |
709 builder.string(param.getSimpleName().toString()); | |
710 } | |
711 builder.end().end(); | |
712 } | |
713 | |
714 for (VariableElement var : type.getFields()) { | |
715 builder.startStatement(); | |
716 String fieldName = var.getSimpleName().toString(); | |
717 | |
718 CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString()); | |
719 builder.string("this.").string(var.getSimpleName().toString()); | |
720 | |
721 NodeChildData child = getModel().findChild(fieldName); | |
722 if (child != null) { | |
723 CreateCastData createCast = getModel().findCast(child.getName()); | |
724 if (createCast != null) { | |
725 fieldInit = createTemplateMethodCall(builder, null, getModel().getGenericSpecialization(), createCast, null, child.getName()); | |
726 } | |
727 } | |
728 | |
729 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
730 builder.string(" = adoptChild(").tree(fieldInit).string(")"); | |
731 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
732 builder.string(" = adoptChildren(").tree(fieldInit).string(")"); | |
733 } else { | |
734 builder.string(" = ").tree(fieldInit); | |
735 } | |
736 builder.end(); | |
737 } | |
738 return method; | |
739 } | |
740 | |
741 private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
742 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
743 CodeTreeBuilder builder = method.createBuilder(); | |
744 if (!(superConstructor == null && type.getFields().isEmpty())) { | |
745 method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); | |
746 } | |
747 | |
748 if (superConstructor != null) { | |
749 builder.startStatement().startSuperCall().string("copy").end().end(); | |
750 } | |
751 | |
752 for (VariableElement var : type.getFields()) { | |
753 builder.startStatement(); | |
754 String varName = var.getSimpleName().toString(); | |
755 builder.string("this.").string(varName); | |
756 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
757 builder.string(" = adoptChild(copy.").string(varName).string(")"); | |
758 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
759 builder.string(" = adoptChildren(copy.").string(varName).string(")"); | |
760 } else { | |
761 builder.string(" = copy.").string(varName); | |
762 } | |
763 builder.end(); | |
764 } | |
765 return method; | |
766 } | |
767 | |
768 private CodeVariableElement createAssumptionField(String assumption) { | |
769 CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); | |
770 var.getModifiers().add(Modifier.FINAL); | |
771 return var; | |
772 } | |
773 | |
774 private CodeVariableElement createChildField(NodeChildData child) { | |
775 CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); | |
776 var.getModifiers().add(Modifier.PROTECTED); | |
777 | |
778 DeclaredType annotationType; | |
779 if (child.getCardinality() == Cardinality.MANY) { | |
780 var.getModifiers().add(Modifier.FINAL); | |
781 annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); | |
782 } else { | |
783 annotationType = getContext().getTruffleTypes().getChildAnnotation(); | |
784 } | |
785 | |
786 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); | |
787 return var; | |
788 } | |
789 | |
790 private CodeExecutableElement createGenericExecute(NodeData node, String name, boolean specialize) { | |
791 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); | |
792 | |
793 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, name); | |
794 CodeTreeBuilder builder = method.createBuilder(); | |
795 | |
796 String prefix = null; | |
797 if (specialize) { | |
798 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); | |
799 | |
800 builder.startStatement(); | |
801 builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end(); | |
802 builder.end(); | |
803 | |
804 emitSpecializationListeners(builder, node); | |
805 builder.defaultDeclaration(node.getGenericSpecialization().getReturnSignature().getPrimitiveType(), "result"); | |
806 if (node.getGenericSpecialization().isUseSpecializationsForGeneric()) { | |
807 builder.defaultDeclaration(getContext().getType(boolean.class), "resultIsSet"); | |
808 } | |
809 builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); | |
810 prefix = null; | |
811 | |
812 builder.startStatement().string("StringBuilder message = new StringBuilder(reason)").end(); | |
813 builder.startStatement().startCall("message", "append").doubleQuote(" (").end().end(); | |
814 | |
815 String sep = null; | |
816 for (ActualParameter parameter : node.getGenericSpecialization().getParameters()) { | |
817 if (!parameter.getSpecification().isSignature()) { | |
818 continue; | |
819 } | |
820 | |
821 builder.startStatement(); | |
822 builder.string("message"); | |
823 if (sep != null) { | |
824 builder.startCall(".append").doubleQuote(sep).end(); | |
825 } | |
826 builder.startCall(".append").doubleQuote(parameter.getLocalName()).end(); | |
827 builder.startCall(".append").doubleQuote(" = ").end(); | |
828 builder.startCall(".append").string(parameter.getLocalName()).end(); | |
829 builder.end(); | |
830 | |
831 if (!Utils.isPrimitive(parameter.getType())) { | |
832 builder.startIf().string(parameter.getLocalName() + " != null").end(); | |
833 builder.startBlock(); | |
834 } | |
835 builder.startStatement(); | |
836 if (Utils.isPrimitive(parameter.getType())) { | |
837 builder.startCall("message.append").doubleQuote(" (" + Utils.getSimpleName(parameter.getType()) + ")").end(); | |
838 } else { | |
839 builder.startCall("message.append").doubleQuote(" (").end(); | |
840 builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end(); | |
841 builder.startCall(".append").doubleQuote(")").end(); | |
842 } | |
843 builder.end(); | |
844 if (!Utils.isPrimitive(parameter.getType())) { | |
845 builder.end(); | |
846 } | |
847 | |
848 sep = ", "; | |
849 } | |
850 | |
851 builder.startStatement().startCall("message", "append").doubleQuote(")").end().end(); | |
852 } | |
853 | |
854 addInternalValueParameters(method, node.getGenericSpecialization(), true); | |
855 | |
856 if (specialize) { | |
857 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); | |
858 } | |
859 | |
860 List<SpecializationData> specializations = node.getSpecializations(); | |
861 if (!specialize && !node.getGenericSpecialization().isUseSpecializationsForGeneric()) { | |
862 specializations = Arrays.asList(node.getGenericSpecialization()); | |
863 } | |
864 | |
865 // group specializations for reachabiltiy | |
866 List<SpecializationData> unreachableSpecializations = new ArrayList<>(); | |
867 List<SpecializationData> filteredSpecializations = new ArrayList<>(); | |
868 if (!specialize) { | |
869 unreachableSpecializations = new ArrayList<>(); | |
870 filteredSpecializations = new ArrayList<>(); | |
871 boolean unreachable = false; | |
872 for (SpecializationData specialization : specializations) { | |
873 if (unreachable) { | |
874 unreachableSpecializations.add(specialization); | |
875 } else { | |
876 filteredSpecializations.add(specialization); | |
877 if (!specialization.isUninitialized() && specialization.isGenericSpecialization(getContext())) { | |
878 unreachable = true; | |
879 } | |
880 } | |
881 } | |
882 } else { | |
883 unreachableSpecializations = Collections.emptyList(); | |
884 filteredSpecializations = specializations; | |
885 } | |
886 | |
887 for (SpecializationData current : filteredSpecializations) { | |
888 if (current.isUninitialized()) { | |
889 continue; | |
890 } | |
891 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
892 | |
893 execute.tree(createGenericInvoke(builder, current, specialize)); | |
894 | |
895 if (specialize && !current.isGeneric()) { | |
896 builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); | |
897 } | |
898 | |
899 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true)); | |
900 } | |
901 | |
902 for (SpecializationData specializationData : unreachableSpecializations) { | |
903 builder.string("// unreachable ").string(specializationData.getId()).newLine(); | |
904 } | |
905 | |
906 return method; | |
907 } | |
908 | |
909 private CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData current, boolean specialize) { | |
910 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
911 | |
912 if (!current.getExceptions().isEmpty()) { | |
913 builder.startTryBlock(); | |
914 } | |
915 | |
916 CodeTree executeCall = null; | |
917 if (current.getMethod() != null) { | |
918 executeCall = createTemplateMethodCall(builder, null, current.getNode().getGenericSpecialization(), current, null); | |
919 } | |
920 | |
921 if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { | |
922 emitEncounteredSynthetic(builder, current); | |
923 } else if (specialize) { | |
924 | |
925 if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { | |
926 builder.startIf().string("!resultIsSet").end().startBlock(); | |
927 if (executeCall != null) { | |
928 if (current.getReturnSignature().isVoid()) { | |
929 builder.statement(executeCall); | |
930 } else { | |
931 builder.startStatement().string("result = ").tree(executeCall).end(); | |
932 } | |
933 builder.statement("resultIsSet = true"); | |
934 } else { | |
935 emitEncounteredSynthetic(builder, current); | |
936 } | |
937 builder.end(); | |
938 } | |
939 | |
940 if (!current.isGeneric()) { | |
941 builder.startIf().string("allowed").end().startBlock(); | |
942 } | |
943 | |
944 if (!current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) { | |
945 if (current.getReturnSignature().isVoid()) { | |
946 builder.statement(executeCall); | |
947 } else { | |
948 builder.startStatement().string("result = ").tree(executeCall).end(); | |
949 } | |
950 } | |
951 | |
952 builder.startStatement().startCall("super", "replace"); | |
953 builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); | |
954 builder.string("message.toString()"); | |
955 builder.end().end(); | |
956 | |
957 if (current.getReturnSignature().isVoid()) { | |
958 builder.returnStatement(); | |
959 } else { | |
960 builder.startReturn().string("result").end(); | |
961 } | |
962 if (!current.isGeneric()) { | |
963 builder.end(); | |
964 } | |
965 } else { | |
966 if (executeCall == null) { | |
967 emitEncounteredSynthetic(builder, current); | |
968 } else { | |
969 builder.startReturn().tree(executeCall).end(); | |
970 } | |
971 } | |
972 | |
973 if (!current.getExceptions().isEmpty()) { | |
974 for (SpecializationThrowsData exception : current.getExceptions()) { | |
975 builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); | |
976 builder.string("// fall through").newLine(); | |
977 } | |
978 builder.end(); | |
979 } | |
980 | |
981 return builder.getRoot(); | |
982 } | |
983 | |
984 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { | |
985 for (TemplateMethod listener : node.getSpecializationListeners()) { | |
986 builder.startStatement(); | |
987 builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); | |
988 builder.end(); // statement | |
989 } | |
990 } | |
991 } | |
992 | |
993 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { | 624 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { |
994 | 625 |
995 private final Map<NodeData, List<TypeElement>> childTypes; | 626 private final Map<NodeData, List<TypeElement>> childTypes; |
996 | 627 |
997 private CodeTypeElement generatedNode; | 628 private CodeTypeElement generatedNode; |
1019 | 650 |
1020 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); | 651 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); |
1021 | 652 |
1022 if (node.needsFactory()) { | 653 if (node.needsFactory()) { |
1023 NodeBaseFactory factory = new NodeBaseFactory(context); | 654 NodeBaseFactory factory = new NodeBaseFactory(context); |
1024 add(factory, node); | 655 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); |
1025 generatedNode = factory.getElement(); | 656 generatedNode = factory.getElement(); |
1026 | 657 |
1027 if (node.needsRewrites(context)) { | 658 if (node.needsRewrites(context)) { |
1028 clazz.add(createCreateSpecializedMethod(node, createVisibility)); | 659 clazz.add(createCreateGenericMethod(node, createVisibility)); |
1029 } | 660 } |
1030 | 661 |
1031 createFactoryMethods(node, clazz, createVisibility); | 662 createFactoryMethods(node, clazz, createVisibility); |
1032 | 663 |
664 PolymorphicNodeFactory generic = null; | |
665 for (SpecializationData specialization : node.getPolymorphicSpecializations()) { | |
666 PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(context, generic == null ? generatedNode : generic.getElement(), generic == null); | |
667 add(polymorphicFactory, specialization); | |
668 if (generic == null) { | |
669 generic = polymorphicFactory; | |
670 } | |
671 } | |
672 | |
1033 for (SpecializationData specialization : node.getSpecializations()) { | 673 for (SpecializationData specialization : node.getSpecializations()) { |
674 if (!specialization.isReachable()) { | |
675 continue; | |
676 } | |
1034 add(new SpecializedNodeFactory(context, generatedNode), specialization); | 677 add(new SpecializedNodeFactory(context, generatedNode), specialization); |
1035 } | 678 } |
1036 | 679 |
1037 TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); | 680 TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); |
1038 clazz.getImplements().add(nodeFactory); | 681 clazz.getImplements().add(nodeFactory); |
1039 clazz.add(createCreateNodeMethod(node)); | 682 clazz.add(createCreateNodeMethod(node)); |
1040 clazz.add(createCreateNodeSpecializedMethod(node)); | 683 clazz.add(createCreateNodeGenericMethod(node)); |
1041 clazz.add(createGetNodeClassMethod(node)); | 684 clazz.add(createGetNodeClassMethod(node)); |
1042 clazz.add(createGetNodeSignaturesMethod()); | 685 clazz.add(createGetNodeSignaturesMethod()); |
1043 clazz.add(createGetChildrenSignatureMethod(node)); | 686 clazz.add(createGetChildrenSignatureMethod(node)); |
1044 clazz.add(createGetInstanceMethod(node, createVisibility)); | 687 clazz.add(createGetInstanceMethod(node, createVisibility)); |
1045 clazz.add(createInstanceConstant(node, clazz.asType())); | 688 clazz.add(createInstanceConstant(node, clazz.asType())); |
1195 builder.end().end(); | 838 builder.end().end(); |
1196 builder.end(); // else block | 839 builder.end(); // else block |
1197 return method; | 840 return method; |
1198 } | 841 } |
1199 | 842 |
1200 private CodeExecutableElement createCreateNodeSpecializedMethod(NodeData node) { | 843 private CodeExecutableElement createCreateNodeGenericMethod(NodeData node) { |
1201 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeSpecialized"); | 844 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeGeneric"); |
1202 CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); | 845 CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); |
1203 CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Class.class), "types"); | |
1204 method.addParameter(nodeParam); | 846 method.addParameter(nodeParam); |
1205 method.addParameter(arguments); | |
1206 method.setVarArgs(true); | |
1207 | 847 |
1208 CodeTreeBuilder builder = method.createBuilder(); | 848 CodeTreeBuilder builder = method.createBuilder(); |
1209 if (!node.needsRewrites(getContext())) { | 849 if (!node.needsRewrites(getContext())) { |
1210 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end(); | 850 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end(); |
1211 } else { | 851 } else { |
1212 builder.startIf(); | 852 builder.startReturn().startCall("createGeneric"); |
1213 builder.string("types.length == 1"); | |
1214 builder.end(); | |
1215 builder.startBlock(); | |
1216 | |
1217 builder.startReturn().startCall("createSpecialized"); | |
1218 builder.startGroup(); | |
1219 builder.string(THIS_NODE_LOCAL_VAR_NAME); | 853 builder.string(THIS_NODE_LOCAL_VAR_NAME); |
1220 builder.end(); | |
1221 builder.string("types[0]"); | |
1222 builder.end().end(); | 854 builder.end().end(); |
1223 | 855 } |
1224 builder.end(); | |
1225 builder.startElseBlock(); | |
1226 builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); | |
1227 builder.doubleQuote("Invalid createSpecialized signature."); | |
1228 builder.end().end(); | |
1229 builder.end(); | |
1230 } | |
1231 | |
1232 return method; | 856 return method; |
1233 } | 857 } |
1234 | 858 |
1235 private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { | 859 private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { |
1236 TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); | 860 TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); |
1360 } | 984 } |
1361 body.end(); | 985 body.end(); |
1362 return method; | 986 return method; |
1363 } | 987 } |
1364 | 988 |
1365 private CodeExecutableElement createCreateSpecializedMethod(NodeData node, Modifier visibility) { | 989 private CodeExecutableElement createCreateGenericMethod(NodeData node, Modifier visibility) { |
1366 CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createSpecialized"); | 990 CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createGeneric"); |
1367 if (visibility != null) { | 991 if (visibility != null) { |
1368 method.getModifiers().add(visibility); | 992 method.getModifiers().add(visibility); |
1369 } | 993 } |
1370 method.getModifiers().add(Modifier.STATIC); | 994 method.getModifiers().add(Modifier.STATIC); |
1371 | |
1372 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); | 995 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); |
1373 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); | |
1374 | 996 |
1375 CodeTreeBuilder body = method.createBuilder(); | 997 CodeTreeBuilder body = method.createBuilder(); |
1376 | 998 |
1377 boolean hasCopyConstructor = findCopyConstructor(generatedNode.asType()) != null; | 999 SpecializationData found = null; |
1378 | 1000 List<SpecializationData> specializations = node.getSpecializations(); |
1379 final String thisLocalVariableName = THIS_NODE_LOCAL_VAR_NAME + "Cast"; | 1001 for (int i = 0; i < specializations.size(); i++) { |
1380 | 1002 if (specializations.get(i).isReachable()) { |
1381 if (hasCopyConstructor) { | 1003 found = specializations.get(i); |
1382 body.startStatement(); | 1004 } |
1383 body.type(generatedNode.asType()).string(" ").string(thisLocalVariableName); | 1005 } |
1384 body.string(" = ").string("(").type(generatedNode.asType()).string(") ").string(THIS_NODE_LOCAL_VAR_NAME); | 1006 |
1385 body.end(); | 1007 if (found == null) { |
1386 } | 1008 body.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); |
1387 | 1009 } else { |
1388 boolean first = true; | 1010 body.startReturn().startNew(nodeSpecializationClassName(found)).startGroup().cast(baseClassName(node)).string(THIS_NODE_LOCAL_VAR_NAME).end().end().end(); |
1389 for (TypeData type : node.getTypeSystem().getTypes()) { | 1011 } |
1390 SpecializationData specialization = node.findUniqueSpecialization(type); | |
1391 if (specialization != null && !type.isGeneric()) { | |
1392 if (first) { | |
1393 body.startIf(); | |
1394 first = false; | |
1395 } else { | |
1396 body.startElseIf(); | |
1397 } | |
1398 body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); | |
1399 body.tree(createReturnNewSpecialization(body, specialization, thisLocalVariableName, hasCopyConstructor)); | |
1400 | |
1401 body.end(); // if | |
1402 } | |
1403 } | |
1404 body.tree(createReturnNewSpecialization(body, node.getGenericSpecialization(), thisLocalVariableName, hasCopyConstructor)); | |
1405 return method; | 1012 return method; |
1406 } | 1013 } |
1407 | 1014 } |
1408 } | 1015 |
1409 | 1016 private class NodeBaseFactory extends ClassElementFactory<SpecializationData> { |
1410 private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> { | 1017 |
1411 | 1018 public NodeBaseFactory(ProcessorContext context) { |
1412 private final CodeTypeElement nodeGen; | |
1413 | |
1414 public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) { | |
1415 super(context); | 1019 super(context); |
1416 this.nodeGen = nodeGen; | |
1417 } | 1020 } |
1418 | 1021 |
1419 @Override | 1022 @Override |
1420 public CodeTypeElement create(SpecializationData specialization) { | 1023 protected CodeTypeElement create(SpecializationData specialization) { |
1421 NodeData node = specialization.getNode(); | 1024 NodeData node = specialization.getNode(); |
1422 TypeMirror baseType = node.getNodeType(); | 1025 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); |
1423 if (nodeGen != null) { | 1026 |
1424 baseType = nodeGen.asType(); | 1027 for (NodeChildData child : node.getChildren()) { |
1425 } | 1028 clazz.add(createChildField(child)); |
1426 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); | 1029 |
1427 | 1030 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { |
1428 String shortName = specialization.getNode().getShortName(); | 1031 ExecutableElement getter = (ExecutableElement) child.getAccessElement(); |
1429 CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); | 1032 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); |
1430 if (shortName != null) { | 1033 method.getModifiers().remove(Modifier.ABSTRACT); |
1431 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); | 1034 method.createBuilder().startReturn().string("this.").string(child.getName()).end(); |
1432 } | 1035 clazz.add(method); |
1433 | 1036 } |
1434 DeclaredType nodeinfoKind = getContext().getTruffleTypes().getNodeInfoKind(); | 1037 } |
1435 VariableElement kind; | 1038 |
1436 if (specialization.isGeneric()) { | 1039 for (String assumption : node.getAssumptions()) { |
1437 kind = Utils.findVariableElement(nodeinfoKind, "GENERIC"); | 1040 clazz.add(createAssumptionField(assumption)); |
1438 } else if (specialization.isUninitialized()) { | 1041 } |
1439 kind = Utils.findVariableElement(nodeinfoKind, "UNINITIALIZED"); | 1042 |
1440 } else { | 1043 createConstructors(node, clazz); |
1441 kind = Utils.findVariableElement(nodeinfoKind, "SPECIALIZED"); | |
1442 } | |
1443 | |
1444 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("kind"), new CodeAnnotationValue(kind)); | |
1445 | |
1446 clazz.getAnnotationMirrors().add(nodeInfoMirror); | |
1447 | 1044 |
1448 return clazz; | 1045 return clazz; |
1046 } | |
1047 | |
1048 protected String typeGetterName(ActualParameter parameter) { | |
1049 return "get" + Utils.firstLetterUpperCase(parameter.getLocalName()) + "Type"; | |
1449 } | 1050 } |
1450 | 1051 |
1451 @Override | 1052 @Override |
1452 protected void createChildren(SpecializationData specialization) { | 1053 protected void createChildren(SpecializationData specialization) { |
1054 NodeData node = specialization.getNode(); | |
1453 CodeTypeElement clazz = getElement(); | 1055 CodeTypeElement clazz = getElement(); |
1454 NodeData node = specialization.getNode(); | 1056 |
1455 | 1057 if (node.needsRewrites(context)) { |
1456 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); | 1058 |
1457 for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { | 1059 if (node.getPolymorphicDepth() > 1) { |
1458 ExecutableElement superConstructor = createSuperConstructor(clazz, constructor); | 1060 |
1459 if (superConstructor != null) { | 1061 CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0"); |
1460 clazz.add(superConstructor); | 1062 var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); |
1461 } | 1063 clazz.add(var); |
1462 } | 1064 |
1463 | 1065 CodeExecutableElement setter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(void.class), "setNext0"); |
1464 for (ExecutableTypeData execType : node.getExecutableTypes()) { | 1066 setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0")); |
1465 if (execType.isFinal()) { | 1067 CodeTreeBuilder builder = setter.createBuilder(); |
1068 builder.statement("this.next0 = adoptChild(next0)"); | |
1069 clazz.add(setter); | |
1070 | |
1071 createTypeGetters(clazz, node.getGenericSpecialization()); | |
1072 | |
1073 clazz.add(createCreateSpecialization(node)); | |
1074 | |
1075 CodeExecutableElement genericCachedExecute = null; | |
1076 for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { | |
1077 CodeExecutableElement cachedExecute = createCachedExecute(node, polymorph, genericCachedExecute); | |
1078 clazz.add(cachedExecute); | |
1079 if (genericCachedExecute == null) { | |
1080 genericCachedExecute = cachedExecute; | |
1081 } | |
1082 } | |
1083 } | |
1084 | |
1085 clazz.add(createGenericExecuteAndSpecialize(node)); | |
1086 clazz.add(createInfoMessage(node)); | |
1087 } | |
1088 | |
1089 if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) { | |
1090 clazz.add(createGenericExecute(node)); | |
1091 } | |
1092 } | |
1093 | |
1094 private Element createInfoMessage(NodeData node) { | |
1095 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), "createInfo0"); | |
1096 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message")); | |
1097 addInternalValueParameters(method, node.getGenericSpecialization(), false, false); | |
1098 | |
1099 CodeTreeBuilder builder = method.createBuilder(); | |
1100 builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end(); | |
1101 builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end(); | |
1102 | |
1103 String sep = null; | |
1104 for (ActualParameter parameter : node.getGenericSpecialization().getParameters()) { | |
1105 if (!parameter.getSpecification().isSignature()) { | |
1466 continue; | 1106 continue; |
1467 } | 1107 } |
1468 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType); | 1108 |
1469 clazz.add(executeMethod); | 1109 builder.startStatement(); |
1470 CodeTreeBuilder builder = executeMethod.createBuilder(); | 1110 builder.string("builder"); |
1471 CodeTree result = createExecuteBody(builder, specialization, execType); | 1111 if (sep != null) { |
1472 if (result != null) { | 1112 builder.startCall(".append").doubleQuote(sep).end(); |
1473 builder.tree(result); | 1113 } |
1114 builder.startCall(".append").doubleQuote(parameter.getLocalName()).end(); | |
1115 builder.startCall(".append").doubleQuote(" = ").end(); | |
1116 builder.startCall(".append").string(parameter.getLocalName()).end(); | |
1117 builder.end(); | |
1118 | |
1119 if (!Utils.isPrimitive(parameter.getType())) { | |
1120 builder.startIf().string(parameter.getLocalName() + " != null").end(); | |
1121 builder.startBlock(); | |
1122 } | |
1123 builder.startStatement(); | |
1124 if (Utils.isPrimitive(parameter.getType())) { | |
1125 builder.startCall("builder.append").doubleQuote(" (" + Utils.getSimpleName(parameter.getType()) + ")").end(); | |
1474 } else { | 1126 } else { |
1475 clazz.remove(executeMethod); | 1127 builder.startCall("builder.append").doubleQuote(" (").end(); |
1476 } | 1128 builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end(); |
1477 } | 1129 builder.startCall(".append").doubleQuote(")").end(); |
1478 } | 1130 } |
1479 | 1131 builder.end(); |
1480 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { | 1132 if (!Utils.isPrimitive(parameter.getType())) { |
1481 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | 1133 builder.end(); |
1482 | 1134 } |
1135 | |
1136 sep = ", "; | |
1137 } | |
1138 | |
1139 builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end(); | |
1140 | |
1141 builder.startReturn().string("builder.toString()").end(); | |
1142 | |
1143 return method; | |
1144 } | |
1145 | |
1146 protected void createTypeGetters(CodeTypeElement clazz, SpecializationData specialization) { | |
1147 for (ActualParameter parameter : specialization.getReturnTypeAndParameters()) { | |
1148 if (!parameter.getSpecification().isSignature()) { | |
1149 continue; | |
1150 } | |
1151 CodeExecutableElement typeGetter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(Class.class), typeGetterName(parameter)); | |
1152 CodeTreeBuilder builder = typeGetter.createBuilder(); | |
1153 builder.startReturn().typeLiteral(parameter.getType()).end(); | |
1154 clazz.add(typeGetter); | |
1155 } | |
1156 } | |
1157 | |
1158 private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) { | |
1159 int index = node.getPolymorphicSpecializations().indexOf(polymorph); | |
1160 assert index != -1; | |
1161 boolean generic = index == 0; | |
1162 | |
1163 String name = "executeCached" + index; | |
1164 CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name); | |
1165 addInternalValueParameters(cachedExecute, polymorph, true, true); | |
1166 | |
1167 if (generic) { | |
1168 cachedExecute.getModifiers().add(ABSTRACT); | |
1169 } else { | |
1170 SpecializationData genericPolymorph = node.getPolymorphicSpecializations().get(0); | |
1171 CodeTreeBuilder builder = cachedExecute.createBuilder(); | |
1172 ExecutableTypeData genericExecutable = new ExecutableTypeData(genericPolymorph, genericPolymorphMethod, node.getTypeSystem(), genericPolymorph.getReturnType().getTypeSystemType()); | |
1173 ExecutableTypeData specificExecutable = new ExecutableTypeData(polymorph, cachedExecute, node.getTypeSystem(), polymorph.getReturnType().getTypeSystemType()); | |
1174 builder.tree(createCastingExecute(builder, polymorph, specificExecutable, genericExecutable)); | |
1175 } | |
1176 | |
1177 return cachedExecute; | |
1178 | |
1179 } | |
1180 | |
1181 private CodeExecutableElement createCreateSpecialization(NodeData node) { | |
1182 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getElement().asType(), "createSpezialization0"); | |
1183 method.getParameters().add(new CodeVariableElement(context.getType(Class.class), "clazz")); | |
1184 CodeTreeBuilder builder = method.createBuilder(); | |
1185 | |
1186 builder.startStatement().type(getElement().asType()).string(" node").end(); | |
1187 | |
1188 boolean elseIf = false; | |
1189 for (SpecializationData specialization : node.getSpecializations()) { | |
1190 if (specialization.isGeneric() || specialization.isUninitialized()) { | |
1191 continue; | |
1192 } | |
1193 | |
1194 elseIf = builder.startIf(elseIf); | |
1195 builder.startGroup().string("clazz == ").string(nodeSpecializationClassName(specialization)).string(".class").end(); | |
1196 builder.end(); | |
1197 builder.startBlock(); | |
1198 builder.startStatement(); | |
1199 builder.string("node = "); | |
1200 builder.startNew(nodeSpecializationClassName(specialization)).string("this").end(); | |
1201 builder.end(); | |
1202 builder.end(); | |
1203 } | |
1204 | |
1205 builder.startElseBlock(); | |
1206 builder.startThrow().startNew(context.getType(AssertionError.class)).end().end(); | |
1207 builder.end(); | |
1208 | |
1209 builder.startStatement().startCall("node", "setNext0"); | |
1210 builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); | |
1211 builder.end().end(); | |
1212 | |
1213 builder.startReturn().string("node").end(); | |
1214 | |
1215 return method; | |
1216 } | |
1217 | |
1218 private void createConstructors(NodeData node, CodeTypeElement clazz) { | |
1219 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType()); | |
1220 if (constructors.isEmpty()) { | |
1221 clazz.add(createUserConstructor(clazz, null)); | |
1222 } else { | |
1223 for (ExecutableElement constructor : constructors) { | |
1224 clazz.add(createUserConstructor(clazz, constructor)); | |
1225 } | |
1226 } | |
1227 if (node.needsRewrites(getContext())) { | |
1228 clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()))); | |
1229 } | |
1230 } | |
1231 | |
1232 private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
1233 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
1234 CodeTreeBuilder builder = method.createBuilder(); | |
1235 | |
1236 NodeData node = getModel().getNode(); | |
1237 | |
1238 if (superConstructor != null) { | |
1239 for (VariableElement param : superConstructor.getParameters()) { | |
1240 method.getParameters().add(CodeVariableElement.clone(param)); | |
1241 } | |
1242 } | |
1243 | |
1244 for (VariableElement var : type.getFields()) { | |
1245 NodeChildData child = node.findChild(var.getSimpleName().toString()); | |
1246 if (child != null) { | |
1247 method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); | |
1248 } else { | |
1249 method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); | |
1250 } | |
1251 } | |
1252 | |
1253 if (superConstructor != null) { | |
1254 builder.startStatement().startSuperCall(); | |
1255 for (VariableElement param : superConstructor.getParameters()) { | |
1256 builder.string(param.getSimpleName().toString()); | |
1257 } | |
1258 builder.end().end(); | |
1259 } | |
1260 | |
1261 for (VariableElement var : type.getFields()) { | |
1262 builder.startStatement(); | |
1263 String fieldName = var.getSimpleName().toString(); | |
1264 | |
1265 CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString()); | |
1266 builder.string("this.").string(var.getSimpleName().toString()); | |
1267 | |
1268 NodeChildData child = node.findChild(fieldName); | |
1269 if (child != null) { | |
1270 CreateCastData createCast = node.findCast(child.getName()); | |
1271 if (createCast != null) { | |
1272 fieldInit = createTemplateMethodCall(builder, null, node.getGenericSpecialization(), createCast, null, child.getName()); | |
1273 } | |
1274 } | |
1275 | |
1276 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
1277 builder.string(" = adoptChild(").tree(fieldInit).string(")"); | |
1278 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
1279 builder.string(" = adoptChildren(").tree(fieldInit).string(")"); | |
1280 } else { | |
1281 builder.string(" = ").tree(fieldInit); | |
1282 } | |
1283 builder.end(); | |
1284 } | |
1285 return method; | |
1286 } | |
1287 | |
1288 private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
1289 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
1290 CodeTreeBuilder builder = method.createBuilder(); | |
1291 if (!(superConstructor == null && type.getFields().isEmpty())) { | |
1292 method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); | |
1293 } | |
1294 | |
1295 if (superConstructor != null) { | |
1296 builder.startStatement().startSuperCall().string("copy").end().end(); | |
1297 } | |
1298 | |
1299 for (VariableElement var : type.getFields()) { | |
1300 builder.startStatement(); | |
1301 String varName = var.getSimpleName().toString(); | |
1302 builder.string("this.").string(varName); | |
1303 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
1304 builder.string(" = adoptChild(copy.").string(varName).string(")"); | |
1305 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
1306 builder.string(" = adoptChildren(copy.").string(varName).string(")"); | |
1307 } else { | |
1308 builder.string(" = copy.").string(varName); | |
1309 } | |
1310 builder.end(); | |
1311 } | |
1312 if (getModel().getNode().getPolymorphicDepth() > 1) { | |
1313 builder.statement("this.next0 = adoptChild(copy.next0)"); | |
1314 } | |
1315 | |
1316 return method; | |
1317 } | |
1318 | |
1319 private CodeVariableElement createAssumptionField(String assumption) { | |
1320 CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); | |
1321 var.getModifiers().add(Modifier.FINAL); | |
1322 return var; | |
1323 } | |
1324 | |
1325 private CodeVariableElement createChildField(NodeChildData child) { | |
1326 CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); | |
1327 var.getModifiers().add(Modifier.PROTECTED); | |
1328 | |
1329 DeclaredType annotationType; | |
1330 if (child.getCardinality() == Cardinality.MANY) { | |
1331 annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); | |
1332 } else { | |
1333 annotationType = getContext().getTruffleTypes().getChildAnnotation(); | |
1334 } | |
1335 | |
1336 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); | |
1337 return var; | |
1338 } | |
1339 | |
1340 private CodeExecutableElement createGenericExecuteAndSpecialize(NodeData node) { | |
1341 | |
1342 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); | |
1343 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME); | |
1344 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); | |
1345 addInternalValueParameters(method, node.getGenericSpecialization(), true, false); | |
1346 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); | |
1347 | |
1348 CodeTreeBuilder builder = method.createBuilder(); | |
1349 builder.startStatement(); | |
1350 builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end(); | |
1351 builder.end(); | |
1352 | |
1353 emitSpecializationListeners(builder, node); | |
1354 builder.defaultDeclaration(node.getGenericSpecialization().getReturnType().getTypeSystemType().getPrimitiveType(), "result"); | |
1355 | |
1356 builder.defaultDeclaration(getContext().getType(Class.class), "resultClass"); | |
1357 | |
1358 builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); | |
1359 | |
1360 builder.startStatement().string("String message = ").startCall("createInfo0").string("reason"); | |
1361 addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, false, true); | |
1362 builder.end().end(); | |
1363 | |
1364 String prefix = null; | |
1365 | |
1366 List<SpecializationData> specializations = node.getSpecializations(); | |
1367 | |
1368 for (SpecializationData current : specializations) { | |
1369 if (current.isUninitialized() || !current.isReachable()) { | |
1370 continue; | |
1371 } | |
1372 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1373 | |
1374 execute.tree(createGenericInvokeAndSpecialize(builder, node.getGenericSpecialization(), current)); | |
1375 | |
1376 if (!current.isGeneric()) { | |
1377 builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); | |
1378 } | |
1379 | |
1380 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); | |
1381 } | |
1382 | |
1383 for (SpecializationData current : specializations) { | |
1384 if (current.isUninitialized() || current.isReachable()) { | |
1385 continue; | |
1386 } | |
1387 builder.string("// unreachable ").string(current.getId()).newLine(); | |
1388 } | |
1389 | |
1390 return method; | |
1391 } | |
1392 | |
1393 private CodeExecutableElement createGenericExecute(NodeData node) { | |
1394 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); | |
1395 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_GENERIC_NAME); | |
1396 addInternalValueParameters(method, node.getGenericSpecialization(), true, false); | |
1397 CodeTreeBuilder builder = method.createBuilder(); | |
1398 | |
1399 String prefix = null; | |
1400 List<SpecializationData> specializations = node.getSpecializations(); | |
1401 | |
1402 for (SpecializationData current : specializations) { | |
1403 if (current.isUninitialized() || !current.isReachable()) { | |
1404 continue; | |
1405 } | |
1406 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1407 execute.tree(createGenericInvoke(builder, node.getGenericSpecialization(), current)); | |
1408 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); | |
1409 } | |
1410 | |
1411 for (SpecializationData current : specializations) { | |
1412 if (current.isUninitialized() || current.isReachable()) { | |
1413 continue; | |
1414 } | |
1415 builder.string("// unreachable ").string(current.getId()).newLine(); | |
1416 } | |
1417 | |
1418 return method; | |
1419 } | |
1420 | |
1421 protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { | |
1483 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 1422 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1484 | 1423 |
1485 List<ExecutableTypeData> primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount()); | 1424 if (current.getMethod() == null) { |
1486 | 1425 emitEncounteredSynthetic(builder, current); |
1487 if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) { | |
1488 builder.tree(createFunctionalExecute(builder, specialization, execType)); | |
1489 } else if (needsCastingExecuteMethod(execType, primaryType)) { | |
1490 assert !primaryExecutes.isEmpty(); | |
1491 builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0))); | |
1492 } else { | 1426 } else { |
1493 return null; | 1427 builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); |
1494 } | 1428 } |
1429 | |
1430 return encloseThrowsWithFallThrough(current, builder.getRoot()); | |
1431 } | |
1432 | |
1433 protected CodeTree createGenericInvokeAndSpecialize(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { | |
1434 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1435 | |
1436 NodeData node = current.getNode(); | |
1437 | |
1438 builder.startIf().string("resultClass == null").end().startBlock(); | |
1439 if (current.getMethod() != null) { | |
1440 CodeTree executeCall = createTemplateMethodCall(builder, null, source, current, null); | |
1441 if (current.getReturnType().getTypeSystemType().isVoid()) { | |
1442 builder.statement(executeCall); | |
1443 } else { | |
1444 builder.startStatement().string("result = ").tree(executeCall).end(); | |
1445 } | |
1446 builder.startStatement(); | |
1447 builder.string("resultClass = ").string(nodeSpecializationClassName(current)).string(".class"); | |
1448 builder.end(); | |
1449 } else { | |
1450 emitEncounteredSynthetic(builder, current); | |
1451 } | |
1452 builder.end(); | |
1453 | |
1454 boolean ifAllowed = current.hasRewrite(getContext()); | |
1455 if (ifAllowed) { | |
1456 builder.startIf().string("allowed").end().startBlock(); | |
1457 } | |
1458 | |
1459 if (!current.isGeneric() || node.getPolymorphicDepth() <= 1) { | |
1460 // generic rewrite | |
1461 builder.tree(createRewriteGeneric(builder, current)); | |
1462 } else { | |
1463 boolean rewriteableToGeneric = node.getGenericSpecialization().getMethod() != null && node.getGenericSpecialization().isReachable(); | |
1464 if (rewriteableToGeneric) { | |
1465 builder.startIf().string("resultClass == ").string(nodeSpecializationClassName(node.getGenericSpecialization())).string(".class").end(); | |
1466 builder.startBlock(); | |
1467 | |
1468 boolean maybePolymorphic = node.getPolymorphicDepth() > 1; | |
1469 if (maybePolymorphic) { | |
1470 builder.startIf().string("next0 == null").end(); | |
1471 builder.startBlock(); | |
1472 } | |
1473 builder.tree(createRewriteGeneric(builder, current)); | |
1474 if (maybePolymorphic) { | |
1475 builder.end().startElseBlock(); | |
1476 builder.statement("Node searchNode = super.getParent()"); | |
1477 builder.startWhile().string("searchNode != null").end(); | |
1478 builder.startBlock(); | |
1479 builder.statement("searchNode = searchNode.getParent()"); | |
1480 builder.startIf().instanceOf("searchNode", nodePolymorphicClassName(node, node.getPolymorphicSpecializations().get(0))).end(); | |
1481 builder.startBlock().breakStatement().end(); | |
1482 builder.end(); | |
1483 builder.startStatement().startCall("searchNode", "replace"); | |
1484 builder.startGroup().startNew(nodeSpecializationClassName(current)).startGroup().cast(baseClassName(node)).string("searchNode").end().end().end(); | |
1485 builder.string("message"); | |
1486 builder.end().end().end(); | |
1487 } | |
1488 | |
1489 builder.end().startElseBlock(); | |
1490 } | |
1491 | |
1492 // polymorphic rewrite | |
1493 builder.tree(createRewritePolymorphic(builder, node)); | |
1494 | |
1495 if (rewriteableToGeneric) { | |
1496 builder.end(); | |
1497 } | |
1498 } | |
1499 | |
1500 if (current.getReturnType().getTypeSystemType().isVoid()) { | |
1501 builder.returnStatement(); | |
1502 } else { | |
1503 builder.startReturn().string("result").end(); | |
1504 } | |
1505 if (ifAllowed) { | |
1506 builder.end(); | |
1507 } | |
1508 | |
1509 return encloseThrowsWithFallThrough(current, builder.getRoot()); | |
1510 } | |
1511 | |
1512 private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { | |
1513 if (current.getExceptions().isEmpty()) { | |
1514 return tree; | |
1515 } | |
1516 CodeTreeBuilder builder = new CodeTreeBuilder(null); | |
1517 | |
1518 builder.startTryBlock(); | |
1519 builder.tree(tree); | |
1520 for (SpecializationThrowsData exception : current.getExceptions()) { | |
1521 builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); | |
1522 builder.string("// fall through").newLine(); | |
1523 } | |
1524 builder.end(); | |
1495 | 1525 |
1496 return builder.getRoot(); | 1526 return builder.getRoot(); |
1497 } | 1527 } |
1498 | 1528 |
1499 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) { | 1529 private CodeTree createRewriteGeneric(CodeTreeBuilder parent, SpecializationData current) { |
1500 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); | 1530 CodeTreeBuilder builder = parent.create(); |
1501 | 1531 builder.startStatement().startCall("super", "replace"); |
1502 int i = 0; | 1532 builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); |
1503 for (VariableElement param : method.getParameters()) { | 1533 builder.string("message"); |
1504 CodeVariableElement var = CodeVariableElement.clone(param); | 1534 builder.end().end(); |
1505 ActualParameter actualParameter = execType.getParameters().get(i); | 1535 return builder.getRoot(); |
1506 if (actualParameter.getSpecification().isSignature()) { | 1536 } |
1507 var.setName(valueNameEvaluated(actualParameter)); | 1537 |
1508 } else { | 1538 private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node) { |
1509 var.setName(valueName(actualParameter)); | 1539 CodeTreeBuilder builder = parent.create(); |
1510 } | 1540 builder.startStatement(); |
1511 method.getParameters().set(i, var); | 1541 builder.string(nodePolymorphicClassName(node, null)); |
1512 i++; | 1542 builder.string(" polymorphic = "); |
1513 } | 1543 builder.startNew(nodePolymorphicClassName(node, null)).string("this").end(); |
1514 | 1544 builder.end(); |
1515 method.getAnnotationMirrors().clear(); | 1545 for (NodeChildData child : node.getChildren()) { |
1516 method.getModifiers().remove(Modifier.ABSTRACT); | 1546 builder.startStatement().string("this.").string(child.getName()).string(" = null").end(); |
1517 return method; | 1547 } |
1518 } | 1548 builder.startStatement().startCall("super", "replace"); |
1519 | 1549 builder.string("polymorphic"); |
1520 private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) { | 1550 builder.string("message"); |
1521 if (execType.isAbstract()) { | 1551 builder.end().end(); |
1522 return true; | 1552 |
1523 } | 1553 builder.statement("polymorphic.setNext0(this)"); |
1524 if (Utils.isPrimitiveOrVoid(primaryType.getPrimitiveType()) && Utils.isPrimitiveOrVoid(execType.getType().getPrimitiveType())) { | 1554 builder.statement("setNext0(createSpezialization0(resultClass))"); |
1525 return true; | 1555 |
1526 } | 1556 builder.statement("polymorphic.optimizeTypes()"); |
1527 if (execType.getType().isGeneric()) { | 1557 return builder.getRoot(); |
1528 return true; | 1558 } |
1529 } | 1559 |
1530 return false; | 1560 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { |
1531 } | 1561 for (TemplateMethod listener : node.getSpecializationListeners()) { |
1532 | 1562 builder.startStatement(); |
1533 private List<ExecutableTypeData> findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) { | 1563 builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); |
1534 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | 1564 builder.end(); // statement |
1535 List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount); | 1565 } |
1536 | 1566 } |
1537 List<ExecutableTypeData> filteredTypes = new ArrayList<>(); | 1567 |
1538 for (ExecutableTypeData compareType : otherTypes) { | 1568 protected CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) { |
1539 if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) { | |
1540 continue; | |
1541 } | |
1542 filteredTypes.add(compareType); | |
1543 } | |
1544 | |
1545 // no direct matches found use generic where the type is Object | |
1546 if (filteredTypes.isEmpty()) { | |
1547 for (ExecutableTypeData compareType : otherTypes) { | |
1548 if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) { | |
1549 filteredTypes.add(compareType); | |
1550 } | |
1551 } | |
1552 } | |
1553 | |
1554 if (filteredTypes.isEmpty()) { | |
1555 for (ExecutableTypeData compareType : otherTypes) { | |
1556 if (compareType.getType().isGeneric()) { | |
1557 filteredTypes.add(compareType); | |
1558 } | |
1559 } | |
1560 } | |
1561 | |
1562 return filteredTypes; | |
1563 } | |
1564 | |
1565 private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) { | |
1566 TypeData type = executable.getType(); | 1569 TypeData type = executable.getType(); |
1567 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 1570 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1568 NodeData node = specialization.getNode(); | 1571 NodeData node = specialization.getNode(); |
1569 | 1572 |
1570 ExecutableTypeData castedType = node.findExecutableType(type, 0); | 1573 ExecutableTypeData castedType = node.findExecutableType(type, 0); |
1613 } | 1616 } |
1614 builder.end(); | 1617 builder.end(); |
1615 | 1618 |
1616 if (!returnVoid) { | 1619 if (!returnVoid) { |
1617 builder.startReturn(); | 1620 builder.startReturn(); |
1618 builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, CodeTreeBuilder.singleString("value"))); | 1621 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), executable, CodeTreeBuilder.singleString("value"))); |
1619 builder.end(); | 1622 builder.end(); |
1620 } | 1623 } |
1621 } else { | 1624 } else { |
1622 if (returnVoid) { | 1625 if (returnVoid) { |
1623 builder.statement(primaryExecuteCall); | 1626 builder.statement(primaryExecuteCall); |
1624 } else { | 1627 } else { |
1625 builder.startReturn(); | 1628 builder.startReturn(); |
1626 builder.tree(createExpectExecutableType(node, castExecutable.getReturnSignature(), executable, primaryExecuteCall)); | 1629 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), executable, primaryExecuteCall)); |
1627 builder.end(); | 1630 builder.end(); |
1628 } | 1631 } |
1629 } | 1632 } |
1630 | 1633 |
1631 return builder.getRoot(); | 1634 return builder.getRoot(); |
1632 } | 1635 } |
1633 | 1636 |
1634 private CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { | 1637 protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { |
1635 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); | 1638 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); |
1636 return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); | 1639 return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); |
1637 } | 1640 } |
1638 | 1641 |
1639 private CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { | 1642 protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { |
1640 if (targetType == null) { | 1643 if (targetType == null) { |
1641 return value; | 1644 return value; |
1642 } else if (!sourceType.needsCastTo(getContext(), targetType)) { | 1645 } else if (!sourceType.needsCastTo(getContext(), targetType)) { |
1643 return value; | 1646 return value; |
1644 } | 1647 } |
1655 builder.tree(value); | 1658 builder.tree(value); |
1656 builder.end().end(); | 1659 builder.end().end(); |
1657 return builder.getRoot(); | 1660 return builder.getRoot(); |
1658 } | 1661 } |
1659 | 1662 |
1660 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) { | 1663 protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters, |
1661 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1662 if (specialization.isUninitialized()) { | |
1663 builder.tree(createDeoptimize(builder)); | |
1664 } | |
1665 | |
1666 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); | |
1667 | |
1668 CodeTree executeNode; | |
1669 executeNode = createExecute(builder, executable, specialization); | |
1670 | |
1671 SpecializationData next = specialization.findNextSpecialization(); | |
1672 CodeTree returnSpecialized = null; | |
1673 if (next != null) { | |
1674 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); | |
1675 returnBuilder.tree(createDeoptimize(builder)); | |
1676 returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null, "One of guards " + specialization.getGuards() + " failed")); | |
1677 returnSpecialized = returnBuilder.getRoot(); | |
1678 } | |
1679 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false)); | |
1680 | |
1681 return builder.getRoot(); | |
1682 } | |
1683 | |
1684 private CodeTree createDeoptimize(CodeTreeBuilder parent) { | |
1685 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1686 builder.startStatement(); | |
1687 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); | |
1688 builder.end(); | |
1689 return builder.getRoot(); | |
1690 } | |
1691 | |
1692 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { | |
1693 NodeData node = specialization.getNode(); | |
1694 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1695 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { | |
1696 builder.startTryBlock(); | |
1697 } | |
1698 | |
1699 for (String assumption : specialization.getAssumptions()) { | |
1700 builder.startStatement(); | |
1701 builder.string("this.").string(assumption).string(".check()"); | |
1702 builder.end(); | |
1703 } | |
1704 | |
1705 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); | |
1706 if (specialization.isUninitialized()) { | |
1707 returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); | |
1708 returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); | |
1709 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
1710 returnBuilder.doubleQuote("Uninitialized"); | |
1711 returnBuilder.end(); | |
1712 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { | |
1713 emitEncounteredSynthetic(builder, specialization); | |
1714 } else if (specialization.isGeneric()) { | |
1715 returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); | |
1716 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
1717 returnBuilder.end(); | |
1718 } else { | |
1719 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); | |
1720 } | |
1721 | |
1722 if (!returnBuilder.isEmpty()) { | |
1723 builder.startReturn(); | |
1724 | |
1725 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); | |
1726 TypeData sourceType = specialization.getReturnType().getTypeSystemType(); | |
1727 | |
1728 if (targetType == null || sourceType == null) { | |
1729 builder.tree(returnBuilder.getRoot()); | |
1730 } else if (sourceType.needsCastTo(getContext(), targetType)) { | |
1731 builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot())); | |
1732 } else { | |
1733 builder.tree(returnBuilder.getRoot()); | |
1734 } | |
1735 builder.end(); | |
1736 } | |
1737 | |
1738 if (!specialization.getExceptions().isEmpty()) { | |
1739 for (SpecializationThrowsData exception : specialization.getExceptions()) { | |
1740 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); | |
1741 builder.tree(createDeoptimize(builder)); | |
1742 builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null, "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); | |
1743 } | |
1744 builder.end(); | |
1745 } | |
1746 if (!specialization.getAssumptions().isEmpty()) { | |
1747 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); | |
1748 builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null, "Assumption failed")); | |
1749 builder.end(); | |
1750 } | |
1751 | |
1752 return builder.getRoot(); | |
1753 } | |
1754 | |
1755 private CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters, | |
1756 ActualParameter unexpectedParameter, boolean cast) { | 1664 ActualParameter unexpectedParameter, boolean cast) { |
1757 NodeData sourceNode = specialization.getNode(); | 1665 NodeData sourceNode = specialization.getNode(); |
1758 | 1666 |
1759 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 1667 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1760 | 1668 |
1815 if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) { | 1723 if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) { |
1816 unexpected = true; | 1724 unexpected = true; |
1817 cast = true; | 1725 cast = true; |
1818 } | 1726 } |
1819 | 1727 |
1728 if (specialization.isGeneric() && unexpected) { | |
1729 throw new AssertionError("Generic has unexpected parameters. " + specialization.toString()); | |
1730 } | |
1731 | |
1820 builder.startStatement(); | 1732 builder.startStatement(); |
1821 | 1733 |
1822 if (!shortCircuit) { | 1734 if (!shortCircuit) { |
1823 builder.type(param.getType()).string(" ").string(targetVariableName); | 1735 builder.type(param.getType()).string(" ").string(targetVariableName); |
1824 } | 1736 } |
1848 ActualParameter genericParameter = generic.findParameter(param.getLocalName()); | 1760 ActualParameter genericParameter = generic.findParameter(param.getLocalName()); |
1849 | 1761 |
1850 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); | 1762 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); |
1851 builder.tree(createDeoptimize(builder)); | 1763 builder.tree(createDeoptimize(builder)); |
1852 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); | 1764 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); |
1853 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param, | 1765 if (specialization.isPolymorphic()) { |
1854 "Expected " + param.getLocalName() + " instanceof " + Utils.getSimpleName(param.getType()))); | 1766 builder.tree(createReturnOptimizeTypes(builder, specialization, param)); |
1767 } else { | |
1768 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param, "Expected " + param.getLocalName() + " instanceof " + | |
1769 Utils.getSimpleName(param.getType()))); | |
1770 } | |
1855 builder.end(); // catch block | 1771 builder.end(); // catch block |
1856 } | 1772 } |
1857 | 1773 |
1774 return builder.getRoot(); | |
1775 } | |
1776 | |
1777 private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, SpecializationData specialization, ActualParameter param) { | |
1778 NodeData node = specialization.getNode(); | |
1779 assert !node.getPolymorphicSpecializations().isEmpty(); | |
1780 SpecializationData generic = node.getPolymorphicSpecializations().get(0); | |
1781 | |
1782 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1783 builder.startReturn(); | |
1784 | |
1785 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1786 execute.startCall("next0", "executeCached0"); | |
1787 addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true); | |
1788 execute.end(); | |
1789 | |
1790 TypeData sourceType = generic.getReturnType().getTypeSystemType(); | |
1791 TypeData targetType = specialization.getReturnType().getTypeSystemType(); | |
1792 | |
1793 builder.tree(createCastType(node, sourceType, targetType, true, execute.getRoot())); | |
1794 | |
1795 builder.end(); | |
1858 return builder.getRoot(); | 1796 return builder.getRoot(); |
1859 } | 1797 } |
1860 | 1798 |
1861 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { | 1799 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { |
1862 TypeData type = sourceParameter.getTypeSystemType(); | 1800 TypeData type = sourceParameter.getTypeSystemType(); |
1863 ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); | 1801 ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); |
1864 | 1802 |
1865 /* | |
1866 * FIXME Temporary deactivated due to partial evaluation failure else if | |
1867 * (accessElement.getKind() == ElementKind.METHOD) { | |
1868 * builder.startCall(accessElement.getSimpleName().toString()).end(); } | |
1869 */ | |
1870 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 1803 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1871 if (targetField != null) { | 1804 if (targetField != null) { |
1872 Element accessElement = targetField.getAccessElement(); | 1805 Element accessElement = targetField.getAccessElement(); |
1873 if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { | 1806 if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { |
1874 builder.string("this.").string(targetField.getName()); | 1807 builder.string("this.").string(targetField.getName()); |
1975 builder.end(); // statement | 1908 builder.end(); // statement |
1976 | 1909 |
1977 return builder.getRoot(); | 1910 return builder.getRoot(); |
1978 } | 1911 } |
1979 | 1912 |
1980 private CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam, String reason) { | 1913 protected CodeTree createDeoptimize(CodeTreeBuilder parent) { |
1981 | 1914 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1982 SpecializationData generic = nextSpecialization.getNode().getGenericSpecialization(); | 1915 builder.startStatement(); |
1916 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); | |
1917 builder.end(); | |
1918 return builder.getRoot(); | |
1919 } | |
1920 | |
1921 protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam, String reason) { | |
1922 SpecializationData generic = getModel().getNode().getGenericSpecialization(); | |
1983 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); | 1923 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); |
1984 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); | 1924 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); |
1985 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); | 1925 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); |
1986 addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); | 1926 addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); |
1987 specializeCall.doubleQuote(reason); | 1927 specializeCall.doubleQuote(reason); |
1988 specializeCall.end().end(); | 1928 specializeCall.end().end(); |
1989 | 1929 |
1990 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | 1930 CodeTreeBuilder builder = new CodeTreeBuilder(parent); |
1991 | 1931 |
1992 builder.startReturn(); | 1932 builder.startReturn(); |
1993 builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnSignature(), executable, specializeCall.getRoot())); | 1933 builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot())); |
1994 builder.end(); | 1934 builder.end(); |
1995 | 1935 |
1996 return builder.getRoot(); | 1936 return builder.getRoot(); |
1997 } | 1937 } |
1938 } | |
1939 | |
1940 private class PolymorphicNodeFactory extends SpecializedNodeFactory { | |
1941 | |
1942 private final boolean generic; | |
1943 | |
1944 public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen, boolean generic) { | |
1945 super(context, nodeGen); | |
1946 this.generic = generic; | |
1947 } | |
1948 | |
1949 @Override | |
1950 public CodeTypeElement create(SpecializationData specialization) { | |
1951 NodeData node = specialization.getNode(); | |
1952 TypeMirror baseType = node.getNodeType(); | |
1953 if (nodeGen != null) { | |
1954 baseType = nodeGen.asType(); | |
1955 } | |
1956 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC), nodePolymorphicClassName(node, specialization), baseType, false); | |
1957 | |
1958 if (!generic) { | |
1959 clazz.getModifiers().add(Modifier.FINAL); | |
1960 } | |
1961 | |
1962 clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC)); | |
1963 | |
1964 return clazz; | |
1965 } | |
1966 | |
1967 @Override | |
1968 protected void createChildren(SpecializationData specialization) { | |
1969 // super.createChildren(specialization); | |
1970 CodeTypeElement clazz = getElement(); | |
1971 | |
1972 createConstructors(clazz); | |
1973 createExecuteMethods(specialization); | |
1974 | |
1975 if (generic) { | |
1976 getElement().add(createOptimizeTypes()); | |
1977 createCachedExecuteMethods(specialization); | |
1978 } | |
1979 } | |
1980 | |
1981 private CodeExecutableElement createOptimizeTypes() { | |
1982 NodeData node = getModel().getNode(); | |
1983 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), getContext().getType(void.class), "optimizeTypes"); | |
1984 CodeTreeBuilder builder = method.createBuilder(); | |
1985 builder.startStatement().string(baseClassName(node)).string(" node = this.next0").end(); | |
1986 TypeMirror classType = getContext().getType(Class.class); | |
1987 | |
1988 SpecializationData genericSpecialization = node.getGenericSpecialization(); | |
1989 | |
1990 CodeTreeBuilder whileBodyBuilder = builder.create(); | |
1991 for (ActualParameter parameter : node.getGenericSpecialization().getReturnTypeAndParameters()) { | |
1992 if (!parameter.getSpecification().isSignature()) { | |
1993 continue; | |
1994 } | |
1995 | |
1996 ActualParameter genericParameter = genericSpecialization.findParameter(parameter.getLocalName()); | |
1997 | |
1998 String name = parameter.getLocalName() + "Type"; | |
1999 | |
2000 builder.declaration(classType, name, builder.create().startCall("node", typeGetterName(parameter)).end().getRoot()); | |
2001 | |
2002 whileBodyBuilder.startIf().string(name).string(" != ").startCall("node", typeGetterName(parameter)).end().end(); | |
2003 whileBodyBuilder.startBlock(); | |
2004 whileBodyBuilder.startStatement().string(name).string(" = ").typeLiteral(genericParameter.getType()).end(); | |
2005 whileBodyBuilder.end(); | |
2006 } | |
2007 | |
2008 builder.startWhile().string("node != null && !(").instanceOf("node", nodeSpecializationClassName(node.getUninitializedSpecialization())).string(")").end(); | |
2009 builder.startBlock(); | |
2010 builder.tree(whileBodyBuilder.getRoot()); | |
2011 builder.statement("node = node.next0"); | |
2012 builder.end(); | |
2013 | |
2014 boolean elseIf = false; | |
2015 for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { | |
2016 elseIf = builder.startIf(elseIf); | |
2017 String and = ""; | |
2018 StringBuilder reason = new StringBuilder("Optimized polymorphic types for ("); | |
2019 for (ActualParameter parameter : polymorph.getReturnTypeAndParameters()) { | |
2020 if (!parameter.getSpecification().isSignature()) { | |
2021 continue; | |
2022 } | |
2023 String name = parameter.getLocalName() + "Type"; | |
2024 builder.string(and).string(name).string(" == ").typeLiteral(parameter.getType()); | |
2025 | |
2026 if (!and.isEmpty()) { | |
2027 reason.append(", "); | |
2028 } | |
2029 reason.append(Utils.getSimpleName(parameter.getType())); | |
2030 and = " && "; | |
2031 } | |
2032 reason.append(")"); | |
2033 builder.end(); | |
2034 builder.startBlock(); | |
2035 | |
2036 String className = nodePolymorphicClassName(node, polymorph); | |
2037 builder.startIf().string("getClass() != ").string(className).string(".class").end(); | |
2038 builder.startBlock(); | |
2039 builder.startStatement().startCall("super", "replace"); | |
2040 builder.startNew(className).string("this").end(); | |
2041 builder.doubleQuote(reason.toString()); | |
2042 builder.end().end(); // call | |
2043 builder.end(); // block | |
2044 builder.end(); | |
2045 } | |
2046 return method; | |
2047 } | |
2048 } | |
2049 | |
2050 private class SpecializedNodeFactory extends NodeBaseFactory { | |
2051 | |
2052 protected final CodeTypeElement nodeGen; | |
2053 | |
2054 public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) { | |
2055 super(context); | |
2056 this.nodeGen = nodeGen; | |
2057 } | |
2058 | |
2059 @Override | |
2060 public CodeTypeElement create(SpecializationData specialization) { | |
2061 NodeData node = specialization.getNode(); | |
2062 TypeMirror baseType = node.getNodeType(); | |
2063 if (nodeGen != null) { | |
2064 baseType = nodeGen.asType(); | |
2065 } | |
2066 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); | |
2067 | |
2068 Kind kind; | |
2069 if (specialization.isGeneric()) { | |
2070 kind = Kind.GENERIC; | |
2071 } else if (specialization.isUninitialized()) { | |
2072 kind = Kind.UNINITIALIZED; | |
2073 } else { | |
2074 kind = Kind.SPECIALIZED; | |
2075 } | |
2076 clazz.getAnnotationMirrors().add(createNodeInfo(node, kind)); | |
2077 | |
2078 return clazz; | |
2079 } | |
2080 | |
2081 protected CodeAnnotationMirror createNodeInfo(NodeData node, Kind kind) { | |
2082 String shortName = node.getShortName(); | |
2083 CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); | |
2084 if (shortName != null) { | |
2085 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); | |
2086 } | |
2087 | |
2088 DeclaredType nodeinfoKind = getContext().getTruffleTypes().getNodeInfoKind(); | |
2089 VariableElement varKind = Utils.findVariableElement(nodeinfoKind, kind.name()); | |
2090 | |
2091 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("kind"), new CodeAnnotationValue(varKind)); | |
2092 return nodeInfoMirror; | |
2093 } | |
2094 | |
2095 @Override | |
2096 protected void createChildren(SpecializationData specialization) { | |
2097 CodeTypeElement clazz = getElement(); | |
2098 createConstructors(clazz); | |
2099 | |
2100 NodeData node = specialization.getNode(); | |
2101 | |
2102 if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic() && node.needsRewrites(getContext()) && node.getPolymorphicDepth() > 1) { | |
2103 | |
2104 createTypeGetters(clazz, specialization); | |
2105 } | |
2106 | |
2107 createExecuteMethods(specialization); | |
2108 createCachedExecuteMethods(specialization); | |
2109 } | |
2110 | |
2111 protected void createConstructors(CodeTypeElement clazz) { | |
2112 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); | |
2113 for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { | |
2114 if (getModel().getNode().getUninitializedSpecialization() != null && !getModel().isUninitialized() && constructor.getParameters().size() != 1 || | |
2115 constructor.getParameters().get(0).getSimpleName().toString().equals(baseClassName(getModel().getNode()))) { | |
2116 continue; | |
2117 } | |
2118 | |
2119 CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); | |
2120 if (superConstructor != null) { | |
2121 if (getModel().isGeneric() && getModel().getNode().getPolymorphicDepth() > 1) { | |
2122 CodeTree body = superConstructor.getBodyTree(); | |
2123 CodeTreeBuilder builder = superConstructor.createBuilder(); | |
2124 builder.tree(body); | |
2125 builder.statement("this.next0 = null"); | |
2126 } | |
2127 | |
2128 clazz.add(superConstructor); | |
2129 } | |
2130 } | |
2131 } | |
2132 | |
2133 protected void createExecuteMethods(SpecializationData specialization) { | |
2134 NodeData node = specialization.getNode(); | |
2135 CodeTypeElement clazz = getElement(); | |
2136 | |
2137 for (ExecutableTypeData execType : node.getExecutableTypes()) { | |
2138 if (execType.isFinal()) { | |
2139 continue; | |
2140 } | |
2141 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true); | |
2142 clazz.add(executeMethod); | |
2143 CodeTreeBuilder builder = executeMethod.createBuilder(); | |
2144 CodeTree result = createExecuteBody(builder, specialization, execType); | |
2145 if (result != null) { | |
2146 builder.tree(result); | |
2147 } else { | |
2148 clazz.remove(executeMethod); | |
2149 } | |
2150 } | |
2151 } | |
2152 | |
2153 protected void createCachedExecuteMethods(SpecializationData specialization) { | |
2154 NodeData node = specialization.getNode(); | |
2155 CodeTypeElement clazz = getElement(); | |
2156 int index = 0; | |
2157 for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) { | |
2158 boolean matchFound = false; | |
2159 if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic()) { | |
2160 matchFound = polymorphic.getSignature().hasAnyParameterMatch(specialization.getSignature()); | |
2161 } | |
2162 | |
2163 if (matchFound || index == 0) { | |
2164 ExecutableElement executeCached = nodeGen.getMethod("executeCached" + index); | |
2165 ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType()); | |
2166 | |
2167 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); | |
2168 CodeTreeBuilder builder = executeMethod.createBuilder(); | |
2169 | |
2170 if (specialization.isGeneric() || specialization.isPolymorphic()) { | |
2171 builder.startThrow().startNew(getContext().getType(AssertionError.class)); | |
2172 builder.doubleQuote("Should not be reached."); | |
2173 builder.end().end(); | |
2174 } else if (specialization.isUninitialized()) { | |
2175 builder.tree(createAppendPolymorphic(builder, specialization)); | |
2176 } else { | |
2177 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); | |
2178 elseBuilder.startReturn().startCall("this.next0", "executeCached" + index); | |
2179 addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true); | |
2180 elseBuilder.end().end(); | |
2181 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
2182 execute.tree(createGenericInvoke(builder, polymorphic, specialization)); | |
2183 boolean forceElse = !specialization.getExceptions().isEmpty(); | |
2184 builder.tree(createGuardAndCast(builder, null, polymorphic, specialization, true, execute.getRoot(), elseBuilder.getRoot(), true, forceElse)); | |
2185 } | |
2186 clazz.add(executeMethod); | |
2187 } | |
2188 index++; | |
2189 } | |
2190 } | |
2191 | |
2192 private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) { | |
2193 NodeData node = specialization.getNode(); | |
2194 String genericClassName = nodePolymorphicClassName(node, null); | |
2195 | |
2196 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2197 builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); | |
2198 | |
2199 builder.declaration(getContext().getTruffleTypes().getNode(), "searchNode", "super.getParent()"); | |
2200 builder.declaration(getContext().getType(int.class), "depth", "0"); | |
2201 builder.startWhile().string("searchNode != null").end(); | |
2202 builder.startBlock(); | |
2203 builder.statement("depth++"); | |
2204 builder.statement("searchNode = searchNode.getParent()"); | |
2205 | |
2206 builder.startIf().instanceOf("searchNode", genericClassName).end(); | |
2207 builder.startBlock().breakStatement().end(); | |
2208 builder.end(); // if | |
2209 builder.end(); // while | |
2210 | |
2211 builder.startAssert().instanceOf("searchNode", genericClassName).end(); | |
2212 | |
2213 builder.startStatement(); | |
2214 builder.string(genericClassName).string(" ").string("polymorphic = ").string("(").string(genericClassName).string(") searchNode"); | |
2215 builder.end(); | |
2216 | |
2217 builder.startIf().string("depth >= ").string(String.valueOf(node.getPolymorphicDepth())).end(); | |
2218 builder.startBlock(); | |
2219 builder.startStatement(); | |
2220 builder.startCall("searchNode", "replace"); | |
2221 builder.startNew(nodeSpecializationClassName(node.getGenericSpecialization())).string("this").end(); | |
2222 builder.doubleQuote("Polymorphic limit reached (" + node.getPolymorphicDepth() + ")"); | |
2223 builder.end(); | |
2224 builder.end(); | |
2225 | |
2226 builder.startReturn().startCall("super", EXECUTE_GENERIC_NAME); | |
2227 addInternalValueParameterNames(builder, specialization, node.getGenericSpecialization(), null, true, true); | |
2228 builder.end().end(); | |
2229 | |
2230 builder.end().startElseBlock(); | |
2231 builder.startStatement().startCall("super", "setNext0"); | |
2232 builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); | |
2233 builder.end().end(); | |
2234 | |
2235 CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder); | |
2236 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); | |
2237 specializeCall.string(nodeSpecializationClassName(node.getUninitializedSpecialization()) + ".class"); | |
2238 addInternalValueParameterNames(specializeCall, specialization, node.getGenericSpecialization(), null, true, true); | |
2239 specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end(); | |
2240 specializeCall.end().end(); | |
2241 | |
2242 builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot()); | |
2243 | |
2244 builder.statement("polymorphic.optimizeTypes()"); | |
2245 | |
2246 if (Utils.isVoid(builder.findMethod().getReturnType())) { | |
2247 builder.returnStatement(); | |
2248 } else { | |
2249 builder.startReturn().string("result").end(); | |
2250 } | |
2251 | |
2252 builder.end(); | |
2253 | |
2254 return builder.getRoot(); | |
2255 } | |
2256 | |
2257 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { | |
2258 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | |
2259 | |
2260 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2261 | |
2262 List<ExecutableTypeData> primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount()); | |
2263 | |
2264 if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) { | |
2265 builder.tree(createFunctionalExecute(builder, specialization, execType)); | |
2266 } else if (needsCastingExecuteMethod(execType, primaryType)) { | |
2267 assert !primaryExecutes.isEmpty(); | |
2268 builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0))); | |
2269 } else { | |
2270 return null; | |
2271 } | |
2272 | |
2273 return builder.getRoot(); | |
2274 } | |
2275 | |
2276 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { | |
2277 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); | |
2278 | |
2279 int i = 0; | |
2280 for (VariableElement param : method.getParameters()) { | |
2281 CodeVariableElement var = CodeVariableElement.clone(param); | |
2282 ActualParameter actualParameter = execType.getParameters().get(i); | |
2283 if (evaluated && actualParameter.getSpecification().isSignature()) { | |
2284 var.setName(valueNameEvaluated(actualParameter)); | |
2285 } else { | |
2286 var.setName(valueName(actualParameter)); | |
2287 } | |
2288 method.getParameters().set(i, var); | |
2289 i++; | |
2290 } | |
2291 | |
2292 method.getAnnotationMirrors().clear(); | |
2293 method.getModifiers().remove(Modifier.ABSTRACT); | |
2294 return method; | |
2295 } | |
2296 | |
2297 private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) { | |
2298 if (execType.isAbstract()) { | |
2299 return true; | |
2300 } | |
2301 if (Utils.isPrimitiveOrVoid(primaryType.getPrimitiveType()) && Utils.isPrimitiveOrVoid(execType.getType().getPrimitiveType())) { | |
2302 return true; | |
2303 } | |
2304 if (execType.getType().isGeneric()) { | |
2305 return true; | |
2306 } | |
2307 return false; | |
2308 } | |
2309 | |
2310 private List<ExecutableTypeData> findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) { | |
2311 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | |
2312 List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount); | |
2313 | |
2314 List<ExecutableTypeData> filteredTypes = new ArrayList<>(); | |
2315 for (ExecutableTypeData compareType : otherTypes) { | |
2316 if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) { | |
2317 continue; | |
2318 } | |
2319 filteredTypes.add(compareType); | |
2320 } | |
2321 | |
2322 // no direct matches found use generic where the type is Object | |
2323 if (filteredTypes.isEmpty()) { | |
2324 for (ExecutableTypeData compareType : otherTypes) { | |
2325 if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) { | |
2326 filteredTypes.add(compareType); | |
2327 } | |
2328 } | |
2329 } | |
2330 | |
2331 if (filteredTypes.isEmpty()) { | |
2332 for (ExecutableTypeData compareType : otherTypes) { | |
2333 if (compareType.getType().isGeneric()) { | |
2334 filteredTypes.add(compareType); | |
2335 } | |
2336 } | |
2337 } | |
2338 | |
2339 return filteredTypes; | |
2340 } | |
2341 | |
2342 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) { | |
2343 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2344 if (specialization.isUninitialized()) { | |
2345 builder.tree(createDeoptimize(builder)); | |
2346 } | |
2347 | |
2348 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); | |
2349 | |
2350 CodeTree executeNode = createExecute(builder, executable, specialization); | |
2351 | |
2352 SpecializationData next = specialization.findNextSpecialization(); | |
2353 CodeTree returnSpecialized = null; | |
2354 if (next != null) { | |
2355 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); | |
2356 returnBuilder.tree(createDeoptimize(builder)); | |
2357 returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null, "One of guards " + specialization.getGuards() + " failed")); | |
2358 returnSpecialized = returnBuilder.getRoot(); | |
2359 } | |
2360 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false, false)); | |
2361 | |
2362 return builder.getRoot(); | |
2363 } | |
2364 | |
2365 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { | |
2366 NodeData node = specialization.getNode(); | |
2367 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2368 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { | |
2369 builder.startTryBlock(); | |
2370 } | |
2371 | |
2372 for (String assumption : specialization.getAssumptions()) { | |
2373 builder.startStatement(); | |
2374 builder.string("this.").string(assumption).string(".check()"); | |
2375 builder.end(); | |
2376 } | |
2377 | |
2378 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); | |
2379 if (specialization.isPolymorphic()) { | |
2380 int index = 0; | |
2381 if (executable.hasUnexpectedValue(getContext())) { | |
2382 index = specialization.getNode().getPolymorphicSpecializations().indexOf(specialization); | |
2383 } | |
2384 returnBuilder.startCall("next0", "executeCached" + index); | |
2385 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2386 returnBuilder.end(); | |
2387 } else if (specialization.isUninitialized()) { | |
2388 returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); | |
2389 returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); | |
2390 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2391 returnBuilder.doubleQuote("Uninitialized monomorphic"); | |
2392 returnBuilder.end(); | |
2393 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { | |
2394 emitEncounteredSynthetic(builder, specialization); | |
2395 } else if (specialization.isGeneric()) { | |
2396 returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); | |
2397 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2398 returnBuilder.end(); | |
2399 } else { | |
2400 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); | |
2401 } | |
2402 | |
2403 if (!returnBuilder.isEmpty()) { | |
2404 builder.startReturn(); | |
2405 | |
2406 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); | |
2407 TypeData sourceType = specialization.getReturnType().getTypeSystemType(); | |
2408 | |
2409 if (targetType == null || sourceType == null) { | |
2410 builder.tree(returnBuilder.getRoot()); | |
2411 } else if (sourceType.needsCastTo(getContext(), targetType)) { | |
2412 builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot())); | |
2413 } else { | |
2414 builder.tree(returnBuilder.getRoot()); | |
2415 } | |
2416 builder.end(); | |
2417 } | |
2418 | |
2419 if (!specialization.getExceptions().isEmpty()) { | |
2420 for (SpecializationThrowsData exception : specialization.getExceptions()) { | |
2421 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); | |
2422 builder.tree(createDeoptimize(builder)); | |
2423 builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null, "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); | |
2424 } | |
2425 builder.end(); | |
2426 } | |
2427 if (!specialization.getAssumptions().isEmpty()) { | |
2428 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); | |
2429 builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null, "Assumption failed")); | |
2430 builder.end(); | |
2431 } | |
2432 | |
2433 return builder.getRoot(); | |
2434 } | |
1998 | 2435 |
1999 } | 2436 } |
2000 | 2437 |
2001 } | 2438 } |