Mercurial > hg > graal-compiler
diff graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLShare.java @ 16751:4f589fa69b9c
Truffle-DSL: added shared code required for the new generation layout.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 11 Aug 2014 15:53:05 +0200 |
parents | |
children | e6d15134ca86 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/graal/com.oracle.truffle.api.dsl/src/com/oracle/truffle/api/dsl/internal/DSLShare.java Mon Aug 11 15:53:05 2014 +0200 @@ -0,0 +1,176 @@ +package com.oracle.truffle.api.dsl.internal; + +import java.util.*; + +import com.oracle.truffle.api.nodes.*; + +/** Contains utility classes shared across generated DSLNode implementations. */ +public class DSLShare { + + public static boolean isExcluded(Node currentNode, DSLMetadata otherMetadata) { + assert otherMetadata.getExcludedBy().length > 0 : "At least one exclude must be defined for isIncluded."; + Node cur = findRoot(currentNode); + while (cur != null) { + Class<?> curClass = cur.getClass(); + if (curClass == otherMetadata.getSpecializationClass()) { + return true; + } else if (containsClass(otherMetadata.getExcludedBy(), cur)) { + return true; + } + cur = getNext(cur); + } + return false; + } + + private static boolean includes(Node oldNode, DSLNode newNode) { + return containsClass(newNode.getMetadata0().getIncludes(), oldNode); + } + + public static <T extends Node & DSLNode> T rewrite(Node thisNode, T newNode, String message) { + assert newNode != null; + if (getNext(thisNode) != null || getPrevious(thisNode) != null) { + // already polymorphic -> append + return appendPolymorphic(findUninitialized(thisNode), newNode); + } else if (includes(thisNode, newNode)) { + // included -> remains monomorphic + newNode.adoptChildren0(thisNode, null); + return thisNode.replace(newNode, message); + } else { + // goto polymorphic + return null; + } + } + + @SuppressWarnings("unchecked") + public static <T extends Node> T findRoot(T node) { + Node prev = node; + Node cur; + do { + cur = prev; + prev = getPrevious(cur); + } while (prev != null); + return (T) cur; + } + + private static Node findUninitialized(Node node) { + Node next = node; + Node cur; + do { + cur = next; + next = getNext(cur); + } while (next != null); + return cur; + } + + public static <T extends Node & DSLNode> T rewriteUninitialized(Node uninitialized, T newNode) { + Node prev = getPrevious(uninitialized); + if (prev == null) { + newNode.adoptChildren0(uninitialized, null); + return uninitialized.replace(newNode, "Uninitialized monomorphic"); + } else { + return appendPolymorphic(uninitialized, newNode); + } + } + + public static <T extends Node & DSLNode> T rewriteToPolymorphic(Node oldNode, DSLNode uninitialized, T polymorphic, DSLNode currentCopy, DSLNode newNode, String message) { + assert getNext(oldNode) == null; + assert getPrevious(oldNode) == null; + + polymorphic.adoptChildren0(oldNode, (Node) currentCopy); + + if (newNode == null) { + // fallback + currentCopy.adoptChildren0(null, (Node) uninitialized); + } else { + // new specialization + newNode.adoptChildren0(null, (Node) uninitialized); + currentCopy.adoptChildren0(null, (Node) newNode); + } + + oldNode.replace(polymorphic, message); + + assert polymorphic.getNext0() == currentCopy; + assert newNode != null ? currentCopy.getNext0() == newNode : currentCopy.getNext0() == uninitialized; + assert uninitialized.getNext0() == null; + return polymorphic; + } + + private static Class<?>[] mergeTypes(DSLNode node, Class<?>[] types) { + Class<?>[] specializedTypes = node.getMetadata0().getSpecializedTypes(); + if (specializedTypes.length == 0) { + return null; + } else if (types == null) { + return Arrays.copyOf(specializedTypes, specializedTypes.length); + } else { + for (int i = 0; i < specializedTypes.length; i++) { + if (specializedTypes[i] != types[i]) { + types[i] = Object.class; + } + } + return types; + } + } + + private static <T extends Node & DSLNode> T appendPolymorphic(Node uninitialized, T newNode) { + Class<?>[] includes = newNode.getMetadata0().getIncludes(); + Node cur = getPrevious(uninitialized); + Node prev = uninitialized; + int depth = 0; + Class<?>[] types = null; + while (cur != null) { + if (containsClass(includes, cur)) { + cur.replace(prev, "Included in other specialization"); + cur = prev; + } else { + depth++; + types = mergeTypes((DSLNode) cur, types); + } + prev = cur; + cur = getPrevious(cur); + } + assert prev.getCost() == NodeCost.POLYMORPHIC; + + if (depth == 0) { + newNode.adoptChildren0(prev, null); + return prev.replace(newNode, "Polymorphic to monomorphic."); + } else { + newNode.adoptChildren0(null, uninitialized); + ((DSLNode) prev).updateTypes0(mergeTypes(newNode, types)); + return uninitialized.replace(newNode, "Appended polymorphic"); + } + } + + private static boolean containsClass(Class<?>[] classList, Node node) { + Class<?> nodeClass = node.getClass(); + for (Class<?> toCheck : classList) { + if (nodeClass == toCheck) { + if (node.getCost() == NodeCost.UNINITIALIZED) { + /* + * In case a specialization is excluded by the fallback specialization the + * uninitialized class is used as exclusion class. Because the fallback field in + * the uninitialized specialization is not accessible we use the costs to check + * if the fallback was reached or not. In case the fallback was reached in the + * uninitialized version the cost is MONOMORPHIC, otherwise it is UNINITIALIZED. + */ + continue; + } + return true; + } + } + return false; + } + + private static Node getNext(Node node) { + return ((DSLNode) node).getNext0(); + } + + private static Node getPrevious(Node node) { + Node parent = node.getParent(); + if (parent instanceof DSLNode && getNext(parent) == node) { + return parent; + } else { + return null; + } + } + +} \ No newline at end of file