use of com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror in project graal by oracle.
the class NodeParser method parseChildren.
private List<NodeChildData> parseChildren(NodeData node, final List<TypeElement> typeHierarchy, List<? extends Element> elements) {
Map<String, TypeMirror> castNodeTypes = new HashMap<>();
for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
AnnotationMirror mirror = findAnnotationMirror(method, types.CreateCast);
if (mirror != null) {
List<String> children = (getAnnotationValueList(String.class, mirror, "value"));
if (children != null) {
for (String child : children) {
castNodeTypes.put(child, method.getReturnType());
}
}
}
}
List<NodeChildData> executedFieldChildren = new ArrayList<>();
for (VariableElement field : ElementFilter.fieldsIn(elements)) {
if (field.getModifiers().contains(Modifier.STATIC)) {
continue;
}
AnnotationMirror executed = findAnnotationMirror(field.getAnnotationMirrors(), types.Executed);
if (executed != null) {
TypeMirror type = field.asType();
String name = field.getSimpleName().toString();
Cardinality cardinality = Cardinality.ONE;
if (type.getKind() == TypeKind.ARRAY) {
cardinality = Cardinality.MANY;
}
AnnotationValue executedWith = getAnnotationValue(executed, "with");
NodeChildData child = new NodeChildData(field, executed, name, type, type, field, cardinality, executedWith, null, null);
executedFieldChildren.add(child);
if (field.getModifiers().contains(Modifier.PRIVATE)) {
child.addError("Field annotated with @%s must be visible for the generated subclass to execute.", types.Executed.asElement().getSimpleName().toString());
}
if (cardinality == Cardinality.ONE) {
if (ElementUtils.findAnnotationMirror(field, types.Node_Child) == null) {
child.addError("Field annotated with @%s must also be annotated with @%s.", types.Executed.asElement().getSimpleName().toString(), types.Node_Child.asElement().getSimpleName().toString());
}
} else {
assert cardinality == Cardinality.MANY;
if (ElementUtils.findAnnotationMirror(field, types.Node_Children) == null) {
child.addError("Field annotated with @%s must also be annotated with @%s.", types.Executed.asElement().getSimpleName().toString(), types.Node_Children.asElement().getSimpleName().toString());
}
}
}
}
NodeChildData many = null;
Set<String> names = new HashSet<>();
for (NodeChildData child : executedFieldChildren) {
if (child.needsGeneratedField()) {
throw new AssertionError("Should not need generated field.");
}
if (names.contains(child.getName())) {
child.addError("Field annotated with @%s has duplicate name '%s'. " + "Executed children must have unique names.", types.Executed.asElement().getSimpleName().toString(), child.getName());
} else if (many != null) {
child.addError("Field annotated with @%s is hidden by executed field '%s'. " + "Executed child fields with multiple children hide all following executed child declarations. " + "Reorder or remove this executed child declaration.", types.Executed.asElement().getSimpleName().toString(), many.getName());
} else if (child.getCardinality().isMany()) {
many = child;
}
names.add(child.getName());
}
List<NodeChildData> nodeChildren = new ArrayList<>();
List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
Collections.reverse(typeHierarchyReversed);
for (TypeElement type : typeHierarchyReversed) {
AnnotationMirror nodeChildrenMirror = findAnnotationMirror(type, types.NodeChildren);
TypeMirror nodeClassType = type.getSuperclass();
if (nodeClassType.getKind() == TypeKind.NONE || !isAssignable(nodeClassType, types.Node)) {
nodeClassType = null;
}
List<AnnotationMirror> children = collectAnnotations(nodeChildrenMirror, "value", type, types.NodeChild);
int index = 0;
for (AnnotationMirror childMirror : children) {
String name = getAnnotationValue(String.class, childMirror, "value");
if (name.equals("")) {
name = "child" + index;
}
Cardinality cardinality = Cardinality.ONE;
TypeMirror childNodeType = inheritType(childMirror, "type", nodeClassType);
if (childNodeType.getKind() == TypeKind.ARRAY) {
cardinality = Cardinality.MANY;
}
TypeMirror originalChildType = childNodeType;
TypeMirror castNodeType = castNodeTypes.get(name);
if (castNodeType != null) {
childNodeType = castNodeType;
}
Element getter = findGetter(elements, name, childNodeType);
AnnotationValue executeWith = getAnnotationValue(childMirror, "executeWith");
String create = null;
boolean implicit = (boolean) unboxAnnotationValue(getAnnotationValue(childMirror, "implicit"));
boolean implicitCreateSpecified = getAnnotationValue(childMirror, "implicitCreate", false) != null;
if (implicit || implicitCreateSpecified) {
create = (String) unboxAnnotationValue(getAnnotationValue(childMirror, "implicitCreate"));
}
String uncached = null;
boolean allowUncached = (boolean) unboxAnnotationValue(getAnnotationValue(childMirror, "allowUncached"));
boolean uncachedSpecified = getAnnotationValue(childMirror, "uncached", false) != null;
if (allowUncached || uncachedSpecified) {
uncached = (String) unboxAnnotationValue(getAnnotationValue(childMirror, "uncached"));
}
NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childNodeType, originalChildType, getter, cardinality, executeWith, create, uncached);
if (implicitCreateSpecified && implicit) {
nodeChild.addError("The attributes 'implicit' and 'implicitCreate' are mutually exclusive. Remove one of the attributes to resolve this.");
}
if (uncachedSpecified && allowUncached) {
nodeChild.addError("The attributes 'allowUncached' and 'uncached' are mutually exclusive. Remove one of the attributes to resolve this.");
}
nodeChildren.add(nodeChild);
if (nodeChild.getNodeType() == null) {
nodeChild.addError("No valid node type could be resolved.");
}
if (nodeChild.hasErrors()) {
continue;
}
index++;
}
}
if (!nodeChildren.isEmpty() && !executedFieldChildren.isEmpty()) {
node.addError("The use of @%s and @%s at the same time is not supported.", types.NodeChild.asElement().getSimpleName().toString(), types.Executed.asElement().getSimpleName().toString());
return executedFieldChildren;
} else if (!executedFieldChildren.isEmpty()) {
return executedFieldChildren;
} else {
List<NodeChildData> filteredChildren = new ArrayList<>();
Set<String> encounteredNames = new HashSet<>();
for (int i = nodeChildren.size() - 1; i >= 0; i--) {
NodeChildData child = nodeChildren.get(i);
if (!encounteredNames.contains(child.getName())) {
filteredChildren.add(0, child);
encounteredNames.add(child.getName());
}
}
return filteredChildren;
}
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror in project graal by oracle.
the class NodeParser method initializeAOT.
private void initializeAOT(NodeData node) {
if (!node.isGenerateAOT()) {
return;
}
// apply exclude rules
for (SpecializationData specialization : node.getSpecializations()) {
if (!specialization.isReachable() || specialization.getMethod() == null) {
continue;
}
AnnotationMirror mirror = ElementUtils.findAnnotationMirror(specialization.getMethod(), types.GenerateAOT_Exclude);
if (mirror != null) {
// explicitly excluded
continue;
}
specialization.setPrepareForAOT(true);
}
// exclude uncached specializations
for (SpecializationData specialization : node.getSpecializations()) {
if (specialization.getUncachedSpecialization() != null) {
specialization.getUncachedSpecialization().setPrepareForAOT(false);
}
}
// second pass to remove replaced specializations
outer: for (SpecializationData specialization : node.getSpecializations()) {
if (!specialization.isPrepareForAOT()) {
continue;
}
// not reachable during AOT
for (SpecializationData otherSpecialization : node.getSpecializations()) {
if (otherSpecialization.getReplaces().contains(specialization) && otherSpecialization.isPrepareForAOT()) {
specialization.setPrepareForAOT(false);
continue outer;
}
}
}
// third pass validate included specializations
outer: for (SpecializationData specialization : node.getSpecializations()) {
if (!specialization.isPrepareForAOT()) {
continue;
}
for (CacheExpression cache : specialization.getCaches()) {
if (ElementUtils.typeEquals(cache.getParameter().getType(), node.getTemplateType().asType())) {
if (specialization.getGuards().isEmpty()) {
if (cache.usesDefaultCachedInitializer()) {
// guaranteed recursion
cache.addError(//
"Failed to generate code for @%s: " + //
"Recursive AOT preparation detected. Recursive AOT preparation is not supported as this would lead to infinite compiled code." + //
"Resolve this problem by either: %n" + //
" - Exclude this specialization from AOT with @%s.%s if it is acceptable to deoptimize for this specialization in AOT compiled code. %n" + //
" - Configure the specialization to be replaced with a more generic specialization. %n" + //
" - Add a specialization guard that guarantees that the recursion is finite. %n" + //
" - Remove the cached parameter value. %n", getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude));
continue;
}
}
}
if (cache.isMergedLibrary()) {
cache.addError(//
"Merged libraries are not supported in combination with AOT preparation. " + //
"Resolve this problem by either: %n" + //
" - Setting @%s(..., useForAOT=false) to disable AOT preparation for this export. %n" + //
" - Using a dispatched library without receiver expression. %n" + " - Adding the @%s.%s annotation to the specialization or exported method.", getSimpleName(types.ExportLibrary), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude));
continue;
}
TypeMirror type = cache.getParameter().getType();
if (NodeCodeGenerator.isSpecializedNode(type)) {
List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), ElementUtils.castTypeElement(type));
AnnotationMirror generateAOT = findFirstAnnotation(lookupTypes, types.GenerateAOT);
if (generateAOT == null) {
cache.addError(//
"Failed to generate code for @%s: " + //
"Referenced node type cannot be initialized for AOT." + //
"Resolve this problem by either: %n" + //
" - Exclude this specialization from AOT with @%s.%s if it is acceptable to deoptimize for this specialization in AOT compiled code. %n" + //
" - Configure the specialization to be replaced with a more generic specialization. %n" + //
" - Remove the cached parameter value. %n" + " - Add the @%s annotation to node type '%s' or one of its super types.", getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude), getSimpleName(types.GenerateAOT), getSimpleName(type));
continue;
}
}
boolean cachedLibraryAOT = false;
if (cache.isCachedLibrary()) {
cachedLibraryAOT = ElementUtils.findAnnotationMirror(ElementUtils.fromTypeMirror(cache.getParameter().getType()), types.GenerateAOT) != null;
}
if (cache.isCachedLibrary() && cache.getCachedLibraryLimit() != null && !cache.getCachedLibraryLimit().equals("")) {
if (!cachedLibraryAOT) {
cache.addError(//
"Failed to generate code for @%s: " + //
"@%s with automatic dispatch cannot be prepared for AOT." + //
"Resolve this problem by either: %n" + //
" - Exclude this specialization from AOT with @%s.%s if it is acceptable to deoptimize for this specialization in AOT compiled code. %n" + //
" - Configure the specialization to be replaced with a more generic specialization. %n" + //
" - Remove the cached parameter value. %n" + //
" - Define a cached library initializer expression for manual dispatch. %n" + " - Add the @%s annotation to the %s library class to enable AOT for the library.", getSimpleName(types.GenerateAOT), getSimpleName(types.CachedLibrary), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude), getSimpleName(types.GenerateAOT), getSimpleName(type));
continue;
}
}
if (!cache.isCachedContext() && !cache.isCachedLanguage() && specialization.isDynamicParameterBound(cache.getDefaultExpression(), true)) {
/*
* We explicitly support cached language references and lookups thereof in AOT.
* But the generated code introduces a check to ensure that only the language of
* the root node is used.
*/
if (specialization.isOnlyLanguageReferencesBound(cache.getDefaultExpression())) {
continue;
}
if (!cachedLibraryAOT) {
cache.addError(//
"Failed to generate code for @%s: " + //
"Cached values in specializations included for AOT must not bind dynamic values. " + //
"Such caches are only allowed to bind static values, values read from the node or values from the current language instance using a language reference. " + //
"Resolve this problem by either: %n" + //
" - Exclude this specialization from AOT with @%s.%s if it is acceptable to deoptimize for this specialization in AOT compiled code. %n" + //
" - Configure the specialization to be replaced with a more generic specialization. %n" + //
" - Remove the cached parameter value. %n" + //
" - Avoid binding dynamic parameters in the cache initializer expression. %n" + " - If a cached library is used add the @%s annotation to the library class to enable AOT for the library.", getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude), getSimpleName(types.GenerateAOT));
continue outer;
}
}
}
}
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror in project graal by oracle.
the class NodeParser method initializeCaches.
private SpecializationData initializeCaches(SpecializationData specialization, DSLExpressionResolver resolver) {
List<CacheExpression> caches = new ArrayList<>();
List<CacheExpression> cachedLibraries = new ArrayList<>();
Parameter[] parameters = specialization.getParameters().toArray(new Parameter[0]);
parameters: for (Parameter parameter : parameters) {
if (!parameter.getSpecification().isCached()) {
continue;
}
AnnotationMirror foundCached = null;
for (TypeMirror cachedAnnotation : cachedAnnotations) {
AnnotationMirror found = ElementUtils.findAnnotationMirror(parameter.getVariableElement().getAnnotationMirrors(), cachedAnnotation);
if (found == null) {
continue;
}
if (foundCached == null) {
foundCached = found;
} else {
StringBuilder b = new StringBuilder();
String sep = "";
for (TypeMirror stringCachedAnnotation : cachedAnnotations) {
b.append(sep);
b.append("@");
b.append(ElementUtils.getSimpleName(stringCachedAnnotation));
sep = ", ";
}
specialization.addError(parameter.getVariableElement(), "The following annotations are mutually exclusive for a parameter: %s.", b.toString());
continue parameters;
}
}
if (foundCached == null) {
continue;
}
CacheExpression cache = new CacheExpression(parameter, foundCached);
caches.add(cache);
if (cache.isCached()) {
boolean weakReference = getAnnotationValue(Boolean.class, foundCached, "weak");
if (weakReference) {
if (ElementUtils.isPrimitive(cache.getParameter().getType())) {
cache.addError("Cached parameters with primitive types cannot be weak. Set weak to false to resolve this.");
}
parseCached(cache, specialization, resolver, parameter);
if (cache.hasErrors()) {
continue;
}
DSLExpression sourceExpression = cache.getDefaultExpression();
String weakName = "weak" + ElementUtils.firstLetterUpperCase(parameter.getLocalName()) + "Gen_";
TypeMirror weakType = new CodeTypeMirror.DeclaredCodeTypeMirror(context.getTypeElement(types.TruffleWeakReference), Arrays.asList(cache.getParameter().getType()));
CodeVariableElement weakVariable = new CodeVariableElement(weakType, weakName);
weakVariable.setEnclosingElement(specialization.getMethod());
Parameter weakParameter = new Parameter(parameter, weakVariable);
DSLExpression newWeakReference = new DSLExpression.Call(null, "new", Arrays.asList(sourceExpression));
newWeakReference.setResolvedTargetType(weakType);
resolveCachedExpression(resolver, cache, weakType, newWeakReference, null);
CacheExpression weakCache = new CacheExpression(weakParameter, foundCached);
weakCache.setDefaultExpression(newWeakReference);
weakCache.setUncachedExpression(newWeakReference);
weakCache.setWeakReference(true);
caches.add(0, weakCache);
DSLExpressionResolver weakResolver = resolver.copy(Arrays.asList());
weakResolver.addVariable(weakName, weakVariable);
specialization.addParameter(specialization.getParameters().size(), weakParameter);
DSLExpression parsedDefaultExpression = parseCachedExpression(weakResolver, cache, parameter.getType(), weakName + ".get()");
cache.setDefaultExpression(parsedDefaultExpression);
cache.setUncachedExpression(sourceExpression);
cache.setAlwaysInitialized(true);
cache.setWeakReferenceGet(true);
} else {
parseCached(cache, specialization, resolver, parameter);
}
} else if (cache.isCachedLibrary()) {
String expression = cache.getCachedLibraryExpression();
String limit = cache.getCachedLibraryLimit();
if (expression == null) {
// its cached dispatch version treat it as normal cached
if (limit == null) {
cache.addError("A specialized value expression or limit must be specified for @%s. " + "Use @%s(\"value\") for a specialized or " + "@%s(limit=\"\") for a dispatched library. " + "See the javadoc of @%s for further details.", types.CachedLibrary.asElement().getSimpleName().toString(), types.CachedLibrary.asElement().getSimpleName().toString(), types.CachedLibrary.asElement().getSimpleName().toString(), types.CachedLibrary.asElement().getSimpleName().toString());
continue;
}
DSLExpression limitExpression = parseCachedExpression(resolver, cache, context.getType(int.class), limit);
if (limitExpression == null) {
continue;
}
TypeMirror libraryType = types.Library;
DSLExpressionResolver cachedResolver = importStatics(resolver, types.LibraryFactory);
TypeMirror usedLibraryType = parameter.getType();
DSLExpression resolveCall = new DSLExpression.Call(null, "resolve", Arrays.asList(new DSLExpression.ClassLiteral(usedLibraryType)));
DSLExpression defaultExpression = new DSLExpression.Call(resolveCall, "createDispatched", Arrays.asList(limitExpression));
DSLExpression uncachedExpression = new DSLExpression.Call(resolveCall, "getUncached", Arrays.asList());
cache.setDefaultExpression(resolveCachedExpression(cachedResolver, cache, libraryType, defaultExpression, null));
cache.setUncachedExpression(resolveCachedExpression(cachedResolver, cache, libraryType, uncachedExpression, null));
} else {
if (limit != null) {
cache.addError("The limit and specialized value expression cannot be specified at the same time. They are mutually exclusive.");
continue parameters;
}
cachedLibraries.add(cache);
}
} else if (cache.isCachedLanguage()) {
TypeMirror languageType = cache.getParameter().getType();
boolean isLanguage = ElementUtils.isAssignable(languageType, types.TruffleLanguage);
boolean isLanguageReference = ElementUtils.isAssignable(languageType, types.TruffleLanguage_LanguageReference);
if (!isLanguage && !isLanguageReference) {
cache.addError("Invalid @%s specification. The parameter type must be a subtype of %s or of type LanguageReference<%s>.", types.CachedLanguage.asElement().getSimpleName().toString(), types.TruffleLanguage.asElement().getSimpleName().toString(), types.TruffleLanguage.asElement().getSimpleName().toString());
continue parameters;
}
TypeMirror referenceType;
if (isLanguageReference) {
TypeMirror typeArgument = getFirstTypeArgument(languageType);
if (typeArgument == null || !ElementUtils.isAssignable(typeArgument, types.TruffleLanguage)) {
cache.addError("Invalid @%s specification. The first type argument of the LanguageReference must be a subtype of '%s'.", types.CachedLanguage.asElement().getSimpleName().toString(), types.TruffleLanguage.asElement().getSimpleName().toString());
} else {
verifyLanguageType(types.CachedLanguage, cache, typeArgument);
}
referenceType = languageType;
languageType = typeArgument;
} else {
verifyLanguageType(types.CachedLanguage, cache, languageType);
referenceType = new CodeTypeMirror.DeclaredCodeTypeMirror(context.getTypeElement(types.TruffleLanguage_LanguageReference), Arrays.asList(languageType));
}
if (cache.hasErrors()) {
continue parameters;
}
DSLExpressionResolver cachedResolver = importStatics(resolver, types.TruffleLanguage_LanguageReference);
DSLExpression.Variable thisReceiver = new DSLExpression.Variable(null, "this");
cachedResolver.addVariable("this", new CodeVariableElement(types.Node, "this"));
DSLExpression expression = new DSLExpression.Call(null, "create", Arrays.asList(new DSLExpression.ClassLiteral(languageType)));
if (isLanguage) {
expression = new DSLExpression.Call(expression, "get", Collections.singletonList(thisReceiver));
}
cache.setReferenceType(referenceType);
cache.setLanguageType(languageType);
cache.setDefaultExpression(resolveCachedExpression(cachedResolver, cache, null, expression, null));
cache.setUncachedExpression(resolveCachedExpression(cachedResolver, cache, null, expression, null));
cache.setAlwaysInitialized(true);
} else if (cache.isCachedContext()) {
AnnotationMirror cachedContext = cache.getMessageAnnotation();
TypeMirror languageType = ElementUtils.getAnnotationValue(TypeMirror.class, cachedContext, "value");
if (!ElementUtils.isAssignable(languageType, languageType)) {
cache.addError("Invalid @%s specification. The value type must be a subtype of %s.", types.CachedContext.asElement().getSimpleName().toString(), types.TruffleLanguage.asElement().getSimpleName().toString());
continue parameters;
}
verifyLanguageType(types.CachedContext, cache, languageType);
if (cache.hasErrors()) {
continue parameters;
}
TypeMirror contextType = findContextTypeFromLanguage(languageType);
if (contextType == null || contextType.getKind() != TypeKind.DECLARED) {
cache.addError("Invalid @%s specification. The context type could not be inferred from super type in language '%s'.", types.CachedContext.asElement().getSimpleName().toString(), ElementUtils.getSimpleName(languageType));
continue parameters;
}
TypeMirror declaredContextType = parameter.getType();
if (ElementUtils.typeEquals(ElementUtils.eraseGenericTypes(parameter.getType()), ElementUtils.eraseGenericTypes(types.TruffleLanguage_ContextReference))) {
declaredContextType = getFirstTypeArgument(parameter.getType());
}
if (!ElementUtils.typeEquals(contextType, declaredContextType)) {
cache.addError("Invalid @%s specification. The parameter type must match the context type '%s' or 'ContextReference<%s>'.", types.CachedContext.asElement().getSimpleName().toString(), ElementUtils.getSimpleName(contextType), ElementUtils.getSimpleName(contextType));
continue parameters;
}
TypeMirror referenceType = new CodeTypeMirror.DeclaredCodeTypeMirror(context.getTypeElement(types.TruffleLanguage_ContextReference), Arrays.asList(contextType));
cache.setReferenceType(referenceType);
cache.setLanguageType(languageType);
DSLExpressionResolver cachedResolver = importStatics(resolver, types.TruffleLanguage_ContextReference);
DSLExpression.Variable thisReceiver = new DSLExpression.Variable(null, "this");
cachedResolver.addVariable("this", new CodeVariableElement(types.Node, "this"));
DSLExpression expression = new DSLExpression.Call(null, "create", Arrays.asList(new DSLExpression.ClassLiteral(languageType)));
if (!cache.isReference()) {
expression = new DSLExpression.Call(expression, "get", Collections.singletonList(thisReceiver));
}
cache.setDefaultExpression(resolveCachedExpression(cachedResolver, cache, null, expression, null));
cache.setUncachedExpression(resolveCachedExpression(cachedResolver, cache, null, expression, null));
cache.setAlwaysInitialized(true);
} else if (cache.isBind()) {
AnnotationMirror dynamic = cache.getMessageAnnotation();
String expression = ElementUtils.getAnnotationValue(String.class, dynamic, "value", false);
DSLExpression parsedExpression = parseCachedExpression(resolver, cache, parameter.getType(), expression);
cache.setDefaultExpression(parsedExpression);
cache.setUncachedExpression(parsedExpression);
cache.setAlwaysInitialized(true);
}
}
specialization.setCaches(caches);
SpecializationData uncachedSpecialization = null;
if (!cachedLibraries.isEmpty()) {
uncachedSpecialization = parseCachedLibraries(specialization, resolver, cachedLibraries);
}
if (specialization.hasErrors()) {
return null;
}
// verify that cache expressions are bound in the correct order.
for (int i = 0; i < caches.size(); i++) {
CacheExpression currentExpression = caches.get(i);
Set<VariableElement> boundVariables = new HashSet<>();
if (currentExpression.getDefaultExpression() != null) {
boundVariables.addAll(currentExpression.getDefaultExpression().findBoundVariableElements());
}
if (currentExpression.getUncachedExpression() != null) {
boundVariables.addAll(currentExpression.getUncachedExpression().findBoundVariableElements());
}
for (int j = i + 1; j < caches.size(); j++) {
CacheExpression boundExpression = caches.get(j);
if (boundVariables.contains(boundExpression.getParameter().getVariableElement())) {
currentExpression.addError("The initializer expression of parameter '%s' binds uninitialized parameter '%s. Reorder the parameters to resolve the problem.", currentExpression.getParameter().getLocalName(), boundExpression.getParameter().getLocalName());
break;
}
}
}
return uncachedSpecialization;
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror in project graal by oracle.
the class ExportsParser method parse.
@Override
protected ExportsData parse(Element element, List<AnnotationMirror> elementMirrors) {
TypeElement type = (TypeElement) element;
ExportsData model = parseExports(type, elementMirrors);
if (model.hasErrors()) {
return model;
}
// set of types that contribute members
Set<TypeElement> declaringTypes = new HashSet<>();
Set<TypeElement> declaringInTemplateTypes = new HashSet<>();
declaringInTemplateTypes.add(type);
for (ExportsLibrary library : model.getExportedLibraries().values()) {
declaringTypes.addAll(library.getDeclaringTypes());
if (library.isDeclaredInTemplate()) {
declaringInTemplateTypes.addAll(library.getDeclaringTypes());
}
}
Element packageElement = ElementUtils.findPackageElement(type);
for (TypeElement currentType : declaringInTemplateTypes) {
if (ElementUtils.elementEquals(currentType, element)) {
// current type always visible
continue;
}
List<Element> foundInvisibleMembers = new ArrayList<>();
List<? extends Element> superTypeMembers = loadMembers(null, currentType);
for (Element superTypeMember : superTypeMembers) {
List<AnnotationMirror> exportedMessages = getRepeatedAnnotation(superTypeMember.getAnnotationMirrors(), types.ExportMessage);
if (!exportedMessages.isEmpty()) {
if (!ElementUtils.isVisible(packageElement, superTypeMember)) {
foundInvisibleMembers.add(superTypeMember);
} else if (superTypeMember.getKind().isClass()) {
for (Element specializationMember : loadMembers(null, (TypeElement) superTypeMember)) {
if (ElementUtils.findAnnotationMirror(specializationMember, types.Specialization) != null && !ElementUtils.isVisible(packageElement, specializationMember)) {
foundInvisibleMembers.add(specializationMember);
}
}
}
}
}
if (!foundInvisibleMembers.isEmpty()) {
StringBuilder b = new StringBuilder();
for (Element invisibleMember : foundInvisibleMembers) {
b.append(System.lineSeparator()).append(" - ");
b.append(ElementUtils.getReadableReference(element, invisibleMember));
}
model.addError("Found invisible exported elements in super type '%s': %s%nIncrease their visibility to resolve this problem.", ElementUtils.getSimpleName(currentType), b.toString());
}
}
if (model.getExportedLibraries().isEmpty()) {
for (Element member : loadMembers(null, type)) {
List<AnnotationMirror> exportedMessageMirrors = getRepeatedAnnotation(member.getAnnotationMirrors(), types.ExportMessage);
if (!exportedMessageMirrors.isEmpty()) {
model.addError(//
"Class declares @%s annotations but does not export any libraries. " + //
"Exported messages cannot be resoved without exported library. " + "Add @%s(MyLibrary.class) to the class ot resolve this.", getSimpleName(types.ExportMessage), getSimpleName(types.ExportLibrary));
return model;
}
}
}
List<? extends Element> members = loadMembers(declaringInTemplateTypes, type);
/*
* First pass: element creation
*/
Map<String, List<Element>> potentiallyMissedOverrides = new LinkedHashMap<>();
List<ExportMessageData> exportedElements = new ArrayList<>();
for (Element member : members) {
List<AnnotationMirror> exportedMessageMirrors = getRepeatedAnnotation(member.getAnnotationMirrors(), types.ExportMessage);
if (exportedMessageMirrors.isEmpty()) {
boolean isMethod = isMethodElement(member);
boolean isNode = isNodeElement(member);
String name = null;
if (isMethod) {
name = member.getSimpleName().toString();
} else if (isNode) {
name = inferNodeMessageName((TypeElement) member);
}
if (isMethod || isNode) {
Element enclosingType = member.getEnclosingElement();
if (elementEquals(model.getTemplateType(), enclosingType)) {
potentiallyMissedOverrides.computeIfAbsent(name, (n) -> new ArrayList<>()).add(member);
}
}
} else {
for (AnnotationMirror exportMessage : exportedMessageMirrors) {
exportedElements.addAll(parseExportedMessage(model, member, exportMessage));
}
}
}
for (ExportMessageData exportedMessage : exportedElements) {
Element member = exportedMessage.getMessageElement();
String messageName = exportedMessage.getResolvedMessage().getName();
Map<String, ExportMessageData> exportedMessages = exportedMessage.getExportsLibrary().getExportedMessages();
ExportMessageData existing = exportedMessages.get(messageName);
if (existing != null) {
Element existingEnclosingElement = existing.getMessageElement().getEnclosingElement();
Element currentEnclosingElement = exportedMessage.getMessageElement().getEnclosingElement();
if (ElementUtils.elementEquals(existingEnclosingElement, currentEnclosingElement)) {
String error = String.format("Duplicate exported library message %s.", messageName);
model.addError(member, error);
model.addError(existing.getMessageElement(), error);
} else if (ElementUtils.isSubtype(currentEnclosingElement.asType(), existingEnclosingElement.asType())) {
// new message is more concrete
exportedMessages.put(messageName, exportedMessage);
existing.setOverriden(true);
} else {
// keep existing exported message
exportedMessage.setOverriden(true);
}
} else {
exportedMessages.put(messageName, exportedMessage);
}
}
/*
* Generate synthetic exports for export delegation.
*/
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (!exportsLibrary.hasExportDelegation()) {
continue;
}
ExportMessageData accepts = exportsLibrary.getExportedMessages().get("accepts");
if (accepts == null) {
String delegateName = exportsLibrary.getDelegationVariable().getSimpleName().toString();
CodeAnnotationMirror annotation = new CodeAnnotationMirror(types.CachedLibrary);
annotation.setElementValue(ElementUtils.findExecutableElement(types.CachedLibrary, "value"), new CodeAnnotationValue("receiver_." + delegateName));
CodeExecutableElement executable = CodeExecutableElement.clone(ElementUtils.findMethod(types.Library, "accepts"));
executable.changeTypes(exportsLibrary.getReceiverType());
executable.renameArguments("receiver_");
executable.getModifiers().add(Modifier.STATIC);
CodeVariableElement var = new CodeVariableElement(exportsLibrary.getLibrary().getTemplateType().asType(), delegateName);
var.addAnnotationMirror(annotation);
executable.setEnclosingElement(exportsLibrary.getTemplateType());
executable.getParameters().add(var);
LibraryMessage message = null;
for (LibraryMessage libMessage : exportsLibrary.getLibrary().getMethods()) {
if (libMessage.getName().equals("accepts")) {
message = libMessage;
break;
}
}
accepts = new ExportMessageData(exportsLibrary, message, executable, annotation);
exportsLibrary.getExportedMessages().put("accepts", accepts);
exportedElements.add(accepts);
} else {
accepts.addError("Exporting a custom accepts method is currently not supported when export delegation is used in @%s. " + "Remove delegateTo from all exports or remove the accepts export to resolve this.", getSimpleName(types.ExportLibrary));
}
}
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (!exportsLibrary.isDeclaredInTemplate()) {
for (ExportMessageData message : exportsLibrary.getExportedMessages().values()) {
if (elementEquals(message.getMessageElement().getEnclosingElement(), type)) {
message.addError(//
"The @%s declaration is missing for this exported message. " + "Add @%s(%s.class) to the enclosing class %s to resolve this.", getSimpleName(types.ExportLibrary), getSimpleName(types.ExportLibrary), getSimpleName(exportsLibrary.getLibrary().getTemplateType()), getSimpleName(type));
}
}
}
}
// avoid removal of elements if errors occured.
if (model.hasErrors()) {
return model;
}
for (ExportsLibrary exportsLibrary : model.getExportedLibraries().values()) {
if (exportsLibrary.isBuiltinDefaultExport()) {
// we don't print unused warnings for builtin defaults.
continue;
}
if (exportsLibrary.isDeclaredInTemplate()) {
boolean foundDeclared = false;
for (ExportMessageData message : exportsLibrary.getExportedMessages().values()) {
if (message.isDeclared()) {
foundDeclared = true;
break;
}
}
if (!foundDeclared) {
exportsLibrary.addWarning("Exported library %s does not export any messages and therefore has no effect. Remove the export declaration to resolve this.", getSimpleName(exportsLibrary.getLibrary().getTemplateType()));
}
}
}
// avoid removal of elements if errors occured.
if (model.hasErrors()) {
return model;
}
/*
* filter elements that come from exports not relevant for this class. Remove all export
* declarations not relevant for this type.
*/
Predicate<? super ExportsLibrary> filterpredicate = (library -> {
if (library.isDynamicDispatchTarget()) {
// Implicitly export super's library if dynamic dispatched.
return true;
}
return library.isDeclaredInTemplate();
});
Set<ExportsLibrary> declaredExports = model.getExportedLibraries().values().stream().filter(filterpredicate).collect(Collectors.toSet());
model.getExportedLibraries().values().removeIf((e) -> !declaredExports.contains(e));
exportedElements = exportedElements.stream().filter((e) -> declaredExports.contains(e.getExportsLibrary())).collect(Collectors.toList());
/*
* Third pass: initialize and further parsing that need both method and node to be
* available.
*/
for (ExportsLibrary exportsLibrary : declaredExports) {
// recreate cache for every exports library to not confuse exports configuration
Map<String, NodeData> parsedNodeCache = new HashMap<>();
for (ExportMessageData exportedElement : exportsLibrary.getExportedMessages().values()) {
if (exportedElement.isOverriden()) {
// gets confused.
continue;
}
Element member = exportedElement.getMessageElement();
if (isMethodElement(member)) {
initializeExportedMethod(parsedNodeCache, model, exportedElement);
} else if (isNodeElement(member)) {
initializeExportedNode(parsedNodeCache, exportedElement);
} else {
throw new AssertionError("should not be reachable");
}
}
}
TypeMirror receiverClass = null;
for (Entry<String, ExportsLibrary> entry : model.getExportedLibraries().entrySet()) {
ExportsLibrary exportLib = entry.getValue();
if (exportLib.hasErrors()) {
continue;
}
if (receiverClass == null) {
receiverClass = exportLib.getReceiverType();
} else if (!typeEquals(exportLib.getReceiverType(), receiverClass)) {
exportLib.addError("All receiver classes must match for a declared java type. Found '%s' and '%s'.", getSimpleName(receiverClass), getSimpleName(exportLib.getReceiverType()));
continue;
}
Set<LibraryMessage> missingAbstractMessage = new LinkedHashSet<>();
for (LibraryMessage message : exportLib.getLibrary().getMethods()) {
List<Element> elementsWithSameName = potentiallyMissedOverrides.getOrDefault(message.getName(), Collections.emptyList());
if (!elementsWithSameName.isEmpty()) {
for (Element overridingElement : elementsWithSameName) {
if (ElementUtils.findAnnotationMirror(overridingElement, types.ExportMessage_Ignore) == null) {
exportLib.addError(overridingElement, "The method has the same name '%s' as a message in the exported library %s. Did you forget to export it? " + "Use @%s to export the message, @%s to ignore this warning, rename the method or reduce the visibility of the method to private to resolve this warning.", overridingElement.getSimpleName().toString(), getSimpleName(exportLib.getLibrary().getTemplateType()), types.ExportMessage.asElement().getSimpleName().toString(), types.ExportMessage_Ignore.asElement().getSimpleName().toString());
}
}
}
if (message.isAbstract() && !message.getName().equals("accepts")) {
ExportMessageData exportMessage = exportLib.getExportedMessages().get(message.getName());
if (exportMessage == null || exportMessage.getResolvedMessage() != message) {
boolean isAbstract;
if (!message.getAbstractIfExported().isEmpty()) {
isAbstract = false;
for (LibraryMessage abstractIfExported : message.getAbstractIfExported()) {
if (exportLib.getExportedMessages().containsKey(abstractIfExported.getName())) {
isAbstract = true;
break;
}
}
} else {
isAbstract = !exportLib.hasExportDelegation();
}
if (isAbstract) {
missingAbstractMessage.add(message);
}
}
}
}
if (!missingAbstractMessage.isEmpty()) {
StringBuilder msg = new StringBuilder(String.format("The following message(s) of library %s are abstract and must be exported using:%n", getSimpleName(exportLib.getLibrary().getTemplateType())));
for (LibraryMessage message : missingAbstractMessage) {
msg.append(" ").append(generateExpectedSignature(type, message, exportLib.getExplicitReceiver())).append(" {");
if (!ElementUtils.isVoid(message.getExecutable().getReturnType())) {
msg.append(" return ").append(ElementUtils.defaultValue(message.getExecutable().getReturnType()));
msg.append(";");
}
msg.append(" }%n");
}
exportLib.addError(msg.toString());
}
}
for (ExportsLibrary libraryExports : model.getExportedLibraries().values()) {
List<NodeData> cachedSharedNodes = new ArrayList<>();
List<ExportMessageData> exportedMessages = new ArrayList<>();
for (ExportMessageData export : libraryExports.getExportedMessages().values()) {
if (export.getSpecializedNode() != null) {
cachedSharedNodes.add(export.getSpecializedNode());
exportedMessages.add(export);
}
}
libraryExports.setSharedExpressions(NodeParser.computeSharing(libraryExports.getTemplateType(), cachedSharedNodes, true));
// JDT will otherwise just ignore those messages and not display anything.
for (int i = 0; i < cachedSharedNodes.size(); i++) {
NodeData nodeData = cachedSharedNodes.get(i);
ExportMessageData exportedMessage = exportedMessages.get(i);
if (nodeData.hasErrorsOrWarnings()) {
nodeData.redirectMessagesOnGeneratedElements(exportedMessage);
}
nodeData.setGenerateUncached(false);
}
}
for (ExportMessageData message : exportedElements) {
if (!elementEquals(message.getMessageElement().getEnclosingElement(), model.getTemplateType())) {
message.redirectMessages(message.getExportsLibrary());
}
}
if (isGenerateSlowPathOnly(type)) {
for (ExportsLibrary libraryExports : model.getExportedLibraries().values()) {
for (ExportMessageData export : libraryExports.getExportedMessages().values()) {
if (export.isClass() && export.getSpecializedNode() != null) {
NodeParser.removeFastPathSpecializations(export.getSpecializedNode());
}
}
}
}
return model;
}
use of com.oracle.truffle.dsl.processor.java.ElementUtils.findAnnotationMirror in project graal by oracle.
the class FlatNodeGenFactory method create.
public CodeTypeElement create(CodeTypeElement clazz) {
if (primaryNode) {
for (NodeChildData child : node.getChildren()) {
clazz.addOptional(createAccessChildMethod(child, false));
}
for (NodeFieldData field : node.getFields()) {
if (!field.isGenerated()) {
continue;
}
Set<Modifier> fieldModifiers;
if (field.isSettable()) {
fieldModifiers = modifiers(PRIVATE);
} else {
fieldModifiers = modifiers(PRIVATE, FINAL);
}
clazz.add(new CodeVariableElement(fieldModifiers, field.getType(), field.getName()));
if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) {
CodeExecutableElement method = CodeExecutableElement.clone(field.getGetter());
method.getModifiers().remove(Modifier.ABSTRACT);
method.createBuilder().startReturn().string("this.").string(field.getName()).end();
clazz.add(method);
}
if (field.isSettable()) {
CodeExecutableElement method = CodeExecutableElement.clone(field.getSetter());
method.renameArguments(field.getName());
method.getModifiers().remove(Modifier.ABSTRACT);
method.createBuilder().startStatement().string("this.").string(field.getName()).string(" = ", field.getName()).end();
clazz.add(method);
}
}
for (ExecutableElement superConstructor : GeneratorUtils.findUserConstructors(node.getTemplateType().asType())) {
clazz.add(createNodeConstructor(clazz, superConstructor));
}
for (NodeExecutionData execution : node.getChildExecutions()) {
if (execution.getChild() != null && execution.getChild().needsGeneratedField()) {
clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), types.Node_Child));
}
}
}
createFields(clazz);
TypeMirror genericReturnType = node.getPolymorphicExecutable().getReturnType();
List<ExecutableTypeData> executableTypes = filterExecutableTypes(node.getExecutableTypes(), reachableSpecializations);
List<ExecutableTypeData> genericExecutableTypes = new ArrayList<>();
List<ExecutableTypeData> specializedExecutableTypes = new ArrayList<>();
List<ExecutableTypeData> voidExecutableTypes = new ArrayList<>();
for (ExecutableTypeData type : executableTypes) {
if (isVoid(type.getReturnType())) {
voidExecutableTypes.add(type);
} else if (type.hasUnexpectedValue() && !typeEquals(genericReturnType, type.getReturnType())) {
specializedExecutableTypes.add(type);
} else {
genericExecutableTypes.add(type);
}
}
if (genericExecutableTypes.size() > 1) {
boolean hasGenericTypeMatch = false;
for (ExecutableTypeData genericExecutable : genericExecutableTypes) {
if (typeEquals(genericExecutable.getReturnType(), genericReturnType)) {
hasGenericTypeMatch = true;
break;
}
}
if (hasGenericTypeMatch) {
for (ListIterator<ExecutableTypeData> iterator = genericExecutableTypes.listIterator(); iterator.hasNext(); ) {
ExecutableTypeData executableTypeData = iterator.next();
if (!isAssignable(genericReturnType, executableTypeData.getReturnType())) {
iterator.remove();
specializedExecutableTypes.add(executableTypeData);
}
}
}
}
SpecializationData fallback = node.getFallbackSpecialization();
if (fallback.getMethod() != null && fallback.isReachable()) {
clazz.add(createFallbackGuard());
}
for (ExecutableTypeData type : genericExecutableTypes) {
wrapWithTraceOnReturn(createExecute(clazz, type, Collections.<ExecutableTypeData>emptyList()));
}
for (ExecutableTypeData type : specializedExecutableTypes) {
wrapWithTraceOnReturn(createExecute(clazz, type, genericExecutableTypes));
}
for (ExecutableTypeData type : voidExecutableTypes) {
List<ExecutableTypeData> genericAndSpecialized = new ArrayList<>();
genericAndSpecialized.addAll(genericExecutableTypes);
genericAndSpecialized.addAll(specializedExecutableTypes);
wrapWithTraceOnReturn(createExecute(clazz, type, genericAndSpecialized));
}
clazz.addOptional(createExecuteAndSpecialize());
final ReportPolymorphismAction reportPolymorphismAction = reportPolymorphismAction(node, reachableSpecializations);
if (reportPolymorphismAction.required()) {
clazz.addOptional(createCheckForPolymorphicSpecialize(reportPolymorphismAction));
if (requiresCacheCheck(reportPolymorphismAction)) {
clazz.addOptional(createCountCaches());
}
}
AnnotationMirror nodeInfo = null;
try {
nodeInfo = ElementUtils.findAnnotationMirror(node.getTemplateType(), types.NodeInfo);
} catch (UnsupportedOperationException e) {
}
String cost = nodeInfo != null ? ElementUtils.getAnnotationValue(VariableElement.class, nodeInfo, "cost").getSimpleName().toString() : null;
if ((cost == null || cost.equals("MONOMORPHIC")) && isUndeclaredOrOverrideable(clazz, "getCost")) {
if (primaryNode) {
clazz.add(createGetCostMethod(false));
}
}
for (TypeMirror type : uniqueSortedTypes(expectedTypes, false)) {
if (!typeSystem.hasType(type)) {
clazz.addOptional(TypeSystemCodeGenerator.createExpectMethod(PRIVATE, typeSystem, context.getType(Object.class), type));
}
}
clazz.getEnclosedElements().addAll(removeThisMethods.values());
for (SpecializationData specialization : specializationClasses.keySet()) {
CodeTypeElement type = specializationClasses.get(specialization);
if (getInsertAccessorSet(true).contains(specialization)) {
type.add(createInsertAccessor(true));
}
if (getInsertAccessorSet(false).contains(specialization)) {
type.add(createInsertAccessor(false));
}
}
if (isGenerateIntrospection()) {
generateIntrospectionInfo(clazz);
}
if (isGenerateAOT()) {
generateAOT(clazz);
}
if (node.isUncachable() && node.isGenerateUncached()) {
CodeTypeElement uncached = GeneratorUtils.createClass(node, null, modifiers(PRIVATE, STATIC, FINAL), "Uncached", node.getTemplateType().asType());
uncached.getEnclosedElements().addAll(createUncachedFields());
for (NodeFieldData field : node.getFields()) {
if (!field.isGenerated()) {
continue;
}
if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) {
CodeExecutableElement method = CodeExecutableElement.clone(field.getGetter());
method.getModifiers().remove(Modifier.ABSTRACT);
method.createBuilder().startThrow().startNew(context.getType(UnsupportedOperationException.class)).end().end();
uncached.add(method);
}
if (field.isSettable()) {
CodeExecutableElement method = CodeExecutableElement.clone(field.getSetter());
method.getModifiers().remove(Modifier.ABSTRACT);
method.createBuilder().startThrow().startNew(context.getType(UnsupportedOperationException.class)).end().end();
uncached.add(method);
}
}
generateStatisticsFields(uncached);
for (NodeChildData child : node.getChildren()) {
uncached.addOptional(createAccessChildMethod(child, true));
}
for (ExecutableTypeData type : genericExecutableTypes) {
wrapWithTraceOnReturn(uncached.add(createUncachedExecute(type)));
}
for (ExecutableTypeData type : specializedExecutableTypes) {
wrapWithTraceOnReturn(uncached.add(createUncachedExecute(type)));
}
for (ExecutableTypeData type : voidExecutableTypes) {
wrapWithTraceOnReturn(uncached.add(createUncachedExecute(type)));
}
if ((cost == null || cost.equals("MONOMORPHIC")) && isUndeclaredOrOverrideable(uncached, "getCost")) {
uncached.add(createGetCostMethod(true));
}
CodeExecutableElement isAdoptable = CodeExecutableElement.cloneNoAnnotations(ElementUtils.findExecutableElement(types.Node, "isAdoptable"));
isAdoptable.createBuilder().returnFalse();
uncached.add(isAdoptable);
clazz.add(uncached);
GeneratedTypeMirror uncachedType = new GeneratedTypeMirror("", uncached.getSimpleName().toString());
CodeVariableElement uncachedField = clazz.add(new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), uncachedType, "UNCACHED"));
uncachedField.createInitBuilder().startNew(uncachedType).end();
}
return clazz;
}
Aggregations