diff graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.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 3cc5fb59916e
children
line wrap: on
line diff
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Jul 01 20:31:30 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Mon Jul 01 20:32:20 2013 +0200
@@ -36,6 +36,7 @@
 import com.oracle.truffle.codegen.processor.node.NodeChildData.Cardinality;
 import com.oracle.truffle.codegen.processor.node.NodeChildData.ExecutionKind;
 import com.oracle.truffle.codegen.processor.template.*;
+import com.oracle.truffle.codegen.processor.template.TemplateMethod.Signature;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
 public class NodeParser extends TemplateParser<NodeData> {
@@ -152,13 +153,7 @@
         }
 
         if (nodeType == null) {
-            if (nodeClass == null) {
-                // no node
-                return null;
-            } else {
-                // FIXME nodeType not specified error
-                return null;
-            }
+            return null;
         }
 
         Elements elementUtil = context.getEnvironment().getElementUtils();
@@ -206,16 +201,71 @@
         for (NodeData splittedNode : nodes) {
             finalizeSpecializations(elements, splittedNode);
             verifyNode(splittedNode, elements);
+            splittedNode.setPolymorphicSpecializations(createPolymorphicSpecializations(splittedNode));
+            assignShortCircuitsToSpecializations(splittedNode);
         }
 
         if (node.isNodeContainer()) {
             node.setDeclaredNodes(nodes);
             node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
             node.setSpecializations(new ArrayList<SpecializationData>());
-            return node;
-        } else {
-            return node;
+        }
+        return node;
+    }
+
+    private List<SpecializationData> createPolymorphicSpecializations(NodeData node) {
+        if (!node.needsRewrites(context) || node.getPolymorphicDepth() <= 1) {
+            return Collections.emptyList();
+        }
+
+        Signature genericSignature = node.getGenericSpecialization().getSignature();
+        Set<Signature> signatures = new HashSet<>();
+
+        for (SpecializationData specialization1 : node.getSpecializations()) {
+            Signature signature = specialization1.getSignature();
+
+            for (SpecializationData specialization2 : node.getSpecializations()) {
+                if (specialization1 == specialization2) {
+                    continue;
+                }
+                signatures.add(signature.combine(genericSignature, specialization2.getSignature()));
+            }
         }
+
+        while (true) {
+            List<Signature> newSignatures = new ArrayList<>();
+            for (Signature signature1 : signatures) {
+                for (Signature signature2 : signatures) {
+                    if (signature1 == signature2) {
+                        continue;
+                    }
+                    newSignatures.add(signature1.combine(genericSignature, signature2));
+                }
+            }
+            if (!signatures.addAll(newSignatures)) {
+                break;
+            }
+        }
+
+        List<Signature> sortedSignatures = new ArrayList<>(signatures);
+        Collections.sort(sortedSignatures);
+
+        List<SpecializationData> specializations = new ArrayList<>();
+        SpecializationData generic = node.getGenericSpecialization();
+        for (Signature signature : sortedSignatures) {
+            SpecializationData specialization = new SpecializationData(generic, false, false, true);
+            specialization.forceFrame(context.getTruffleTypes().getFrame());
+            specialization.setNode(node);
+            specialization.updateSignature(signature);
+
+            if (specialization.isGenericSpecialization(context)) {
+                specializations.add(0, specialization);
+            } else {
+                specializations.add(specialization);
+            }
+        }
+
+        return specializations;
     }
 
     private NodeData parseNodeData(TypeElement templateType, TypeMirror nodeType, List<? extends Element> elements, List<TypeElement> lookupTypes) {
@@ -234,8 +284,17 @@
             return nodeData;
         }
 
+        AnnotationMirror polymorphicMirror = findFirstAnnotation(lookupTypes, PolymorphicLimit.class);
+        if (polymorphicMirror != null) {
+            AnnotationValue limitValue = Utils.getAnnotationValue(polymorphicMirror, "value");
+            int polymorphicLimit = Utils.getAnnotationValue(Integer.class, polymorphicMirror, "value");
+            if (polymorphicLimit < 1) {
+                nodeData.addError(limitValue, "Invalid polymorphic limit %s.", polymorphicLimit);
+            }
+            nodeData.setPolymorphicDepth(polymorphicLimit);
+        }
+
         List<String> assumptionsList = new ArrayList<>();
-
         for (int i = lookupTypes.size() - 1; i >= 0; i--) {
             TypeElement type = lookupTypes.get(i);
             AnnotationMirror assumptions = Utils.findAnnotationMirror(context.getEnvironment(), type, NodeAssumptions.class);
@@ -543,34 +602,32 @@
                 }
             }
             TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters);
-            genericSpecialization = new SpecializationData(genericMethod, true, false);
+            genericSpecialization = new SpecializationData(genericMethod, true, false, false);
 
             specializations.add(genericSpecialization);
         }
 
         if (genericSpecialization != null) {
-            if (genericSpecialization.isUseSpecializationsForGeneric()) {
-                for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) {
-                    if (Utils.isObject(parameter.getType())) {
-                        continue;
+            for (ActualParameter parameter : genericSpecialization.getReturnTypeAndParameters()) {
+                if (Utils.isObject(parameter.getType())) {
+                    continue;
+                }
+                Set<String> types = new HashSet<>();
+                for (SpecializationData specialization : specializations) {
+                    ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
+                    if (actualParameter != null) {
+                        types.add(Utils.getQualifiedName(actualParameter.getType()));
                     }
-                    Set<String> types = new HashSet<>();
-                    for (SpecializationData specialization : specializations) {
-                        ActualParameter actualParameter = specialization.findParameter(parameter.getLocalName());
-                        if (actualParameter != null) {
-                            types.add(Utils.getQualifiedName(actualParameter.getType()));
-                        }
-                    }
-                    if (types.size() > 1) {
-                        genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
-                    }
+                }
+                if (types.size() > 1) {
+                    genericSpecialization.replaceParameter(parameter.getLocalName(), new ActualParameter(parameter, node.getTypeSystem().getGenericTypeData()));
                 }
             }
             TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), null, null, genericSpecialization.getReturnType(),
                             genericSpecialization.getParameters());
             // should not use messages from generic specialization
             uninializedMethod.getMessages().clear();
-            specializations.add(new SpecializationData(uninializedMethod, false, true));
+            specializations.add(new SpecializationData(uninializedMethod, false, true, false));
         }
 
         Collections.sort(specializations);
@@ -595,6 +652,35 @@
                 needsId.get(i).setId(ids.get(i));
             }
         }
+
+        // calculate reachability
+        int specializationCount = 0;
+        boolean reachable = true;
+        for (SpecializationData specialization : specializations) {
+            if (specialization.isUninitialized()) {
+                specialization.setReachable(true);
+                continue;
+            }
+            if (!reachable && specialization.getMethod() != null) {
+                specialization.addError("%s is not reachable.", specialization.isGeneric() ? "Generic" : "Specialization");
+            }
+            specialization.setReachable(reachable);
+            if (!specialization.hasRewrite(context)) {
+                reachable = false;
+            }
+            if (!specialization.isGeneric()) {
+                specializationCount++;
+            }
+        }
+
+        if (node.getPolymorphicDepth() < 0) {
+            node.setPolymorphicDepth(specializationCount - 1);
+        }
+
+        // reduce polymorphicness if generic is not reachable
+        if (node.getGenericSpecialization() != null && !node.getGenericSpecialization().isReachable()) {
+            node.setPolymorphicDepth(1);
+        }
     }
 
     private void assignShortCircuitsToSpecializations(NodeData node) {
@@ -653,7 +739,11 @@
         }
 
         NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT);
-        for (SpecializationData specialization : node.getSpecializations()) {
+        List<SpecializationData> specializations = new ArrayList<>();
+        specializations.addAll(node.getSpecializations());
+        specializations.addAll(node.getPolymorphicSpecializations());
+
+        for (SpecializationData specialization : specializations) {
             List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length);
 
             for (int i = 0; i < fields.length; i++) {
@@ -821,8 +911,6 @@
 
         verifyMissingAbstractMethods(nodeData, elements);
 
-        assignShortCircuitsToSpecializations(nodeData);
-
         verifyConstructors(nodeData);
 
         verifyNamingConvention(nodeData.getShortCircuits(), "needs");