changeset 13277:ce017d1e4234

Merge.
author Christian Humer <christian.humer@gmail.com>
date Mon, 09 Dec 2013 17:31:12 +0100
parents 06afa0db90b3 (diff) 68b964b6dc8e (current diff)
children 038f55aab194
files graal/com.oracle.graal.compiler.ptx/src/com/oracle/graal/compiler/ptx/PTXTargetMethodAssembler.java graal/com.oracle.graal.lir/src/com/oracle/graal/lir/asm/TargetMethodAssembler.java graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64HotSpotTruffleBackend.java graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/AMD64HotSpotTruffleBackendFactory.java graal/com.oracle.graal.truffle.hotspot.amd64/src/com/oracle/graal/truffle/hotspot/amd64/util/OptimizedCallTargetFieldInfo.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleBackendFactory.java
diffstat 16 files changed, 328 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ExecuteEvaluatedTest.java	Mon Dec 09 17:31:12 2013 +0100
@@ -26,8 +26,22 @@
 
 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.TestEvaluatedVarArgs3Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs4Factory;
+import com.oracle.truffle.api.dsl.test.ExecuteEvaluatedTestFactory.TestEvaluatedVarArgs5Factory;
+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 +140,120 @@
         }
     }
 
+    @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;
+        }
+    }
+
+    @Test
+    public void test3VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs3> root = TestHelper.createRoot(TestEvaluatedVarArgs3Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 42));
+    }
+
+    @NodeChild
+    abstract static class TestEvaluatedVarArgs3 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0) {
+            return exp0;
+        }
+    }
+
+    @Test
+    public void test4VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs4> root = TestHelper.createRoot(TestEvaluatedVarArgs4Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null, 21, 21));
+    }
+
+    @NodeChildren({@NodeChild, @NodeChild})
+    abstract static class TestEvaluatedVarArgs4 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call(int exp0, int exp1) {
+            return exp0 + exp1;
+        }
+    }
+
+    @Test
+    public void test5VarArgs1() {
+        TestRootNode<TestEvaluatedVarArgs5> root = TestHelper.createRoot(TestEvaluatedVarArgs5Factory.getInstance());
+        Assert.assertEquals(42, root.getNode().execute1(null));
+    }
+
+    abstract static class TestEvaluatedVarArgs5 extends ValueNode {
+
+        public abstract Object execute1(VirtualFrame frame, Object... value);
+
+        @Specialization
+        int call() {
+            return 42;
+        }
+    }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/ast/CodeExecutableElement.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/AbstractCodeWriter.java	Mon Dec 09 17:31:12 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/ExecutableTypeMethodParser.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/ExecutableTypeMethodParser.java	Mon Dec 09 17:31:12 2013 +0100
@@ -39,6 +39,7 @@
         super(context, node);
         setEmitErrors(false);
         setParseNullOnError(false);
+        setUseVarArgs(true);
     }
 
     @Override
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Dec 09 17:31:12 2013 +0100
@@ -478,6 +478,14 @@
         return createCastType(typeSystem, sourceType, targetType, true, expression);
     }
 
+    public CodeTree createDeoptimize(CodeTreeBuilder parent) {
+        CodeTreeBuilder builder = new CodeTreeBuilder(parent);
+        builder.startStatement();
+        builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end();
+        builder.end();
+        return builder.getRoot();
+    }
+
     private class NodeFactoryFactory extends ClassElementFactory<NodeData> {
 
         private final Map<NodeData, List<TypeElement>> childTypes;
@@ -1015,7 +1023,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 +2110,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 +2426,7 @@
                 throw new AssertionError();
             }
             if (targetParameter.getSpecification().isIndexed()) {
-                builder.string("[" + targetParameter.getIndex() + "]");
+                builder.string("[" + targetParameter.getSpecificationIndex() + "]");
             }
             return builder.getRoot();
         }
@@ -2470,14 +2478,6 @@
             return builder.getRoot();
         }
 
-        protected CodeTree createDeoptimize(CodeTreeBuilder parent) {
-            CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startStatement();
-            builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end();
-            builder.end();
-            return builder.getRoot();
-        }
-
         protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData current, ActualParameter exceptionParam, String reason) {
             NodeData node = current.getNode();
             SpecializationData generic = node.getGenericSpecialization();
@@ -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));
@@ -2786,7 +2786,7 @@
             NodeData node = specialization.getNode();
 
             CodeTreeBuilder builder = new CodeTreeBuilder(parent);
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.tree(createDeoptimize(builder));
 
             builder.declaration(getContext().getTruffleTypes().getNode(), "root", "this");
             builder.declaration(getContext().getType(int.class), "depth", "0");
@@ -2851,15 +2851,46 @@
         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) {
+                            if (varArgCount <= 0) {
+                                break;
+                            }
+                            TypeMirror type = baseVarArgs.getType();
+                            if (type.getKind() == TypeKind.ARRAY) {
+                                type = ((ArrayType) type).getComponentType();
+                            }
+                            builder.declaration(type, valueNameEvaluated(varArg), name + "[" + varArg.getVarArgsIndex() + "]");
+                            varArgCount--;
+                        }
+                    }
+                }
+                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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeData.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/SpecializationData.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/ActualParameter.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/MethodSpec.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethod.java	Mon Dec 09 17:31:12 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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/template/TemplateMethodParser.java	Mon Dec 09 17:31:12 2013 +0100
@@ -44,12 +44,21 @@
 
     private boolean emitErrors = true;
     private boolean parseNullOnError = false;
+    private boolean useVarArgs = false;
 
     public TemplateMethodParser(ProcessorContext context, T template) {
         this.template = template;
         this.context = context;
     }
 
+    protected void setUseVarArgs(boolean useVarArgs) {
+        this.useVarArgs = useVarArgs;
+    }
+
+    public boolean isUseVarArgs() {
+        return useVarArgs;
+    }
+
     public boolean isEmitErrors() {
         return emitErrors;
     }
@@ -140,7 +149,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 +170,7 @@
             parameterTypes.add(var.asType());
         }
 
-        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes);
+        List<ActualParameter> parameters = parseParameters(methodSpecification, parameterTypes, isUseVarArgs() && method.isVarArgs());
         if (parameters == null) {
             if (isEmitErrors()) {
                 E invalidMethod = create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, Collections.<ActualParameter> emptyList()), true);
@@ -201,7 +210,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 +220,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 +253,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 +273,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 +288,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 +306,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 +325,7 @@
             }
         }
 
-        if (!types.toList().isEmpty()) {
+        if (!types.toList().isEmpty() && !(varArgs && types.isLast())) {
             // additional types -> error
             return null;
         }
@@ -311,7 +337,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 +349,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 +372,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	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/GuardParser.java	Mon Dec 09 17:31:12 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);
             }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/typesystem/TypeSystemCodeGenerator.java	Mon Dec 09 17:31:12 2013 +0100
@@ -221,7 +221,7 @@
             }
 
             builder.startElseBlock();
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
             builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end();
             builder.end();
             return method;
@@ -248,7 +248,7 @@
             }
 
             builder.startElseBlock();
-            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end();
+            builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreterAndInvalidate").end().end();
             builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).doubleQuote("Illegal type ").end().end();
             builder.end();
 
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/SLNodeFactory.java	Mon Dec 09 17:31:12 2013 +0100
@@ -59,10 +59,6 @@
         this.parser = parser;
     }
 
-    public CallTarget findFunction(String name) {
-        return context.getFunctionRegistry().lookup(name);
-    }
-
     public void startFunction() {
         frameDescriptor = new FrameDescriptor();
     }
--- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Mon Dec 09 15:24:27 2013 +0100
+++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/CallNode.java	Mon Dec 09 17:31:12 2013 +0100
@@ -140,22 +140,21 @@
                     }
                     return new InlinableCallNode((DefaultCallTarget) function, clonedArgs);
                 }
+                // got a call target that is not inlinable (should not occur for SL)
+                return new DispatchedCallNode(defaultFunction, clonedArgs);
+            } else {
+                throw new AssertionError();
             }
 
-            // got a call target that is not inlinable (should not occur for SL)
-            return new DispatchedCallNode(function, clonedArgs);
         }
     }
 
     private static final class InlinableCallNode extends DispatchedCallNode implements InlinableCallSite {
 
-        private final DefaultCallTarget inlinableTarget;
-
         @CompilationFinal private int callCount;
 
         InlinableCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
             super(function, arguments);
-            this.inlinableTarget = function;
         }
 
         @Override
@@ -170,7 +169,7 @@
 
         @Override
         public Node getInlineTree() {
-            RootNode root = inlinableTarget.getRootNode();
+            RootNode root = function.getRootNode();
             if (root instanceof FunctionRootNode) {
                 return ((FunctionRootNode) root).getUninitializedBody();
             }
@@ -182,7 +181,7 @@
             CompilerAsserts.neverPartOfCompilation();
             TypedNode functionCall = null;
 
-            RootNode root = inlinableTarget.getRootNode();
+            RootNode root = function.getRootNode();
             if (root instanceof FunctionRootNode) {
                 functionCall = ((FunctionRootNode) root).inline(NodeUtil.cloneNode(args));
             }
@@ -204,7 +203,7 @@
 
         @Override
         public CallTarget getCallTarget() {
-            return inlinableTarget;
+            return function;
         }
 
     }
@@ -212,9 +211,9 @@
     private static class DispatchedCallNode extends TypedNode {
 
         @Child protected ArgumentsNode args;
-        protected final CallTarget function;
+        protected final DefaultCallTarget function;
 
-        DispatchedCallNode(CallTarget function, ArgumentsNode arguments) {
+        DispatchedCallNode(DefaultCallTarget function, ArgumentsNode arguments) {
             this.args = adoptChild(arguments);
             this.function = function;
         }