Mercurial > hg > truffle
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java @ 20940:476374f3fe9a
Truffle-DSL: generate better polymorphic execute signatures
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 14 Apr 2015 15:12:48 +0200 |
parents | 18c0f02fa4d2 |
children | 833e088ee7d3 |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Tue Apr 14 15:12:48 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/model/ExecutableTypeData.java Tue Apr 14 15:12:48 2015 +0200 @@ -24,6 +24,8 @@ import java.util.*; +import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; + import javax.lang.model.element.*; import javax.lang.model.type.*; @@ -34,11 +36,25 @@ public class ExecutableTypeData extends MessageContainer implements Comparable<ExecutableTypeData> { private final ExecutableElement method; + private final TypeMirror returnType; private final TypeMirror frameParameter; private final List<TypeMirror> evaluatedParameters; + private ExecutableTypeData delegatedTo; + private final List<ExecutableTypeData> delegatedFrom = new ArrayList<>(); + + private String uniqueName; + + public ExecutableTypeData(TypeMirror returnType, String uniqueName, TypeMirror frameParameter, List<TypeMirror> evaluatedParameters) { + this.returnType = returnType; + this.frameParameter = frameParameter; + this.evaluatedParameters = evaluatedParameters; + this.uniqueName = uniqueName; + this.method = null; + } public ExecutableTypeData(ExecutableElement method, int signatureSize, List<TypeMirror> frameTypes) { this.method = method; + this.returnType = method.getReturnType(); TypeMirror foundFrameParameter = null; List<? extends VariableElement> parameters = method.getParameters(); @@ -70,14 +86,32 @@ evaluatedParameters.add(parameter); } this.frameParameter = foundFrameParameter; + this.uniqueName = "execute" + (ElementUtils.isObject(getReturnType()) ? "" : ElementUtils.getTypeId(getReturnType())); + } + + public void addDelegatedFrom(ExecutableTypeData child) { + this.delegatedFrom.add(child); + child.delegatedTo = this; + } + + public List<ExecutableTypeData> getDelegatedFrom() { + return delegatedFrom; + } + + public ExecutableTypeData getDelegatedTo() { + return delegatedTo; } public ExecutableElement getMethod() { return method; } - public String getName() { - return method.getSimpleName().toString(); + public String getUniqueName() { + return uniqueName; + } + + public void setUniqueName(String name) { + this.uniqueName = name; } @Override @@ -106,27 +140,198 @@ } public TypeMirror getReturnType() { - return method.getReturnType(); + return returnType; } public boolean hasUnexpectedValue(ProcessorContext context) { - return ElementUtils.canThrowType(method.getThrownTypes(), context.getType(UnexpectedResultException.class)); + return method == null ? false : ElementUtils.canThrowType(method.getThrownTypes(), context.getType(UnexpectedResultException.class)); } public boolean isFinal() { - return method.getModifiers().contains(Modifier.FINAL); + return method == null ? false : method.getModifiers().contains(Modifier.FINAL); } public boolean isAbstract() { - return method.getModifiers().contains(Modifier.ABSTRACT); + return method == null ? false : method.getModifiers().contains(Modifier.ABSTRACT); } public int getEvaluatedCount() { return evaluatedParameters.size(); } - public int compareTo(ExecutableTypeData o) { - return ElementUtils.compareMethod(method, o.getMethod()); + public boolean canDelegateTo(NodeData node, ExecutableTypeData to) { + ExecutableTypeData from = this; + if (to.getEvaluatedCount() < from.getEvaluatedCount()) { + return false; + } + + ProcessorContext context = node.getContext(); + + // we cannot delegate from generic to unexpected + if (!from.hasUnexpectedValue(context) && to.hasUnexpectedValue(context)) { + return false; + } + + // we can skip the return type check for void. everything is assignable to void. + if (!isVoid(from.getReturnType())) { + if (!isSubtypeBoxed(context, from.getReturnType(), to.getReturnType()) && !isSubtypeBoxed(context, to.getReturnType(), from.getReturnType())) { + return false; + } + } + if (from.getFrameParameter() != to.getFrameParameter() && from.getFrameParameter() != null && to.getFrameParameter() != null && + !isSubtypeBoxed(context, from.getFrameParameter(), to.getFrameParameter())) { + return false; + } + + for (int i = 0; i < from.getEvaluatedCount(); i++) { + if (!isSubtypeBoxed(context, from.getEvaluatedParameters().get(i), to.getEvaluatedParameters().get(i))) { + return false; + } + } + + for (int i = from.getEvaluatedCount(); i < to.getEvaluatedCount(); i++) { + TypeMirror delegateToParameter = to.getEvaluatedParameters().get(i); + if (i < node.getChildExecutions().size()) { + List<TypeMirror> genericTypes = node.getGenericTypes(node.getChildExecutions().get(i)); + + boolean typeFound = false; + for (TypeMirror generic : genericTypes) { + if (isSubtypeBoxed(context, generic, delegateToParameter)) { + typeFound = true; + } + } + if (!typeFound) { + return false; + } + } + } + + return true; } + public int compareTo(ExecutableTypeData o2) { + ExecutableTypeData o1 = this; + ProcessorContext context = ProcessorContext.getInstance(); + + int result = Integer.compare(o2.getEvaluatedCount(), o1.getEvaluatedCount()); + if (result != 0) { + return result; + } + + result = Boolean.compare(o1.hasUnexpectedValue(context), o2.hasUnexpectedValue(context)); + if (result != 0) { + return result; + } + + result = compareType(context, o1.getReturnType(), o2.getReturnType()); + if (result != 0) { + return result; + } + result = compareType(context, o1.getFrameParameter(), o2.getFrameParameter()); + if (result != 0) { + return result; + } + + for (int i = 0; i < o1.getEvaluatedCount(); i++) { + result = compareType(context, o1.getEvaluatedParameters().get(i), o2.getEvaluatedParameters().get(i)); + if (result != 0) { + return result; + } + } + + result = o1.getUniqueName().compareTo(o2.getUniqueName()); + if (result != 0) { + return result; + } + + if (o1.getMethod() != null && o2.getMethod() != null) { + result = ElementUtils.compareMethod(o1.getMethod(), o2.getMethod()); + if (result != 0) { + return result; + } + } + return 0; + } + + public static int compareType(ProcessorContext context, TypeMirror signature1, TypeMirror signature2) { + if (signature1 == null) { + if (signature2 == null) { + return 0; + } + return -1; + } else if (signature2 == null) { + return 1; + } + if (ElementUtils.typeEquals(signature1, signature2)) { + return 0; + } + if (isVoid(signature1)) { + if (isVoid(signature2)) { + return 0; + } + return 1; + } else if (isVoid(signature2)) { + return -1; + } + + TypeMirror boxedType1 = ElementUtils.boxType(context, signature1); + TypeMirror boxedType2 = ElementUtils.boxType(context, signature2); + + if (ElementUtils.isSubtype(boxedType1, boxedType2)) { + if (ElementUtils.isSubtype(boxedType2, boxedType1)) { + return 0; + } + return 1; + } else if (ElementUtils.isSubtype(boxedType2, boxedType1)) { + return -1; + } else { + return ElementUtils.getSimpleName(signature1).compareTo(ElementUtils.getSimpleName(signature2)); + } + } + + @Override + public String toString() { + return method != null ? ElementUtils.createReferenceName(method) : getUniqueName() + evaluatedParameters.toString(); + } + + public boolean sameParameters(ExecutableTypeData other) { + if (!typeEquals(other.getFrameParameter(), getFrameParameter())) { + return false; + } + + if (getEvaluatedCount() != other.getEvaluatedCount()) { + return false; + } + + for (int i = 0; i < getEvaluatedCount(); i++) { + if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) { + return false; + } + } + return true; + } + + public boolean sameSignature(ExecutableTypeData other) { + if (!typeEquals(other.getReturnType(), getReturnType())) { + return false; + } + + if (other.getFrameParameter() != null) { + if (!typeEquals(getFrameParameter(), other.getFrameParameter())) { + return false; + } + } + + if (getEvaluatedCount() != other.getEvaluatedCount()) { + return false; + } + + for (int i = 0; i < getEvaluatedCount(); i++) { + if (!typeEquals(getEvaluatedParameters().get(i), other.getEvaluatedParameters().get(i))) { + return false; + } + } + + return true; + } }