changeset 13271:2b9fcffd6f36

Truffle-DSL: added support for generating execute methods with java varargs.
author Christian Humer <christian.humer@gmail.com>
date Sun, 01 Dec 2013 18:18:33 +0100
parents 401e1473c546
children 0b8335a4fb13
files graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java
diffstat 12 files changed, 242 insertions(+), 38 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Sun Dec 01 18:18:33 2013 +0100
@@ -26,8 +26,19 @@
 
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.dsl.*;
-import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.*;
-import com.oracle.truffle.api.dsl.test.TypeSystemTest.*;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.DoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.EvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedGenerationFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs0Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs1Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs2Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseDoubleEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.UseEvaluatedNodeFactory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ArgumentNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ChildrenNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestArguments;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.ValueNode;
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
@@ -126,4 +137,70 @@
         }
     }
 
+    @Test
+    public void test0VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs0> root = TestHelper.createRoot(TestEvaluatedVarArgs0Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs0 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call() {
+            return 42;
+        }
+    }
+
+    @Test
+    public void test1VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs1> root = TestHelper.createRoot(TestEvaluatedVarArgs1Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 42));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test1VarArgs2() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs1 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0) {
+            return exp0;
+        }
+    }
+
+    @Test
+    public void test2VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 21, 21));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2VarArgs2() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null, 42));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void test2VarArgs3() {
+        TestRootNode<TestEvaluatedVarArgs2> root = TestHelper.createRoot(TestEvaluatedVarArgs2Factory.getInstance());
+        Assert.assertEquals(-1, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs2 extends ChildrenNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0, int exp1) {
+            return exp0 + exp1;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Sun Dec 01 18:18:33 2013 +0100
@@ -113,6 +113,11 @@
         return name;
     }
 
+    public CodeTreeBuilder getBuilder() {
+        CodeTree tree = this.bodyTree;
+        return createBuilder().tree(tree);
+    }
+
     public CodeTreeBuilder createBuilder() {
         CodeTreeBuilder builder = new CodeTreeBuilder(null);
         this.bodyTree = builder.getTree();
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java	Sun Dec 01 18:18:33 2013 +0100
@@ -274,16 +274,28 @@
                 }
             }
         } else {
+            Element enclosing = f.getEnclosingElement();
             writeModifiers(f.getModifiers());
-            write(useImport(f, f.asType()));
 
-            if (f.getEnclosingElement().getKind() == ElementKind.METHOD) {
-                ExecutableElement method = (ExecutableElement) f.getEnclosingElement();
+            boolean varArgs = false;
+            if (enclosing.getKind() == ElementKind.METHOD) {
+                ExecutableElement method = (ExecutableElement) enclosing;
                 if (method.isVarArgs() && method.getParameters().indexOf(f) == method.getParameters().size() - 1) {
-                    write("...");
+                    varArgs = true;
                 }
             }
 
+            TypeMirror varType = f.asType();
+            if (varArgs) {
+                if (varType.getKind() == TypeKind.ARRAY) {
+                    varType = ((ArrayType) varType).getComponentType();
+                }
+                write(useImport(f, varType));
+                write("...");
+            } else {
+                write(useImport(f, varType));
+            }
+
             write(" ");
             write(f.getSimpleName());
             if (init != null) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Sun Dec 01 18:18:33 2013 +0100
@@ -1015,7 +1015,7 @@
                 CodeTreeBuilder access = builder.create();
                 access.string("this.").string(child.getName());
                 if (child.getCardinality().isMany()) {
-                    access.string("[").string(String.valueOf(param.getIndex())).string("]");
+                    access.string("[").string(String.valueOf(param.getSpecificationIndex())).string("]");
                 }
 
                 String oldName = "old" + Utils.firstLetterUpperCase(param.getLocalName());
@@ -2102,7 +2102,7 @@
                 return null;
             }
             String prefix = expect ? "expect" : "execute";
-            return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getIndex();
+            return prefix + Utils.firstLetterUpperCase(child.getName()) + Utils.firstLetterUpperCase(Utils.getSimpleName(param.getType())) + param.getSpecificationIndex();
         }
 
         private List<CodeExecutableElement> createExecuteChilds(ActualParameter param, Set<TypeData> expectTypes) {
@@ -2418,7 +2418,7 @@
                 throw new AssertionError();
             }
             if (targetParameter.getSpecification().isIndexed()) {
-                builder.string("[" + targetParameter.getIndex() + "]");
+                builder.string("[" + targetParameter.getSpecificationIndex() + "]");
             }
             return builder.getRoot();
         }
@@ -2729,7 +2729,7 @@
                 }
                 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true);
                 clazz.add(executeMethod);
-                CodeTreeBuilder builder = executeMethod.createBuilder();
+                CodeTreeBuilder builder = executeMethod.getBuilder();
                 CodeTree result = createExecuteBody(builder, specialization, execType);
                 if (result != null) {
                     builder.tree(result);
@@ -2757,7 +2757,7 @@
             ExecutableTypeData execType = parser.parse(Arrays.asList(executeCached)).get(0);
 
             CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false);
-            CodeTreeBuilder builder = executeMethod.createBuilder();
+            CodeTreeBuilder builder = executeMethod.getBuilder();
 
             if (specialization.isGeneric() || specialization.isPolymorphic()) {
                 builder.startThrow().startNew(getContext().getType(AssertionError.class));
@@ -2851,15 +2851,43 @@
         private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) {
             CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
 
+            CodeTreeBuilder builder = method.createBuilder();
             int i = 0;
+            int signatureIndex = -1;
             for (VariableElement param : method.getParameters()) {
                 CodeVariableElement var = CodeVariableElement.clone(param);
                 ActualParameter actualParameter = execType.getParameters().get(i);
+                if (actualParameter.getSpecification().isSignature()) {
+                    signatureIndex++;
+                }
+
+                String name;
                 if (evaluated && actualParameter.getSpecification().isSignature()) {
-                    var.setName(valueNameEvaluated(actualParameter));
+                    name = valueNameEvaluated(actualParameter);
                 } else {
-                    var.setName(valueName(actualParameter));
+                    name = valueName(actualParameter);
                 }
+
+                int varArgCount = getModel().getSignatureSize() - signatureIndex;
+                if (evaluated && actualParameter.isVarArgs()) {
+                    ActualParameter baseVarArgs = actualParameter;
+                    name = valueName(baseVarArgs) + "Args";
+
+                    builder.startAssert().string(name).string(" != null").end();
+                    builder.startAssert().string(name).string(".length == ").string(String.valueOf(varArgCount)).end();
+                    if (varArgCount > 0) {
+                        List<ActualParameter> varArgsParameter = execType.getParameters().subList(i, execType.getParameters().size());
+
+                        for (ActualParameter varArg : varArgsParameter) {
+                            TypeMirror type = baseVarArgs.getType();
+                            if (type.getKind() == TypeKind.ARRAY) {
+                                type = ((ArrayType) type).getComponentType();
+                            }
+                            builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getVarArgsIndex() + "]");
+                        }
+                    }
+                }
+                var.setName(name);
                 method.getParameters().set(i, var);
                 i++;
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Sun Dec 01 18:18:33 2013 +0100
@@ -78,6 +78,13 @@
         this.assumptions = splitSource.assumptions;
     }
 
+    public int getSignatureSize() {
+        if (getSpecializations() != null && !getSpecializations().isEmpty()) {
+            return getSpecializations().get(0).getSignatureSize();
+        }
+        return 0;
+    }
+
     public boolean needsFrame(ProcessorContext context) {
         for (SpecializationData specialization : specializations) {
             if (!specialization.isReachable()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Sun Dec 01 18:18:33 2013 +0100
@@ -205,6 +205,7 @@
 
             finalizeSpecializations(elements, splittedNode);
             verifyNode(splittedNode, elements);
+            expandExecutableTypeVarArgs(splittedNode);
             createPolymorphicSpecializations(splittedNode);
             assignShortCircuitsToSpecializations(splittedNode);
         }
@@ -217,6 +218,26 @@
         return node;
     }
 
+    private static void expandExecutableTypeVarArgs(NodeData node) {
+        for (ExecutableTypeData executableMethod : node.getExecutableTypes()) {
+            if (!(executableMethod.getMethod().isVarArgs() && executableMethod.getSpecification().isVariableRequiredArguments())) {
+                continue;
+            }
+            int expandArguments = node.getSignatureSize() - executableMethod.getSignatureSize();
+            if (expandArguments > 0) {
+                int signatureSize = executableMethod.getSignatureSize();
+                ActualParameter parameter = executableMethod.getSignatureParameter(signatureSize - 1);
+                for (int i = 0; i < expandArguments; i++) {
+                    int newVarArgsIndex = parameter.getVarArgsIndex() + i + 1;
+                    int newSpecificationIndex = parameter.getSpecificationIndex() + i + 1;
+                    executableMethod.getParameters().add(
+                                    new ActualParameter(parameter.getSpecification(), parameter.getTypeSystemType(), newSpecificationIndex, newVarArgsIndex, parameter.isImplicit()));
+                }
+
+            }
+        }
+    }
+
     private void createPolymorphicSpecializations(NodeData node) {
         if (!node.needsRewrites(context) || !node.isPolymorphic()) {
             node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList());
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java	Sun Dec 01 18:18:33 2013 +0100
@@ -261,7 +261,7 @@
         if (getParameters().isEmpty() || !Utils.typeEquals(getParameters().get(0).getType(), frameType)) {
             ParameterSpec frameSpec = getSpecification().findParameterSpec("frame");
             if (frameSpec != null) {
-                getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, false));
+                getParameters().add(0, new ActualParameter(frameSpec, frameType, -1, -1, false));
             }
         }
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java	Sun Dec 01 18:18:33 2013 +0100
@@ -33,49 +33,56 @@
     private TypeData typeSystemType;
     private TemplateMethod method;
     private final String localName;
-    private final int index;
+    private final int specificationIndex;
+    private final int varArgsIndex;
     private final boolean implicit;
     private final TypeMirror type;
 
-    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean implicit) {
+    public ActualParameter(ParameterSpec specification, TypeMirror actualType, int specificationIndex, int varArgsIndex, boolean implicit) {
         this.specification = specification;
         this.type = actualType;
         this.typeSystemType = null;
 
-        this.index = index;
+        this.specificationIndex = specificationIndex;
         this.implicit = implicit;
         String valueName = specification.getName() + "Value";
 
         if (specification.isIndexed()) {
-            valueName += index;
+            valueName += specificationIndex;
         }
+        this.varArgsIndex = varArgsIndex;
         this.localName = valueName;
     }
 
-    public ActualParameter(ParameterSpec specification, TypeData actualType, int index, boolean implicit) {
-        this(specification, actualType.getPrimitiveType(), index, implicit);
+    public ActualParameter(ParameterSpec specification, TypeData actualType, int specificationIndex, int varArgsIndex, boolean implicit) {
+        this(specification, actualType.getPrimitiveType(), specificationIndex, varArgsIndex, implicit);
         this.typeSystemType = actualType;
     }
 
     public ActualParameter(ActualParameter parameter, TypeData otherType) {
-        this(parameter.specification, otherType, parameter.index, parameter.implicit);
+        this(parameter.specification, otherType, parameter.specificationIndex, parameter.varArgsIndex, parameter.implicit);
     }
 
     public ActualParameter(ActualParameter parameter) {
         this.specification = parameter.specification;
         this.type = parameter.type;
         this.typeSystemType = parameter.typeSystemType;
-        this.index = parameter.index;
+        this.specificationIndex = parameter.specificationIndex;
         this.implicit = parameter.implicit;
         this.localName = parameter.localName;
+        this.varArgsIndex = parameter.varArgsIndex;
+    }
+
+    public int getVarArgsIndex() {
+        return varArgsIndex;
     }
 
     public boolean isImplicit() {
         return implicit;
     }
 
-    public int getIndex() {
-        return index;
+    public int getSpecificationIndex() {
+        return specificationIndex;
     }
 
     public String getLocalName() {
@@ -102,6 +109,10 @@
         return typeSystemType;
     }
 
+    public boolean isVarArgs() {
+        return varArgsIndex >= 0;
+    }
+
     public ActualParameter getPreviousParameter() {
         return method.getPreviousParam(this);
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java	Sun Dec 01 18:18:33 2013 +0100
@@ -37,6 +37,7 @@
     private final List<ParameterSpec> optional = new ArrayList<>();
     private final List<ParameterSpec> required = new ArrayList<>();
 
+    private int minimumRequiredArguments;
     private boolean variableRequiredArguments;
     private List<TypeDef> typeDefinitions;
 
@@ -44,6 +45,14 @@
         this.returnType = returnType;
     }
 
+    public void setMinimumRequiredArguments(int minimumRequiredArguments) {
+        this.minimumRequiredArguments = minimumRequiredArguments;
+    }
+
+    public int getMinimumRequiredArguments() {
+        return minimumRequiredArguments;
+    }
+
     public void setVariableRequiredArguments(boolean variableArguments) {
         this.variableRequiredArguments = variableArguments;
     }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Sun Dec 01 18:18:33 2013 +0100
@@ -202,6 +202,17 @@
         return prev;
     }
 
+    public int getSignatureSize() {
+        int signatureSize = 0;
+        for (ActualParameter parameter : getParameters()) {
+            if (!parameter.getSpecification().isSignature()) {
+                continue;
+            }
+            signatureSize++;
+        }
+        return signatureSize;
+    }
+
     public Signature getSignature() {
         Signature signature = new Signature();
         for (ActualParameter parameter : getReturnTypeAndParameters()) {
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java	Sun Dec 01 18:18:33 2013 +0100
@@ -140,7 +140,7 @@
 
         ParameterSpec returnTypeSpec = methodSpecification.getReturnType();
 
-        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false);
+        ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, -1, false);
         if (returnTypeMirror == null) {
             if (emitErrors) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()), true);
@@ -161,7 +161,7 @@
             parameterTypes.add(var.asType());
         }
 
-        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes);
+        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes, method.isVarArgs());
         if (parameters == null) {
             if (isEmitErrors()) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()), true);
@@ -201,7 +201,7 @@
      * ones are cut and used to parse the optional parameters. All those remaining parameters must
      * be consumed otherwise its an error.
      */
-    private List<ActualParameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes) {
+    private List<ActualParameter> parseParameters(MethodSpec spec, List<TypeMirror> parameterTypes, boolean varArgs) {
         List<TypeMirror> implicitTypes = spec.getImplicitRequiredTypes();
 
         int offset = -1;
@@ -211,7 +211,7 @@
             offset++;
             types = new ConsumableListIterator<>(new ArrayList<>(implicitTypes));
             types.data.addAll(parameterTypes.subList(offset, parameterTypes.size()));
-            parsedRequired = parseParametersRequired(spec, types);
+            parsedRequired = parseParametersRequired(spec, types, varArgs);
         }
 
         if (parsedRequired == null && offset >= 0) {
@@ -244,7 +244,7 @@
             int oldIndex = types.getIndex();
             int optionalCount = 1;
             for (ParameterSpec paramspec : optionals) {
-                ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, false);
+                ActualParameter optionalParam = matchParameter(paramspec, type, template, 0, -1, false);
                 if (optionalParam != null) {
                     optionals.consume(optionalCount);
                     types.consume();
@@ -264,9 +264,10 @@
         return parsedParams;
     }
 
-    private List<ActualParameter> parseParametersRequired(MethodSpec spec, ConsumableListIterator<TypeMirror> types) {
+    private List<ActualParameter> parseParametersRequired(MethodSpec spec, ConsumableListIterator<TypeMirror> types, boolean varArgs) {
         List<ActualParameter> parsedParams = new ArrayList<>();
 
+        int varArgsParameterIndex = -1;
         int specificationParameterIndex = 0;
         ConsumableListIterator<ParameterSpec> required = new ConsumableListIterator<>(spec.getRequired());
         while (required.get() != null || types.get() != null) {
@@ -278,8 +279,15 @@
                 }
                 break;
             }
+            TypeMirror actualType = types.get();
+            if (varArgs && types.isLast()) {
+                if (actualType.getKind() == TypeKind.ARRAY) {
+                    actualType = ((ArrayType) actualType).getComponentType();
+                }
+                varArgsParameterIndex++;
+            }
             boolean implicit = types.getIndex() < spec.getImplicitRequiredTypes().size();
-            ActualParameter resolvedParameter = matchParameter(required.get(), types.get(), template, specificationParameterIndex, implicit);
+            ActualParameter resolvedParameter = matchParameter(required.get(), actualType, template, specificationParameterIndex, varArgsParameterIndex, implicit);
             if (resolvedParameter == null) {
                 if (required.get().getCardinality() == Cardinality.MANY) {
                     required.consume();
@@ -289,7 +297,16 @@
                 return null;
             } else {
                 parsedParams.add(resolvedParameter);
-                types.consume();
+
+                if (varArgs && types.isLast()) {
+                    /* Both varargs spec and varargs definition. Need to consume to terminate. */
+                    if (required.get().getCardinality() == Cardinality.MANY) {
+                        types.consume();
+                    }
+                } else {
+                    types.consume();
+                }
+
                 if (required.get().getCardinality() == Cardinality.ONE) {
                     required.consume();
                     specificationParameterIndex = 0;
@@ -299,7 +316,7 @@
             }
         }
 
-        if (!types.toList().isEmpty()) {
+        if (!types.toList().isEmpty() && !(varArgs && types.isLast())) {
             // additional types -> error
             return null;
         }
@@ -311,7 +328,7 @@
         return parsedParams;
     }
 
-    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int index, boolean implicit) {
+    private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template originalTemplate, int specificationIndex, int varArgsIndex, boolean implicit) {
         TypeMirror resolvedType = mirror;
         if (hasError(resolvedType)) {
             resolvedType = context.resolveNotYetCompiledType(mirror, originalTemplate);
@@ -323,9 +340,9 @@
 
         TypeData resolvedTypeData = getTypeSystem().findTypeData(resolvedType);
         if (resolvedTypeData != null) {
-            return new ActualParameter(specification, resolvedTypeData, index, implicit);
+            return new ActualParameter(specification, resolvedTypeData, specificationIndex, varArgsIndex, implicit);
         } else {
-            return new ActualParameter(specification, resolvedType, index, implicit);
+            return new ActualParameter(specification, resolvedType, specificationIndex, varArgsIndex, implicit);
         }
     }
 
@@ -346,6 +363,10 @@
             return data.get(index);
         }
 
+        public boolean isLast() {
+            return index == data.size() - 1;
+        }
+
         public E consume() {
             return consume(1);
         }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java	Sat Nov 30 19:09:55 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java	Sun Dec 01 18:18:33 2013 +0100
@@ -93,9 +93,11 @@
             } else {
                 ActualParameter p;
                 if (parameter.getTypeSystemType() != null) {
-                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getIndex(), parameter.isImplicit());
+                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getTypeSystemType(), specializationParameter.getSpecificationIndex(),
+                                    specializationParameter.getVarArgsIndex(), parameter.isImplicit());
                 } else {
-                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getIndex(), parameter.isImplicit());
+                    p = new ActualParameter(specializationParameter.getSpecification(), parameter.getType(), specializationParameter.getSpecificationIndex(),
+                                    specializationParameter.getVarArgsIndex(), parameter.isImplicit());
                 }
                 newParameters.add(p);
             }