Mercurial > hg > truffle
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @ 20938:18c0f02fa4d2
Truffle-DSL: make type systems optional.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 14 Apr 2015 15:12:48 +0200 |
parents | 8dc73c226c63 |
children | 476374f3fe9a |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java Tue Apr 14 22:12:03 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 @@ -32,7 +32,7 @@ import com.oracle.truffle.api.*; import com.oracle.truffle.api.dsl.*; -import com.oracle.truffle.api.dsl.NodeField; +import com.oracle.truffle.api.dsl.internal.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.dsl.processor.*; import com.oracle.truffle.dsl.processor.expression.*; @@ -45,6 +45,7 @@ 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> { public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, @@ -145,8 +146,8 @@ node.getFields().addAll(parseFields(lookupTypes, members)); node.getChildren().addAll(parseChildren(lookupTypes, members)); - node.getChildExecutions().addAll(parseExecutions(node.getChildren(), members)); - node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, null, context.getFrameTypes()).parse(members))); + node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members)); + node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes()))); initializeExecutableTypes(node); initializeImportGuards(node, lookupTypes, members); @@ -256,20 +257,19 @@ private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) { AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); - if (typeSystemMirror == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), ElementUtils.getQualifiedName(templateType)); - return nodeData; + TypeSystemData typeSystem = null; + if (typeSystemMirror != null) { + TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); + typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); + if (typeSystem == null) { + NodeData nodeData = new NodeData(context, templateType); + nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); + return nodeData; + } + } else { + // default dummy type system + typeSystem = new TypeSystemData(context, templateType, null, NodeParser.class.getAnnotation(DSLOptions.class), true); } - - TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value"); - final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true); - if (typeSystem == null) { - NodeData nodeData = new NodeData(context, templateType); - nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType)); - return nodeData; - } - AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class); String shortName = null; if (nodeInfoMirror != null) { @@ -406,11 +406,7 @@ return filteredChildren; } - private List<NodeExecutionData> parseExecutions(List<NodeChildData> children, List<? extends Element> elements) { - if (children == null) { - return null; - } - + private List<NodeExecutionData> parseExecutions(List<NodeFieldData> fields, List<NodeChildData> children, List<? extends Element> elements) { // pre-parse short circuits Set<String> shortCircuits = new HashSet<>(); List<ExecutableElement> methods = ElementFilter.methodsIn(elements); @@ -433,6 +429,13 @@ } } + List<NodeFieldData> nonGetterFields = new ArrayList<>(); + for (NodeFieldData field : fields) { + if (field.getGetter() == null && field.isGenerated()) { + nonGetterFields.add(field); + } + } + TypeMirror cacheAnnotation = context.getType(Cached.class); List<TypeMirror> frameTypes = context.getFrameTypes(); // pre-parse specializations to find signature size @@ -443,34 +446,40 @@ } int currentArgumentIndex = 0; boolean skipShortCircuit = false; - outer: for (VariableElement var : method.getParameters()) { + parameter: for (VariableElement var : method.getParameters()) { + if (skipShortCircuit) { + skipShortCircuit = false; + continue parameter; + } TypeMirror type = var.asType(); if (currentArgumentIndex == 0) { // skip optionals for (TypeMirror frameType : frameTypes) { if (ElementUtils.typeEquals(type, frameType)) { - continue outer; + continue parameter; + } + } + } + + if (currentArgumentIndex < nonGetterFields.size()) { + for (NodeFieldData field : nonGetterFields) { + if (ElementUtils.typeEquals(var.asType(), field.getType())) { + continue parameter; } } } if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) { - continue outer; + continue parameter; } int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1; - if (childIndex == -1) { - continue; - } - if (!skipShortCircuit) { + if (childIndex != -1) { NodeChildData child = children.get(childIndex); if (shortCircuits.contains(NodeExecutionData.createIndexedName(child, currentArgumentIndex - childIndex))) { skipShortCircuit = true; - continue; } - } else { - skipShortCircuit = false; } currentArgumentIndex++; @@ -480,24 +489,65 @@ List<NodeExecutionData> executions = new ArrayList<>(); for (int i = 0; i < maxSignatureSize; i++) { + boolean varArgParameter = false; int childIndex = i; - boolean varArg = false; - if (childIndex >= children.size() - 1) { + if (i >= children.size() - 1) { if (hasVarArgs) { - childIndex = children.size() - 1; - varArg = hasVarArgs; - } else if (childIndex >= children.size()) { - break; + varArgParameter = hasVarArgs; + childIndex = Math.min(i, children.size() - 1); + } else if (i >= children.size()) { + childIndex = -1; } } - int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; - NodeChildData child = children.get(childIndex); - boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex)); - executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); + int varArgsIndex = -1; + boolean shortCircuit = false; + NodeChildData child = null; + if (childIndex != -1) { + varArgsIndex = varArgParameter ? Math.abs(childIndex - i) : -1; + child = children.get(childIndex); + shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex)); + } + executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit)); } return executions; } + private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes) { + 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 (!method.getSimpleName().toString().startsWith("execute")) { + continue; + } + if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) { + continue; + } + + ExecutableTypeData executableType = new ExecutableTypeData(method, signatureSize, context.getFrameTypes()); + + if (executableType.getFrameParameter() != null) { + boolean supportedType = false; + for (TypeMirror type : frameTypes) { + if (ElementUtils.isAssignable(type, executableType.getFrameParameter())) { + supportedType = true; + break; + } + } + if (!supportedType) { + continue; + } + } + + typeData.add(executableType); + } + + Collections.sort(typeData); + return typeData; + } + private void initializeExecutableTypes(NodeData node) { List<ExecutableTypeData> allExecutes = node.getExecutableTypes(); @@ -507,10 +557,10 @@ for (ExecutableTypeData execute : allExecutes) { evaluatedCounts.add(execute.getEvaluatedCount()); - Parameter frame = execute.getFrame(); + TypeMirror frame = execute.getFrameParameter(); TypeMirror resolvedFrameType; if (frame != null) { - resolvedFrameType = frame.getType(); + resolvedFrameType = frame; if (frameType == null) { frameType = resolvedFrameType; } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) { @@ -540,7 +590,7 @@ int voidCount = 0; for (ExecutableTypeData executableTypeData : genericExecutes) { if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) { - if (ElementUtils.isVoid(executableTypeData.getReturnType().getType())) { + if (ElementUtils.isVoid(executableTypeData.getReturnType())) { voidCount++; } else { genericCount++; @@ -552,16 +602,16 @@ if (voidCount > 1) { List<String> methodSignatures = new ArrayList<>(); for (ExecutableTypeData type : genericExecutes) { - if (type.getType().isVoid()) { - methodSignatures.add(type.createReferenceName()); + 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 (!type.getType().isVoid()) { - methodSignatures.add(type.createReferenceName()); + 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); @@ -577,6 +627,35 @@ + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions."); } + int nodeChildDeclarations = 0; + int nodeChildDeclarationsRequired = 0; + List<NodeExecutionData> executions = node.getChildExecutions(); + for (NodeExecutionData execution : executions) { + if (execution.getChild() == null) { + nodeChildDeclarationsRequired = execution.getIndex() + 1; + } else { + nodeChildDeclarations++; + } + } + + List<String> requireNodeChildDeclarations = new ArrayList<>(); + for (ExecutableTypeData type : allExecutes) { + if (type.getEvaluatedCount() < nodeChildDeclarationsRequired) { + requireNodeChildDeclarations.add(ElementUtils.createReferenceName(type.getMethod())); + } + } + + if (!requireNodeChildDeclarations.isEmpty()) { + node.addError("Not enough child node declarations found. Please annotate the node class with addtional @NodeChild annotations or remove all execute methods that do not provide all evaluated values. " + + "The following execute methods do not provide all evaluated values for the expected signature size %s: %s.", executions.size(), requireNodeChildDeclarations); + } + + if (nodeChildDeclarations > 0 && executions.size() == node.getMinimalEvaluatedParameters()) { + for (NodeChildData child : node.getChildren()) { + child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods."); + } + } + } private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) { @@ -608,10 +687,6 @@ child.setNode(fieldNodeData); if (fieldNodeData == null || fieldNodeData.hasErrors()) { child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType)); - } else if (!ElementUtils.typeEquals(fieldNodeData.getTypeSystem().getTemplateType().asType(), (node.getTypeSystem().getTemplateType().asType()))) { - child.addError("The @%s of the node and the @%s of the @%s does not match. %s != %s. ", TypeSystem.class.getSimpleName(), TypeSystem.class.getSimpleName(), - NodeChild.class.getSimpleName(), ElementUtils.getSimpleName(node.getTypeSystem().getTemplateType()), - ElementUtils.getSimpleName(fieldNodeData.getTypeSystem().getTemplateType())); } else { List<ExecutableTypeData> types = child.findGenericExecutableTypes(context); if (types.isEmpty()) { @@ -680,7 +755,11 @@ if (node.hasErrors()) { return node; } - node.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, node, child, createAllowedChildFrameTypes(parentNode)).parse(members))); + List<TypeMirror> frameTypes = Collections.emptyList(); + if (parentNode.getFrameType() != null) { + frameTypes = Arrays.asList(parentNode.getFrameType()); + } + node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes))); node.setFrameType(parentNode.getFrameType()); return node; } @@ -1159,13 +1238,13 @@ List<VariableElement> parameterTypes = new ArrayList<>(); int signatureIndex = 1; for (ParameterSpec spec : specification.getRequired()) { - parameterTypes.add(new CodeVariableElement(createGenericType(spec, node.getSpecializations(), signatureIndex), "arg" + signatureIndex)); + parameterTypes.add(new CodeVariableElement(createGenericType(node, spec), "arg" + signatureIndex)); if (spec.isSignature()) { signatureIndex++; } } - TypeMirror returnType = createGenericType(specification.getReturnType(), node.getSpecializations(), 0); + TypeMirror returnType = createGenericType(node, specification.getReturnType()); SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes); if (generic == null) { throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + "."); @@ -1174,41 +1253,22 @@ return generic; } - private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) { + private TypeMirror createGenericType(NodeData node, ParameterSpec spec) { NodeExecutionData execution = spec.getExecution(); + Collection<TypeMirror> allowedTypes; if (execution == null) { - if (spec.getAllowedTypes().size() == 1) { - return spec.getAllowedTypes().get(0); - } else { - return ElementUtils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); - } + allowedTypes = spec.getAllowedTypes(); } else { - Set<TypeData> types = new HashSet<>(); - for (SpecializationData specialization : specializations) { - types.add(specialization.getTypeSignature().get(signatureIndex)); - } - - NodeChildData child = execution.getChild(); - TypeData genericType = null; - if (types.size() == 1) { - TypeData singleType = types.iterator().next(); - ExecutableTypeData executable = child.findExecutableType(singleType); - if (executable != null && (signatureIndex == 0 || !executable.hasUnexpectedValue(context))) { - genericType = singleType; - } - } - if (genericType == null) { - ExecutableTypeData type = child.findAnyGenericExecutableType(context); - if (type == null) { - throw new AssertionError("No generic type not yet catched by parser."); - } - genericType = type.getType(); - } - return genericType.getPrimitiveType(); + allowedTypes = node.getPossibleTypes(execution); + } + if (allowedTypes.size() == 1) { + return allowedTypes.iterator().next(); + } else { + return ElementUtils.getCommonSuperType(context, allowedTypes.toArray(new TypeMirror[allowedTypes.size()])); } } - private static void initializeUninitialized(final NodeData node) { + private void initializeUninitialized(final NodeData node) { SpecializationData generic = node.getGenericSpecialization(); if (generic == null) { return; @@ -1225,7 +1285,7 @@ } } if (types.size() > 1) { - generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, node.getTypeSystem().getGenericTypeData())); + generic.replaceParameter(parameter.getLocalName(), new Parameter(parameter, context.getType(Object.class))); } } TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters()); @@ -1241,14 +1301,14 @@ SpecializationData generic = node.getGenericSpecialization(); - List<TypeData> polymorphicSignature = new ArrayList<>(); + List<TypeMirror> polymorphicSignature = new ArrayList<>(); List<Parameter> updatePolymorphic = Arrays.asList(); for (Parameter genericParameter : updatePolymorphic) { if (!genericParameter.getSpecification().isSignature()) { continue; } - Set<TypeData> usedTypes = new HashSet<>(); + Set<TypeMirror> usedTypes = new HashSet<>(); for (SpecializationData specialization : node.getSpecializations()) { if (!specialization.isSpecialized()) { continue; @@ -1257,14 +1317,14 @@ if (parameter == null) { throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName()); } - usedTypes.add(parameter.getTypeSystemType()); + usedTypes.add(parameter.getType()); } - TypeData polymorphicType; + TypeMirror polymorphicType; if (usedTypes.size() == 1) { polymorphicType = usedTypes.iterator().next(); } else { - polymorphicType = node.getTypeSystem().getGenericTypeData(); + polymorphicType = context.getType(Object.class); } polymorphicSignature.add(polymorphicType); } @@ -1370,7 +1430,7 @@ ExecutableTypeData found = null; List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context); for (ExecutableTypeData executable : executableElements) { - if (executable.getType().equalsType(parameter.getTypeSystemType())) { + if (ElementUtils.typeEquals(executable.getReturnType(), parameter.getType())) { found = executable; break; } @@ -1429,8 +1489,8 @@ List<Element> elements = new ArrayList<>(originalElements); Set<Element> unusedElements = new HashSet<>(elements); - for (TemplateMethod method : nodeData.getAllTemplateMethods()) { - unusedElements.remove(method.getMethod()); + for (ExecutableElement method : nodeData.getAllTemplateMethods()) { + unusedElements.remove(method); } for (NodeFieldData field : nodeData.getFields()) {