changeset 10446:746fa60be266

Implemented CreateCast annotation for easier insertion of casts.
author Christian Humer <christian.humer@gmail.com>
date Thu, 20 Jun 2013 19:10:09 +0200
parents f158703c308c
children 638387729ddf
files graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/CreateCast.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/ast/CodeTreeBuilder.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastData.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastParser.java graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.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/NodeMethodParser.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
diffstat 11 files changed, 365 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.codegen/src/com/oracle/truffle/api/codegen/CreateCast.java	Thu Jun 20 19:10:09 2013 +0200
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.api.codegen;
+
+import java.lang.annotation.*;
+
+import com.oracle.truffle.api.nodes.*;
+
+/**
+ * Specifies a factory method that creates a {@link Node} which is used to cast this child.
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target({ElementType.METHOD})
+public @interface CreateCast {
+
+    String[] value();
+
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java	Thu Jun 20 19:10:09 2013 +0200
@@ -583,8 +583,13 @@
         List<? extends AnnotationValue> values = getAnnotationValue(List.class, mirror, name);
         List<T> result = new ArrayList<>();
 
-        for (AnnotationValue value : values) {
-            result.add(resolveAnnotationValue(expectedListType, value));
+        if (values != null) {
+            for (AnnotationValue value : values) {
+                T annotationValue = resolveAnnotationValue(expectedListType, value);
+                if (annotationValue != null) {
+                    result.add(annotationValue);
+                }
+            }
         }
         return result;
     }
@@ -595,6 +600,10 @@
 
     @SuppressWarnings({"unchecked"})
     private static <T> T resolveAnnotationValue(Class<T> expectedType, AnnotationValue value) {
+        if (value == null) {
+            return null;
+        }
+
         Object unboxedValue = value.accept(new AnnotationValueVisitorImpl(), null);
         if (unboxedValue != null) {
             if (expectedType == TypeMirror.class && unboxedValue instanceof String) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/ast/CodeTreeBuilder.java	Thu Jun 20 19:10:09 2013 +0200
@@ -563,7 +563,7 @@
 
     public ExecutableElement findMethod() {
         Element element = currentElement;
-        while (element != null && (element.getKind() != ElementKind.METHOD)) {
+        while (element != null && (element.getKind() != ElementKind.METHOD && (element.getKind() != ElementKind.CONSTRUCTOR))) {
             element = element.getEnclosingElement();
         }
         ExecutableElement found = element != null ? (ExecutableElement) element : null;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastData.java	Thu Jun 20 19:10:09 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import java.util.*;
+
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class CreateCastData extends TemplateMethod {
+
+    private final List<String> childNames;
+
+    public CreateCastData(TemplateMethod method, List<String> childNames) {
+        super(method);
+        this.childNames = childNames;
+    }
+
+    public List<String> getChildNames() {
+        return childNames;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/CreateCastParser.java	Thu Jun 20 19:10:09 2013 +0200
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.truffle.codegen.processor.node;
+
+import java.lang.annotation.*;
+import java.util.*;
+
+import javax.lang.model.element.*;
+import javax.lang.model.type.*;
+
+import com.oracle.truffle.api.codegen.*;
+import com.oracle.truffle.codegen.processor.*;
+import com.oracle.truffle.codegen.processor.template.*;
+
+public class CreateCastParser extends NodeMethodParser<CreateCastData> {
+
+    public CreateCastParser(ProcessorContext context, NodeData operation) {
+        super(context, operation);
+    }
+
+    @Override
+    public Class<? extends Annotation> getAnnotationType() {
+        return CreateCast.class;
+    }
+
+    @Override
+    public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) {
+        List<String> childNames = Utils.getAnnotationValueList(String.class, mirror, "value");
+        TypeMirror baseType = getContext().getTruffleTypes().getNode();
+        for (String childName : childNames) {
+            NodeChildData child = getNode().findChild(childName);
+            if (child != null) {
+                baseType = child.getOriginalType();
+                break;
+            }
+        }
+        MethodSpec spec = new MethodSpec(new InheritsParameterSpec(getContext(), "child", baseType));
+        addDefaultFieldMethodSpec(method, spec);
+        spec.addRequired(new ParameterSpec("castedChild", baseType)).setSignature(true);
+        return spec;
+    }
+
+    @Override
+    public CreateCastData create(TemplateMethod method) {
+        AnnotationMirror mirror = method.getMarkerAnnotation();
+        List<String> childNames = Utils.getAnnotationValueList(String.class, mirror, "value");
+        CreateCastData cast = new CreateCastData(method, childNames);
+        AnnotationValue value = Utils.getAnnotationValue(mirror, "value");
+        TypeMirror type = null;
+        if (childNames == null || childNames.isEmpty()) {
+            cast.addError(value, "No value specified but required.");
+            return cast;
+        }
+
+        for (String childName : childNames) {
+            NodeChildData child = getNode().findChild(childName);
+            if (child == null) {
+                // error
+                cast.addError(value, "Specified child '%s' not found.", childName);
+                continue;
+            }
+            if (type == null) {
+                type = child.getNodeType();
+            } else if (!Utils.typeEquals(type, child.getNodeType())) {
+                cast.addError(value, "All child nodes for a cast must have the same node type.");
+                continue;
+            }
+        }
+        return cast;
+    }
+
+    private static class InheritsParameterSpec extends ParameterSpec {
+
+        private final ProcessorContext context;
+
+        public InheritsParameterSpec(ProcessorContext context, String name, TypeMirror... allowedTypes) {
+            super(name, Arrays.asList(allowedTypes));
+            this.context = context;
+        }
+
+        @Override
+        public boolean matches(TypeMirror actualType) {
+            boolean found = false;
+            for (TypeMirror specType : getAllowedTypes()) {
+                if (Utils.isAssignable(context, actualType, specType)) {
+                    found = true;
+                    break;
+                }
+            }
+            return found;
+        }
+    }
+}
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeChildData.java	Thu Jun 20 19:10:09 2013 +0200
@@ -54,6 +54,7 @@
 
     private final String name;
     private final TypeMirror type;
+    private final TypeMirror originalType;
     private final Element accessElement;
 
     private final Cardinality cardinality;
@@ -63,11 +64,13 @@
 
     private NodeData nodeData;
 
-    public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, Element accessElement, Cardinality cardinality, ExecutionKind executionKind) {
+    public NodeChildData(Element sourceElement, AnnotationMirror sourceMirror, String name, TypeMirror nodeType, TypeMirror originalNodeType, Element accessElement, Cardinality cardinality,
+                    ExecutionKind executionKind) {
         this.sourceElement = sourceElement;
         this.sourceAnnotationMirror = sourceMirror;
         this.name = name;
         this.type = nodeType;
+        this.originalType = originalNodeType;
         this.accessElement = accessElement;
         this.cardinality = cardinality;
         this.executionKind = executionKind;
@@ -101,6 +104,10 @@
         return nodeData.getExecutableTypes(getExecuteWith().size());
     }
 
+    public TypeMirror getOriginalType() {
+        return originalType;
+    }
+
     @Override
     public Element getMessageElement() {
         return sourceElement;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java	Thu Jun 20 19:10:09 2013 +0200
@@ -143,7 +143,8 @@
         }
     }
 
-    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
+    private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName,
+                    String... customSignatureValueNames) {
         CodeTreeBuilder builder = parent.create();
 
         boolean castedValues = sourceMethod != targetMethod;
@@ -199,8 +200,13 @@
         }
         builder.startCall(method.getSimpleName().toString());
 
+        int signatureIndex = 0;
+
         for (ActualParameter targetParameter : targetMethod.getParameters()) {
-            ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
+            ActualParameter valueParameter = null;
+            if (sourceMethod != null) {
+                valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
+            }
             if (valueParameter == null) {
                 valueParameter = targetParameter;
             }
@@ -215,7 +221,10 @@
                 valueType = valueParameter.getTypeSystemType();
             }
 
-            if (targetParameter.getSpecification().isLocal()) {
+            if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) {
+                builder.string(customSignatureValueNames[signatureIndex]);
+                signatureIndex++;
+            } else if (targetParameter.getSpecification().isLocal()) {
                 builder.startGroup();
                 if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) {
                     builder.string(THIS_NODE_LOCAL_VAR_NAME).string(".");
@@ -522,8 +531,25 @@
         return builder.getRoot();
     }
 
-    private void emitEncounteredSynthetic(CodeTreeBuilder builder) {
-        builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
+    private void emitEncounteredSynthetic(CodeTreeBuilder builder, SpecializationData current) {
+        builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class));
+        builder.startGroup();
+        String sep = null;
+        for (ActualParameter parameters : current.getParameters()) {
+            if (parameters.getSpecification().isSignature()) {
+                if (sep == null) {
+                    builder.doubleQuote("Unsupported values: " + parameters.getLocalName() + " = ");
+                    sep = ", ";
+                } else {
+                    builder.string(" + ");
+                    builder.doubleQuote(sep + parameters.getLocalName() + " = ");
+                }
+                builder.string(" + ");
+                builder.string(parameters.getLocalName());
+            }
+        }
+        builder.end();
+        builder.end().end();
     }
 
     private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) {
@@ -669,7 +695,12 @@
             }
 
             for (VariableElement var : type.getFields()) {
-                method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString()));
+                NodeChildData child = getModel().findChild(var.getSimpleName().toString());
+                if (child != null) {
+                    method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName()));
+                } else {
+                    method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString()));
+                }
             }
 
             if (superConstructor != null) {
@@ -682,14 +713,25 @@
 
             for (VariableElement var : type.getFields()) {
                 builder.startStatement();
-                String varName = var.getSimpleName().toString();
-                builder.string("this.").string(varName);
+                String fieldName = var.getSimpleName().toString();
+
+                CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString());
+                builder.string("this.").string(var.getSimpleName().toString());
+
+                NodeChildData child = getModel().findChild(fieldName);
+                if (child != null) {
+                    CreateCastData createCast = getModel().findCast(child.getName());
+                    if (createCast != null) {
+                        fieldInit = createTemplateMethodCall(builder, null, getModel().getGenericSpecialization(), createCast, null, child.getName());
+                    }
+                }
+
                 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) {
-                    builder.string(" = adoptChild(").string(varName).string(")");
+                    builder.string(" = adoptChild(").tree(fieldInit).string(")");
                 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) {
-                    builder.string(" = adoptChildren(").string(varName).string(")");
+                    builder.string(" = adoptChildren(").tree(fieldInit).string(")");
                 } else {
-                    builder.string(" = ").string(varName);
+                    builder.string(" = ").tree(fieldInit);
                 }
                 builder.end();
             }
@@ -832,7 +874,7 @@
                         unreachableSpecializations.add(specialization);
                     } else {
                         filteredSpecializations.add(specialization);
-                        if (!specialization.isUninitialized() && !specialization.hasRewrite(getContext())) {
+                        if (!specialization.isUninitialized() && specialization.isGenericSpecialization(getContext())) {
                             unreachable = true;
                         }
                     }
@@ -877,7 +919,7 @@
             }
 
             if (specialize && executeCall == null && !current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
-                emitEncounteredSynthetic(builder);
+                emitEncounteredSynthetic(builder, current);
             } else if (specialize) {
 
                 if (current.getNode().getGenericSpecialization().isUseSpecializationsForGeneric()) {
@@ -890,7 +932,7 @@
                         }
                         builder.statement("resultIsSet = true");
                     } else {
-                        emitEncounteredSynthetic(builder);
+                        emitEncounteredSynthetic(builder, current);
                     }
                     builder.end();
                 }
@@ -922,7 +964,7 @@
                 }
             } else {
                 if (executeCall == null) {
-                    emitEncounteredSynthetic(builder);
+                    emitEncounteredSynthetic(builder, current);
                 } else {
                     builder.startReturn().tree(executeCall).end();
                 }
@@ -1165,7 +1207,7 @@
 
             CodeTreeBuilder builder = method.createBuilder();
             if (!node.needsRewrites(getContext())) {
-                builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end();
+                builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end();
             } else {
                 builder.startIf();
                 builder.string("types.length == 1");
@@ -1668,7 +1710,7 @@
                 returnBuilder.doubleQuote("Uninitialized");
                 returnBuilder.end();
             } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
-                emitEncounteredSynthetic(builder);
+                emitEncounteredSynthetic(builder, specialization);
             } else if (specialization.isGeneric()) {
                 returnBuilder.startCall("super", EXECUTE_GENERIC_NAME);
                 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java	Thu Jun 20 19:10:09 2013 +0200
@@ -50,6 +50,7 @@
     private Map<Integer, List<ExecutableTypeData>> executableTypes;
     private List<ShortCircuitData> shortCircuits;
     private List<String> assumptions;
+    private List<CreateCastData> casts;
 
     private String shortName;
 
@@ -74,6 +75,14 @@
         this.assumptions = splitSource.assumptions;
     }
 
+    public List<CreateCastData> getCasts() {
+        return casts;
+    }
+
+    void setCasts(List<CreateCastData> casts) {
+        this.casts = casts;
+    }
+
     void setShortName(String shortName) {
         this.shortName = shortName;
     }
@@ -133,6 +142,9 @@
         if (fields != null) {
             containerChildren.addAll(fields);
         }
+        if (casts != null) {
+            containerChildren.addAll(casts);
+        }
         return containerChildren;
     }
 
@@ -230,6 +242,9 @@
         methods.addAll(getSpecializationListeners());
         methods.addAll(getExecutableTypes());
         methods.addAll(getShortCircuits());
+        if (getCasts() != null) {
+            methods.addAll(getCasts());
+        }
 
         return methods;
     }
@@ -367,6 +382,7 @@
         dumpProperty(builder, indent, "executableTypes", getExecutableTypes());
         dumpProperty(builder, indent, "specializations", getSpecializations());
         dumpProperty(builder, indent, "assumptions", getAssumptions());
+        dumpProperty(builder, indent, "casts", getCasts());
         dumpProperty(builder, indent, "messages", collectMessages());
         if (getDeclaredNodes().size() > 0) {
             builder.append(String.format("\n%s  children = [", indent));
@@ -489,4 +505,15 @@
         return getClass().getSimpleName() + "[" + getNodeId() + "]";
     }
 
+    public CreateCastData findCast(String name) {
+        if (getCasts() != null) {
+            for (CreateCastData cast : getCasts()) {
+                if (cast.getChildNames().contains(name)) {
+                    return cast;
+                }
+            }
+        }
+        return null;
+    }
+
 }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeMethodParser.java	Thu Jun 20 19:10:09 2013 +0200
@@ -78,20 +78,15 @@
     protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, boolean shortCircuitsEnabled, String shortCircuitName) {
         MethodSpec methodSpec = new MethodSpec(createReturnParameterSpec());
 
-        if (getNode().supportsFrame()) {
-            methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
-        }
-
-        resolveAndAddImplicitThis(methodSpec, method);
+        addDefaultFrame(methodSpec);
+        addDefaultImplicitThis(method, methodSpec);
+        addDefaultFieldMethodSpec(method, methodSpec);
+        addDefaultChildren(shortCircuitsEnabled, shortCircuitName, methodSpec);
 
-        for (NodeFieldData field : getNode().getFields()) {
-            if (!Utils.isFieldAccessible(method, field.getVariable())) {
-                ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
-                spec.setLocal(true);
-                methodSpec.addOptional(spec);
-            }
-        }
+        return methodSpec;
+    }
 
+    private void addDefaultChildren(boolean shortCircuitsEnabled, String shortCircuitName, MethodSpec methodSpec) {
         // children are null when parsing executable types
         if (getNode().getChildren() != null) {
             for (NodeChildData child : getNode().getChildren()) {
@@ -117,11 +112,25 @@
                 }
             }
         }
+    }
 
-        return methodSpec;
+    private void addDefaultFrame(MethodSpec methodSpec) {
+        if (getNode().supportsFrame()) {
+            methodSpec.addOptional(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame()));
+        }
     }
 
-    protected void resolveAndAddImplicitThis(MethodSpec methodSpec, ExecutableElement method) {
+    protected void addDefaultFieldMethodSpec(ExecutableElement method, MethodSpec methodSpec) {
+        for (NodeFieldData field : getNode().getFields()) {
+            if (!Utils.isFieldAccessible(method, field.getVariable())) {
+                ParameterSpec spec = new ParameterSpec(field.getName(), field.getType());
+                spec.setLocal(true);
+                methodSpec.addOptional(spec);
+            }
+        }
+    }
+
+    protected void addDefaultImplicitThis(ExecutableElement method, MethodSpec methodSpec) {
         TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType();
 
         if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(getContext(), declaredType, getContext().getTruffleTypes().getNode())) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java	Thu Jun 20 19:10:09 2013 +0200
@@ -211,6 +211,7 @@
     private static List<NodeData> splitNodeData(NodeData node) {
         SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations());
         SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners());
+        SortedMap<String, List<CreateCastData>> groupedCasts = groupByNodeId(node.getCasts());
 
         Set<String> ids = new TreeSet<>();
         ids.addAll(groupedSpecializations.keySet());
@@ -220,6 +221,7 @@
         for (String id : ids) {
             List<SpecializationData> specializations = groupedSpecializations.get(id);
             List<SpecializationListenerData> listeners = groupedListeners.get(id);
+            List<CreateCastData> casts = groupedCasts.get(id);
 
             if (specializations == null) {
                 specializations = new ArrayList<>();
@@ -238,12 +240,14 @@
 
             copy.setSpecializations(specializations);
             copy.setSpecializationListeners(listeners);
+            copy.setCasts(casts);
 
             splitted.add(copy);
         }
 
         node.setSpecializations(new ArrayList<SpecializationData>());
         node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
+        node.setCasts(new ArrayList<CreateCastData>());
 
         return splitted;
     }
@@ -266,6 +270,7 @@
         node.setSpecializationListeners(new SpecializationListenerParser(context, node).parse(elements));
         List<SpecializationData> generics = new GenericParser(context, node).parse(elements);
         List<SpecializationData> specializations = new SpecializationMethodParser(context, node).parse(elements);
+        node.setCasts(new CreateCastParser(context, node).parse(elements));
 
         List<SpecializationData> allSpecializations = new ArrayList<>();
         allSpecializations.addAll(generics);
@@ -736,6 +741,18 @@
                 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value"));
             }
         }
+        Map<String, TypeMirror> castNodeTypes = new HashMap<>();
+        for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
+            AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, CreateCast.class);
+            if (mirror != null) {
+                List<String> children = (Utils.getAnnotationValueList(String.class, mirror, "value"));
+                if (children != null) {
+                    for (String child : children) {
+                        castNodeTypes.put(child, method.getReturnType());
+                    }
+                }
+            }
+        }
 
         List<NodeChildData> parsedChildren = new ArrayList<>();
         List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
@@ -768,6 +785,12 @@
                     cardinality = Cardinality.MANY;
                 }
 
+                TypeMirror originalChildType = childType;
+                TypeMirror castNodeType = castNodeTypes.get(name);
+                if (castNodeType != null) {
+                    childType = castNodeType;
+                }
+
                 Element getter = findGetter(elements, name, childType);
 
                 ExecutionKind kind = ExecutionKind.DEFAULT;
@@ -775,7 +798,7 @@
                     kind = ExecutionKind.SHORT_CIRCUIT;
                 }
 
-                NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, getter, cardinality, kind);
+                NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality, kind);
 
                 parsedChildren.add(nodeChild);
 
@@ -883,7 +906,7 @@
         }
 
         for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
-            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.typeEquals(method.getReturnType(), type)) {
+            if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && Utils.isAssignable(context, type, method.getReturnType())) {
                 return method;
             }
         }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Tue Jun 18 10:12:27 2013 +0200
+++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java	Thu Jun 20 19:10:09 2013 +0200
@@ -74,6 +74,24 @@
         return sinks;
     }
 
+    public boolean isGenericSpecialization(ProcessorContext context) {
+        if (hasRewrite(context)) {
+            return false;
+        }
+
+        for (ActualParameter parameter : getParameters()) {
+            NodeChildData child = getNode().findChild(parameter.getSpecification().getName());
+            if (child == null) {
+                continue;
+            }
+            if (!parameter.getTypeSystemType().isGeneric()) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
     public boolean hasRewrite(ProcessorContext context) {
         if (!getExceptions().isEmpty()) {
             return true;