# HG changeset patch # User Christos Kotselidis # Date 1373878754 -7200 # Node ID 257e2455270eca88273aac3e01538f380e03ada9 # Parent cbaf26740df8f337802e467c55c30ddf352fb99f# Parent ff6eb563a2e27811da09193885226d4e3039e641 Merge diff -r cbaf26740df8 -r 257e2455270e graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/PolymorphicTest2.java --- /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 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)"; + } + + } + +} diff -r cbaf26740df8 -r 257e2455270e graal/com.oracle.truffle.api/src/com/oracle/truffle/api/nodes/NodeUtil.java --- 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 clazz) { Field[] declaredFields = clazz.getDeclaredFields(); @@ -660,4 +689,5 @@ p.print(" "); } } + } diff -r cbaf26740df8 -r 257e2455270e graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java --- 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()) {