use of com.oracle.truffle.dsl.processor.model.NodeExecutionData in project graal by oracle.
the class NodeParser method parseExecutions.
private List<NodeExecutionData> parseExecutions(List<NodeFieldData> fields, List<NodeChildData> children, List<? extends Element> elements) {
List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
boolean hasVarArgs = false;
int maxSignatureSize = 0;
if (!children.isEmpty()) {
int lastIndex = children.size() - 1;
hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY;
if (hasVarArgs) {
maxSignatureSize = lastIndex;
} else {
maxSignatureSize = children.size();
}
}
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
for (ExecutableElement method : methods) {
AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class);
if (mirror == null) {
continue;
}
int currentArgumentIndex = 0;
parameter: for (VariableElement var : method.getParameters()) {
TypeMirror type = var.asType();
if (currentArgumentIndex == 0) {
// skip optionals
for (TypeMirror frameType : frameTypes) {
if (ElementUtils.typeEquals(type, frameType)) {
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 parameter;
}
currentArgumentIndex++;
}
maxSignatureSize = Math.max(maxSignatureSize, currentArgumentIndex);
}
List<NodeExecutionData> executions = new ArrayList<>();
for (int i = 0; i < maxSignatureSize; i++) {
boolean varArgParameter = false;
int childIndex = i;
if (i >= children.size() - 1) {
if (hasVarArgs) {
varArgParameter = hasVarArgs;
childIndex = Math.min(i, children.size() - 1);
} else if (i >= children.size()) {
childIndex = -1;
}
}
int varArgsIndex = -1;
NodeChildData child = null;
if (childIndex != -1) {
varArgsIndex = varArgParameter ? Math.abs(childIndex - i) : -1;
child = children.get(childIndex);
}
executions.add(new NodeExecutionData(child, i, varArgsIndex));
}
return executions;
}
use of com.oracle.truffle.dsl.processor.model.NodeExecutionData in project graal by oracle.
the class NodeParser method initializeChildren.
@SuppressWarnings("unchecked")
private void initializeChildren(NodeData node) {
for (NodeChildData child : node.getChildren()) {
AnnotationValue executeWithValue1 = child.getExecuteWithValue();
List<AnnotationValue> executeWithValues = ElementUtils.resolveAnnotationValue(List.class, executeWithValue1);
List<NodeExecutionData> executeWith = new ArrayList<>();
for (AnnotationValue executeWithValue : executeWithValues) {
String executeWithString = ElementUtils.resolveAnnotationValue(String.class, executeWithValue);
if (child.getName().equals(executeWithString)) {
child.addError(executeWithValue1, "The child node '%s' cannot be executed with itself.", executeWithString);
continue;
}
NodeExecutionData found = null;
boolean before = true;
for (NodeExecutionData resolveChild : node.getChildExecutions()) {
if (resolveChild.getChild() == child) {
before = false;
continue;
}
if (resolveChild.getIndexedName().equals(executeWithString)) {
found = resolveChild;
break;
}
}
if (found == null) {
child.addError(executeWithValue1, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
continue;
} else if (!before) {
child.addError(executeWithValue1, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString, executeWithString);
continue;
}
executeWith.add(found);
}
child.setExecuteWith(executeWith);
}
for (NodeChildData child : node.getChildren()) {
TypeMirror nodeType = child.getNodeType();
NodeData fieldNodeData = parseChildNodeData(node, child, ElementUtils.fromTypeMirror(nodeType));
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 {
List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
if (types.isEmpty()) {
AnnotationValue executeWithValue = child.getExecuteWithValue();
child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s and frame types %s.", child.getExecuteWith().size(), ElementUtils.getSimpleName(nodeType), ElementUtils.getUniqueIdentifiers(createAllowedChildFrameTypes(node)));
}
}
}
}
use of com.oracle.truffle.dsl.processor.model.NodeExecutionData in project graal by oracle.
the class NodeParser method initializePolymorphism.
private void initializePolymorphism(NodeData node) {
if (!node.needsRewrites(context)) {
return;
}
SpecializationData generic = node.getGenericSpecialization();
List<VariableElement> types = new ArrayList<>();
Collection<TypeMirror> frameTypes = new HashSet<>();
for (SpecializationData specialization : node.getSpecializations()) {
if (specialization.getFrame() != null) {
frameTypes.add(specialization.getFrame().getType());
}
}
if (node.supportsFrame()) {
frameTypes.add(node.getFrameType());
}
if (!frameTypes.isEmpty()) {
frameTypes = ElementUtils.uniqueSortedTypes(frameTypes, false);
TypeMirror frameType;
if (frameTypes.size() == 1) {
frameType = frameTypes.iterator().next();
} else {
frameType = context.getType(Frame.class);
}
types.add(new CodeVariableElement(frameType, TemplateMethod.FRAME_NAME));
}
TypeMirror returnType = null;
int index = 0;
for (Parameter genericParameter : generic.getReturnTypeAndParameters()) {
TypeMirror polymorphicType;
if (genericParameter.getLocalName().equals(TemplateMethod.FRAME_NAME)) {
continue;
}
boolean isReturnParameter = genericParameter == generic.getReturnType();
if (!genericParameter.getSpecification().isSignature()) {
polymorphicType = genericParameter.getType();
} else {
NodeExecutionData execution = genericParameter.getSpecification().getExecution();
Collection<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());
}
if (isReturnParameter && specialization.hasUnexpectedResultRewrite()) {
if (!ElementUtils.isSubtypeBoxed(context, context.getType(Object.class), node.getGenericType(execution))) {
specialization.addError("Implicit 'Object' return type from UnexpectedResultException not compatible with generic type '%s'.", node.getGenericType(execution));
} else {
// if any specialization throws UnexpectedResultException, Object could
// be returned
usedTypes.add(context.getType(Object.class));
}
}
usedTypes.add(parameter.getType());
}
usedTypes = ElementUtils.uniqueSortedTypes(usedTypes, false);
if (usedTypes.size() == 1) {
polymorphicType = usedTypes.iterator().next();
} else {
polymorphicType = ElementUtils.getCommonSuperType(context, usedTypes);
}
if (execution != null && !ElementUtils.isSubtypeBoxed(context, polymorphicType, node.getGenericType(execution))) {
throw new AssertionError(String.format("Polymorphic types %s not compatible to generic type %s.", polymorphicType, node.getGenericType(execution)));
}
}
if (isReturnParameter) {
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);
if (polymorphic == null) {
throw new AssertionError("Failed to parse polymorphic signature. " + parser.createDefaultMethodSpec(null, null, false, null) + " Types: " + returnType + " - " + types);
}
polymorphic.setKind(SpecializationKind.POLYMORPHIC);
node.getSpecializations().add(polymorphic);
}
use of com.oracle.truffle.dsl.processor.model.NodeExecutionData in project graal by oracle.
the class NodeParser method createGenericType.
private TypeMirror createGenericType(NodeData node, ParameterSpec spec) {
NodeExecutionData execution = spec.getExecution();
Collection<TypeMirror> allowedTypes;
if (execution == null) {
allowedTypes = spec.getAllowedTypes();
} else {
allowedTypes = Arrays.asList(node.getGenericType(execution));
}
if (allowedTypes.size() == 1) {
return allowedTypes.iterator().next();
} else {
return ElementUtils.getCommonSuperType(context, allowedTypes);
}
}
use of com.oracle.truffle.dsl.processor.model.NodeExecutionData in project graal by oracle.
the class NodeParser method initializeExecutableTypes.
private void initializeExecutableTypes(NodeData node) {
List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
Set<String> inconsistentFrameTypes = new HashSet<>();
TypeMirror frameType = null;
for (ExecutableTypeData execute : allExecutes) {
TypeMirror frame = execute.getFrameParameter();
TypeMirror resolvedFrameType;
if (frame != null) {
resolvedFrameType = frame;
if (frameType == null) {
frameType = resolvedFrameType;
} else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
// found inconsistent frame types
inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType));
inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType));
}
}
}
if (!inconsistentFrameTypes.isEmpty()) {
// ensure they are sorted somehow
List<String> inconsistentFrameTypesList = new ArrayList<>(inconsistentFrameTypes);
Collections.sort(inconsistentFrameTypesList);
node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList);
}
if (frameType == null) {
frameType = context.getType(void.class);
}
node.setFrameType(frameType);
boolean genericFound = false;
for (ExecutableTypeData type : node.getExecutableTypes()) {
if (!type.hasUnexpectedValue(context)) {
genericFound = true;
break;
}
}
// no generic executes
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.");
}
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.");
}
}
}
Aggregations