changeset 10746:257e2455270e

Merge
author Christos Kotselidis <christos.kotselidis@oracle.com>
date Mon, 15 Jul 2013 10:59:14 +0200
parents cbaf26740df8 (current diff) ff6eb563a2e2 (diff)
children 3811d04d933e
files
diffstat 3 files changed, 135 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java	Mon Jul 15 10:59:14 2013 +0200
@@ -0,0 +1,70 @@
+/*
+ * 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.dsl.test;
+
+import static com.oracle.truffle.api.dsl.test.TestHelper.*;
+import static org.junit.Assert.*;
+
+import org.junit.*;
+
+import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.dsl.test.BinaryNodeTest.BinaryNode;
+import com.oracle.truffle.api.dsl.test.PolymorphicTest2Factory.Node1Factory;
+import com.oracle.truffle.api.dsl.test.TypeSystemTest.TestRootNode;
+import com.oracle.truffle.api.nodes.*;
+import com.oracle.truffle.api.nodes.NodeInfo.Kind;
+
+public class PolymorphicTest2 {
+
+    @Test
+    public void testMultipleTypes() {
+        /* Tests the unexpected polymorphic case. */
+        TestRootNode<Node1> node = TestHelper.createRoot(Node1Factory.getInstance());
+        assertEquals(21, executeWith(node, false, false));
+        assertEquals(42, executeWith(node, 21, 21));
+        assertEquals("(boolean,int)", executeWith(node, false, 42));
+        assertEquals(Kind.POLYMORPHIC, node.getNode().getClass().getAnnotation(NodeInfo.class).kind());
+    }
+
+    @SuppressWarnings("unused")
+    @PolymorphicLimit(3)
+    abstract static class Node1 extends BinaryNode {
+
+        @Specialization(order = 1)
+        int add(int left, int right) {
+            return 42;
+        }
+
+        @Specialization(order = 2)
+        int add(boolean left, boolean right) {
+            return 21;
+        }
+
+        @Specialization(order = 4)
+        String add(boolean left, int right) {
+            return "(boolean,int)";
+        }
+
+    }
+
+}
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Jul 15 10:50:33 2013 +0200
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java	Mon Jul 15 10:59:14 2013 +0200
@@ -352,17 +352,26 @@
     public static void replaceChild(Node parent, Node oldChild, Node newChild) {
         NodeClass nodeClass = NodeClass.get(parent.getClass());
 
-        for (long fieldOffset : nodeClass.childOffsets) {
+        long[] fieldOffsets = nodeClass.childOffsets;
+        for (int i = 0; i < fieldOffsets.length; i++) {
+            long fieldOffset = fieldOffsets[i];
             if (unsafe.getObject(parent, fieldOffset) == oldChild) {
+                assert assertAssignable(nodeClass, parent, oldChild, newChild);
                 unsafe.putObject(parent, fieldOffset, newChild);
             }
         }
-        for (long fieldOffset : nodeClass.childrenOffsets) {
-            Node[] array = (Node[]) unsafe.getObject(parent, fieldOffset);
-            if (array != null) {
-                for (int i = 0; i < array.length; i++) {
-                    if (array[i] == oldChild) {
-                        array[i] = newChild;
+
+        long[] childrenOffsets = nodeClass.childrenOffsets;
+        for (int i = 0; i < childrenOffsets.length; i++) {
+            long fieldOffset = childrenOffsets[i];
+            Object arrayObject = unsafe.getObject(parent, fieldOffset);
+            if (arrayObject != null) {
+                assert arrayObject instanceof Node[] : "Children must be instanceof Node[] ";
+                Node[] array = (Node[]) arrayObject;
+                for (int j = 0; j < array.length; j++) {
+                    if (array[j] == oldChild) {
+                        assert newChild != null && array.getClass().getComponentType().isAssignableFrom(newChild.getClass()) : "Array type does not match";
+                        array[j] = newChild;
                         return;
                     }
                 }
@@ -370,6 +379,26 @@
         }
     }
 
+    private static boolean assertAssignable(NodeClass clazz, Node parent, Object oldValue, Object newValue) {
+        if (newValue == null) {
+            return true;
+        }
+        for (NodeField field : clazz.fields) {
+            if (field.kind != NodeFieldKind.CHILD) {
+                continue;
+            }
+            if (unsafe.getObject(parent, field.offset) == oldValue) {
+                if (!field.type.isAssignableFrom(newValue.getClass())) {
+                    assert false : "Child class " + newValue.getClass() + " is not assignable to field " + field.type.getName() + " at " + field.name + " in ";
+                    return false;
+                } else {
+                    break;
+                }
+            }
+        }
+        return true;
+    }
+
     /** Returns all declared fields in the class hierarchy. */
     private static Field[] getAllFields(Class<? extends Object> clazz) {
         Field[] declaredFields = clazz.getDeclaredFields();
@@ -660,4 +689,5 @@
             p.print("    ");
         }
     }
+
 }
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Jul 15 10:50:33 2013 +0200
+++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java	Mon Jul 15 10:59:14 2013 +0200
@@ -32,6 +32,7 @@
 import javax.lang.model.util.*;
 
 import com.oracle.truffle.api.dsl.*;
+import com.oracle.truffle.api.nodes.*;
 import com.oracle.truffle.api.nodes.NodeInfo.Kind;
 import com.oracle.truffle.dsl.processor.*;
 import com.oracle.truffle.dsl.processor.ast.*;
@@ -1226,6 +1227,12 @@
         private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) {
             String name = executeCachedName(polymorph);
             CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name);
+
+            ExecutableTypeData sourceExecutableType = node.findExecutableType(polymorph.getReturnType().getTypeSystemType(), 0);
+            boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext());
+            if (sourceThrowsUnexpected) {
+                cachedExecute.getThrownTypes().add(getContext().getType(UnexpectedResultException.class));
+            }
             addInternalValueParameters(cachedExecute, polymorph, true, true);
 
             if (polymorph == node.getGenericPolymorphicSpecialization()) {
@@ -2441,11 +2448,18 @@
             }
 
             if (!returnBuilder.isEmpty()) {
-                builder.startReturn();
+
+                ExecutableTypeData sourceExecutableType = node.findExecutableType(specialization.getReturnType().getTypeSystemType(), 0);
+                boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext());
+                boolean targetSupportsUnexpected = executable.hasUnexpectedValue(getContext());
 
                 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
                 TypeData sourceType = specialization.getReturnType().getTypeSystemType();
 
+                if (specialization.isPolymorphic() && sourceThrowsUnexpected && !targetSupportsUnexpected) {
+                    builder.startTryBlock();
+                }
+                builder.startReturn();
                 if (targetType == null || sourceType == null) {
                     builder.tree(returnBuilder.getRoot());
                 } else if (sourceType.needsCastTo(getContext(), targetType)) {
@@ -2454,6 +2468,19 @@
                     builder.tree(returnBuilder.getRoot());
                 }
                 builder.end();
+                if (specialization.isPolymorphic() && sourceThrowsUnexpected && !targetSupportsUnexpected) {
+                    builder.end();
+                    builder.startCatchBlock(getUnexpectedValueException(), "ex");
+                    builder.startReturn();
+                    CodeTree returns = CodeTreeBuilder.singleString("ex.getResult()");
+                    if (sourceType.needsCastTo(getContext(), targetType)) {
+                        builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), returns));
+                    } else {
+                        builder.tree(returns);
+                    }
+                    builder.end();
+                    builder.end();
+                }
             }
 
             if (!specialization.getExceptions().isEmpty()) {