changeset 8251:cb70ed101b5f

Added automatic generation of generic specialization which throws unsupported operation if reached.
author Christian Humer <christian.humer@gmail.com>
date Wed, 13 Mar 2013 11:32:43 +0100
parents edc414f52e2b
children 0905d796944a
files graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java
diffstat 9 files changed, 125 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java	Wed Mar 13 11:32:43 2013 +0100
@@ -28,6 +28,7 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode;
 import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode;
+import com.oracle.truffle.api.nodes.*;
 
 public class RuntimeStringTest {
 
@@ -86,6 +87,7 @@
         Object execute() {
             return arguments[index];
         }
+
     }
 
     abstract static class BuiltinNode extends ValueNode {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Wed Mar 13 11:32:43 2013 +0100
@@ -748,7 +748,7 @@
             return true;
         }
 
-        // search for any supertypes
+        // search for any super types
         TypeElement exceptionTypeElement = fromTypeMirror(exceptionType);
         List<TypeElement> superTypes = getSuperTypes(exceptionTypeElement);
         for (TypeElement typeElement : superTypes) {
@@ -777,7 +777,7 @@
         Set<String> typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type)));
         String typeName = getQualifiedName(type);
         if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) {
-            throw new IllegalArgumentException("Given does not extend Throwable.");
+            throw new IllegalArgumentException("Given type does not extend Throwable.");
         }
         return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName());
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java	Wed Mar 13 11:32:43 2013 +0100
@@ -62,7 +62,7 @@
 
     @Override
     public SpecializationData create(TemplateMethod method) {
-        SpecializationData data = new SpecializationData(method, true, false);
+        SpecializationData data = new SpecializationData(method, true, false, false);
         data.setUseSpecializationsForGeneric(Utils.getAnnotationValueBoolean(data.getMarkerAnnotation(), "useSpecializations"));
         return data;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Wed Mar 13 11:32:43 2013 +0100
@@ -34,7 +34,8 @@
 import com.oracle.truffle.api.codegen.*;
 import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.ast.*;
-import com.oracle.truffle.codegen.processor.node.NodeFieldData.*;
+import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind;
+import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind;
 import com.oracle.truffle.codegen.processor.template.*;
 import com.oracle.truffle.codegen.processor.typesystem.*;
 
@@ -145,7 +146,9 @@
     private void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) {
         body.startGroup();
         ExecutableElement method = templateMethod.getMethod();
-
+        if (method == null) {
+            throw new IllegalStateException("Cannot call synthtetic operation methods.");
+        }
         TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
         NodeData node = (NodeData) templateMethod.getTemplate();
 
@@ -419,6 +422,10 @@
         return builder.getRoot();
     }
 
+    private void emitEncounteredSynthetic(CodeTreeBuilder builder) {
+        builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
+    }
+
     @Override
     protected void createChildren(NodeData node) {
         Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>();
@@ -987,11 +994,15 @@
                 builder.startTryBlock();
             }
 
-            builder.startReturn();
-            startCallOperationMethod(builder, specialization, true);
-            addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false);
-            builder.end().end(); // start call operation
-            builder.end(); // return
+            if (specialization.isSynthetic()) {
+                emitEncounteredSynthetic(builder);
+            } else {
+                builder.startReturn();
+                startCallOperationMethod(builder, specialization, true);
+                addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false);
+                builder.end().end(); // start call operation
+                builder.end(); // return
+            }
 
             if (!specialization.getExceptions().isEmpty()) {
                 for (SpecializationThrowsData exception : specialization.getExceptions()) {
@@ -1005,6 +1016,7 @@
                 builder.end();
             }
         }
+
     }
 
     private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> {
@@ -1197,7 +1209,9 @@
                 builder.startTryBlock();
             }
 
-            if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) {
+            if (specialization.getMethod() == null) {
+                emitEncounteredSynthetic(builder);
+            } else if (specialization.isUninitialized() || specialization.isGeneric()) {
                 builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null));
                 builder.string("this");
                 addValueParameterNames(builder, specialization, null, true, true);
@@ -1205,12 +1219,9 @@
             } else {
                 builder.startReturn();
 
-                if (specialization.isUninitialized()) {
-                    startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false);
-                } else {
-                    startCallOperationMethod(builder, specialization, false);
-                }
+                startCallOperationMethod(builder, specialization, false);
                 addValueParameterNames(builder, specialization, null, false, false);
+
                 builder.end().end(); // operation call
                 builder.end(); // return
             }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Wed Mar 13 11:32:43 2013 +0100
@@ -68,14 +68,7 @@
         this.guards = copy.guards;
         this.executableTypes = copy.executableTypes;
         this.shortCircuits = copy.shortCircuits;
-
-        List<NodeFieldData> fieldsCopy = new ArrayList<>();
-        for (NodeFieldData field : copy.fields) {
-            NodeFieldData newField = new NodeFieldData(field);
-            newField.setNode(this);
-            fieldsCopy.add(newField);
-        }
-        this.fields = fieldsCopy;
+        this.fields = copy.fields;
     }
 
     public ParameterSpec getInstanceParameterSpec() {
@@ -186,6 +179,14 @@
         return null;
     }
 
+    public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) {
+        List<ExecutableTypeData> types = findGenericExecutableTypes(context);
+        if (!types.isEmpty()) {
+            return types.get(0);
+        }
+        return null;
+    }
+
     public List<ExecutableTypeData> findGenericExecutableTypes(ProcessorContext context) {
         List<ExecutableTypeData> types = new ArrayList<>();
         for (ExecutableTypeData type : executableTypes) {
@@ -250,18 +251,13 @@
 
     public boolean needsRewrites(ProcessorContext context) {
         boolean needsRewrites = false;
-        for (NodeFieldData field : getFields()) {
-            if (field.getExecutionKind() == ExecutionKind.DEFAULT || field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) {
-                if (!field.getNodeData().hasUnexpectedExecutableTypes(context)) {
-                    continue;
-                }
 
+        for (SpecializationData specialization : getSpecializations()) {
+            if (specialization.hasRewrite(context)) {
                 needsRewrites = true;
                 break;
             }
         }
-
-        needsRewrites &= specializations.size() >= 2;
         return needsRewrites;
     }
 
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java	Wed Mar 13 11:32:43 2013 +0100
@@ -103,7 +103,7 @@
 
     @Override
     public String toString() {
-        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + "]";
+        return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData().toString() + "]";
     }
 
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Wed Mar 13 11:32:43 2013 +0100
@@ -120,6 +120,10 @@
             return null; // not a node
         }
 
+        if (type.getModifiers().contains(Modifier.PRIVATE)) {
+            return null; // not visible
+        }
+
         TypeElement nodeType;
         boolean needsSplit;
         if (methodNodes != null) {
@@ -130,10 +134,6 @@
             nodeType = type;
         }
 
-        if (type.getModifiers().contains(Modifier.PRIVATE)) {
-            return null; // not visible
-        }
-
         NodeData nodeData = parseNodeData(type, nodeType);
         if (nodeData == null) {
             return null;
@@ -271,28 +271,63 @@
             }
         }
 
+        if (generics.size() == 1 && specializations.size() == 1) {
+            for (SpecializationData generic : generics) {
+                log.error(generic.getMethod(), "@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName());
+            }
+        }
+
         SpecializationData genericSpecialization = null;
         if (generics.size() > 1) {
             for (SpecializationData generic : generics) {
-                log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
+                log.error(generic.getMethod(), "Only @%s is allowed per operation.", Generic.class.getSimpleName());
             }
             return false;
         } else if (generics.size() == 1) {
             genericSpecialization = generics.get(0);
-        } else {
-            // TODO support generation of generic if not ambiguous.
-        }
+            if (!node.needsRewrites(context)) {
+                log.error(genericSpecialization.getMethod(), "Generic specialization is not reachable.", Generic.class.getSimpleName());
+                return false;
+            }
+        } else if (node.needsRewrites(context)) {
+            SpecializationData specialization = specializations.get(0);
+            GenericParser parser = new GenericParser(context, node);
+            MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null);
+
+            ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context);
+            if (anyGenericReturnType == null) {
+                // TODO fail invalid executable type. should be validated by field. (assertion
+// failure!?)
+            }
 
-        if (specializations.size() > 1 && genericSpecialization == null) {
-            log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName());
-            return false;
+            ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false);
+            List<ActualParameter> parameters = new ArrayList<>();
+            for (ActualParameter specializationParameter : specialization.getParameters()) {
+                ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName());
+                NodeFieldData field = node.findField(parameterSpec.getName());
+                TypeMirror actualType;
+                if (field == null) {
+                    actualType = specializationParameter.getActualType();
+                } else {
+                    ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context);
+                    if (paramType == null) {
+                        // TODO fail
+                    }
+                    actualType = paramType.getType().getPrimitiveType();
+                }
+                parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isHidden()));
+            }
+            TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters);
+            genericSpecialization = new SpecializationData(genericMethod, true, false, true);
+
+            specializations.add(genericSpecialization);
         }
 
         if (genericSpecialization != null) {
             CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized");
-            TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getId(), node, genericSpecialization.getSpecification(), uninitializedMethod,
-                            genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters());
-            specializations.add(new SpecializationData(uninializedMethod, false, true));
+            TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(),
+                            genericSpecialization.getReturnType(), genericSpecialization.getParameters());
+            specializations.add(new SpecializationData(uninializedMethod, false, true, true));
         }
 
         Collections.sort(specializations, new Comparator<SpecializationData>() {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Wed Mar 13 11:32:43 2013 +0100
@@ -25,6 +25,7 @@
 import java.util.*;
 
 import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.codegen.processor.*;
 import com.oracle.truffle.codegen.processor.template.*;
 
 public class SpecializationData extends TemplateMethod {
@@ -38,11 +39,14 @@
     private boolean useSpecializationsForGeneric = true;
     private NodeData node;
 
+    private final boolean synthetic;
+
     public SpecializationData(TemplateMethod template, int order, List<SpecializationThrowsData> exceptions) {
         super(template);
         this.order = order;
         this.generic = false;
         this.uninitialized = false;
+        this.synthetic = false;
         this.exceptions = exceptions;
 
         for (SpecializationThrowsData exception : exceptions) {
@@ -50,13 +54,34 @@
         }
     }
 
-    public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized) {
+    public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized, boolean synthetic) {
         super(template);
         this.order = Specialization.DEFAULT_ORDER;
         this.generic = generic;
         this.uninitialized = uninitialized;
         this.exceptions = Collections.emptyList();
         this.guards = new SpecializationGuardData[0];
+        this.synthetic = synthetic;
+    }
+
+    public boolean hasRewrite(ProcessorContext context) {
+        if (getExceptions().size() > 0) {
+            return true;
+        }
+        if (getGuards().length > 0) {
+            return true;
+        }
+        for (ActualParameter parameter : getParameters()) {
+            NodeFieldData field = getNode().findField(parameter.getSpecification().getName());
+            if (field == null) {
+                continue;
+            }
+            ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem()));
+            if (type.hasUnexpectedValue(context)) {
+                return true;
+            }
+        }
+        return false;
     }
 
     public NodeData getNode() {
@@ -71,6 +96,10 @@
         this.guards = guards;
     }
 
+    public boolean isSynthetic() {
+        return synthetic;
+    }
+
     public int getOrder() {
         return order;
     }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Tue Mar 12 11:38:52 2013 +0100
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java	Wed Mar 13 11:32:43 2013 +0100
@@ -119,7 +119,11 @@
     }
 
     public String getMethodName() {
-        return getMethod().getSimpleName().toString();
+        if (getMethod() != null) {
+            return getMethod().getSimpleName().toString();
+        } else {
+            return "$synthetic";
+        }
     }
 
     public AnnotationMirror getMarkerAnnotation() {