Mercurial > hg > graal-compiler
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.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 | 4f45e4d3361c |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Tue Apr 14 15:12:48 2015 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Tue Apr 14 15:12:48 2015 +0200 @@ -33,6 +33,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; import com.oracle.truffle.api.dsl.internal.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.expression.*; @@ -43,7 +44,6 @@ import com.oracle.truffle.dsl.processor.model.*; import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; -import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature; @DSLOptions public class NodeParser extends AbstractParser<NodeData> { @@ -104,8 +104,9 @@ } catch (CompileErrorException e) { throw e; } catch (Throwable e) { - e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e)); - throw e; + RuntimeException e2 = new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType))); + e2.addSuppressed(e); + throw e2; } if (node == null && !enclosedNodes.isEmpty()) { node = new NodeData(context, rootType); @@ -147,17 +148,16 @@ node.getFields().addAll(parseFields(lookupTypes, members)); node.getChildren().addAll(parseChildren(lookupTypes, members)); node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members)); - node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes()))); + node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false)); initializeExecutableTypes(node); initializeImportGuards(node, lookupTypes, members); + initializeChildren(node); if (node.hasErrors()) { return node; // error sync point } - initializeChildren(node); - if (node.hasErrors()) { return node; // error sync point } @@ -170,9 +170,10 @@ if (node.hasErrors()) { return node; // error sync point } + initializeSpecializations(members, node); + initializeExecutableTypeHierarchy(node); verifySpecializationSameLength(node); - initializeSpecializations(members, node); initializeShortCircuits(node); // requires specializations and polymorphic specializations verifyVisibilities(node); @@ -183,6 +184,67 @@ return node; } + private static void initializeExecutableTypeHierarchy(NodeData node) { + SpecializationData polymorphic = node.getPolymorphicSpecialization(); + if (polymorphic != null) { + boolean polymorphicSignatureFound = false; + TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null; + ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic)); + for (ExecutableTypeData type : node.getExecutableTypes()) { + if (polymorphicType.sameSignature(type)) { + polymorphicSignatureFound = true; + break; + } + } + + if (!polymorphicSignatureFound) { + node.getExecutableTypes().add(polymorphicType); + } + } + + List<ExecutableTypeData> rootTypes = buildExecutableHierarchy(node); + List<ExecutableTypeData> additionalAbstractRootTypes = new ArrayList<>(); + for (int i = 1; i < rootTypes.size(); i++) { + ExecutableTypeData rootType = rootTypes.get(i); + if (rootType.isAbstract()) { + // cannot implemement root + additionalAbstractRootTypes.add(rootType); + } else { + node.getExecutableTypes().remove(rootType); + } + } + if (!additionalAbstractRootTypes.isEmpty()) { + node.addError("Incompatible abstract execute methods found %s.", rootTypes); + } + + } + + private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) { + List<ExecutableTypeData> executes = node.getExecutableTypes(); + if (executes.isEmpty()) { + return Collections.emptyList(); + } + List<ExecutableTypeData> hierarchyExecutes = new ArrayList<>(executes); + Collections.sort(hierarchyExecutes); + ExecutableTypeData parent = hierarchyExecutes.get(0); + ListIterator<ExecutableTypeData> executesIterator = hierarchyExecutes.listIterator(1); + buildExecutableHierarchy(node, parent, executesIterator); + return hierarchyExecutes; + } + + private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) { + while (executesIterator.hasNext()) { + ExecutableTypeData other = executesIterator.next(); + if (other.canDelegateTo(node, parent)) { + parent.addDelegatedFrom(other); + executesIterator.remove(); + } + } + for (int i = 1; i < parent.getDelegatedFrom().size(); i++) { + buildExecutableHierarchy(node, parent.getDelegatedFrom().get(i - 1), parent.getDelegatedFrom().listIterator(i)); + } + } + private List<Element> loadMembers(TypeElement templateType) { List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType)); @@ -512,13 +574,17 @@ return executions; } - private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes) { + private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) { List<ExecutableTypeData> typeData = new ArrayList<>(); for (ExecutableElement method : ElementFilter.methodsIn(elements)) { Set<Modifier> modifiers = method.getModifiers(); if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) { continue; } + if (!includeFinals && modifiers.contains(Modifier.FINAL)) { + continue; + } + if (!method.getSimpleName().toString().startsWith("execute")) { continue; } @@ -545,6 +611,19 @@ } Collections.sort(typeData); + + List<String> names = new ArrayList<>(); + for (ExecutableTypeData type : typeData) { + names.add(type.getUniqueName()); + } + while (renameDuplicateIds(names)) { + // fix point + } + + for (int i = 0; i < typeData.size(); i++) { + typeData.get(i).setUniqueName(names.get(i)); + } + return typeData; } @@ -582,47 +661,16 @@ node.setFrameType(frameType); - int totalGenericCount = 0; - int totalVoidCount = 0; - for (Integer evaluatedCount : evaluatedCounts) { - List<ExecutableTypeData> genericExecutes = node.findGenericExecutableTypes(context, evaluatedCount); - int genericCount = 0; - int voidCount = 0; - for (ExecutableTypeData executableTypeData : genericExecutes) { - if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) { - if (ElementUtils.isVoid(executableTypeData.getReturnType())) { - voidCount++; - } else { - genericCount++; - } - } + boolean genericFound = false; + for (ExecutableTypeData type : node.getExecutableTypes()) { + if (!type.hasUnexpectedValue(context)) { + genericFound = true; + break; } - // multiple generic execute - if (evaluatedCount == 0) { - if (voidCount > 1) { - List<String> methodSignatures = new ArrayList<>(); - for (ExecutableTypeData type : genericExecutes) { - if (context.isType(type.getReturnType(), void.class)) { - methodSignatures.add(ElementUtils.createReferenceName(type.getMethod())); - } - } - node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); - } else if (genericCount > 1) { - List<String> methodSignatures = new ArrayList<>(); - for (ExecutableTypeData type : genericExecutes) { - if (!context.isType(type.getReturnType(), void.class)) { - methodSignatures.add(ElementUtils.createReferenceName(type.getMethod())); - } - } - node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures); - } - } - totalGenericCount += genericCount; - totalVoidCount += voidCount; } // no generic executes - if (totalGenericCount + totalVoidCount == 0) { + if (!genericFound) { node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the " + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions."); } @@ -658,25 +706,6 @@ } - private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) { - Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>(); - for (ExecutableTypeData type : executableTypes) { - int evaluatedCount = type.getEvaluatedCount(); - - List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount); - if (types == null) { - types = new ArrayList<>(); - groupedTypes.put(evaluatedCount, types); - } - types.add(type); - } - - for (List<ExecutableTypeData> types : groupedTypes.values()) { - Collections.sort(types); - } - return groupedTypes; - } - private void initializeChildren(NodeData node) { initializeExecuteWith(node); @@ -759,7 +788,7 @@ if (parentNode.getFrameType() != null) { frameTypes = Arrays.asList(parentNode.getFrameType()); } - node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes))); + node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true)); node.setFrameType(parentNode.getFrameType()); return node; } @@ -1259,7 +1288,7 @@ if (execution == null) { allowedTypes = spec.getAllowedTypes(); } else { - allowedTypes = node.getPossibleTypes(execution); + allowedTypes = node.getGenericTypes(execution); } if (allowedTypes.size() == 1) { return allowedTypes.iterator().next(); @@ -1301,36 +1330,68 @@ SpecializationData generic = node.getGenericSpecialization(); - List<TypeMirror> polymorphicSignature = new ArrayList<>(); - List<Parameter> updatePolymorphic = Arrays.asList(); - for (Parameter genericParameter : updatePolymorphic) { - if (!genericParameter.getSpecification().isSignature()) { - continue; - } + List<VariableElement> types = new ArrayList<>(); - Set<TypeMirror> usedTypes = new HashSet<>(); - for (SpecializationData specialization : node.getSpecializations()) { - if (!specialization.isSpecialized()) { - continue; - } - Parameter parameter = specialization.findParameter(genericParameter.getLocalName()); - if (parameter == null) { - throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); - } - usedTypes.add(parameter.getType()); + Set<TypeMirror> frameTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.getFrame() != null) { + frameTypes.add(specialization.getFrame().getType()); } - - TypeMirror polymorphicType; - if (usedTypes.size() == 1) { - polymorphicType = usedTypes.iterator().next(); + } + if (!frameTypes.isEmpty()) { + TypeMirror frameType; + if (frameTypes.size() == 1) { + frameType = frameTypes.iterator().next(); } else { - polymorphicType = context.getType(Object.class); + frameType = context.getType(Frame.class); } - polymorphicSignature.add(polymorphicType); + types.add(new CodeVariableElement(frameType, "frameValue")); } - SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); - polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); + TypeMirror returnType = null; + int index = 0; + for (Parameter genericParameter : generic.getReturnTypeAndParameters()) { + TypeMirror polymorphicType; + if (!genericParameter.getSpecification().isSignature()) { + polymorphicType = genericParameter.getType(); + } else { + Set<TypeMirror> usedTypes = new HashSet<>(); + for (SpecializationData specialization : node.getSpecializations()) { + if (specialization.isUninitialized()) { + continue; + } + Parameter parameter = specialization.findParameter(genericParameter.getLocalName()); + if (parameter == specialization.getReturnType() && specialization.isFallback() && specialization.getMethod() == null) { + continue; + } + if (parameter == null) { + throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); + } + usedTypes.add(parameter.getType()); + } + + if (usedTypes.size() == 1) { + polymorphicType = usedTypes.iterator().next(); + + if (node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) { + polymorphicType = context.getType(Object.class); + } + } else { + polymorphicType = context.getType(Object.class); + } + } + if (genericParameter == generic.getReturnType()) { + returnType = polymorphicType; + } else { + types.add(new CodeVariableElement(polymorphicType, "param" + index)); + } + index++; + } + + SpecializationMethodParser parser = new SpecializationMethodParser(context, node); + + SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types); + polymorphic.setKind(SpecializationKind.POLYMORPHIC); node.getSpecializations().add(polymorphic); }