comparison truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @ 21951:9c8c0937da41

Moving all sources into truffle subdirectory
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 17 Jun 2015 10:58:08 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java@fdf55f1ffc59
children dc83cc1f94f2
comparison
equal deleted inserted replaced
21950:2a5011c7e641 21951:9c8c0937da41
1 /*
2 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.oracle.truffle.dsl.processor.parser;
24
25 import java.lang.annotation.*;
26 import java.util.*;
27
28 import javax.lang.model.element.*;
29 import javax.lang.model.type.*;
30 import javax.lang.model.util.*;
31 import javax.tools.Diagnostic.Kind;
32
33 import com.oracle.truffle.api.*;
34 import com.oracle.truffle.api.dsl.*;
35 import com.oracle.truffle.api.dsl.internal.*;
36 import com.oracle.truffle.api.frame.*;
37 import com.oracle.truffle.api.nodes.*;
38 import com.oracle.truffle.dsl.processor.*;
39 import com.oracle.truffle.dsl.processor.expression.*;
40 import com.oracle.truffle.dsl.processor.java.*;
41 import com.oracle.truffle.dsl.processor.java.compiler.*;
42 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
43 import com.oracle.truffle.dsl.processor.java.model.*;
44 import com.oracle.truffle.dsl.processor.model.*;
45 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
46 import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind;
47
48 @DSLOptions
49 public class NodeParser extends AbstractParser<NodeData> {
50
51 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
52 NodeChildren.class);
53
54 @Override
55 protected NodeData parse(Element element, AnnotationMirror mirror) {
56 NodeData node = parseRootType((TypeElement) element);
57 if (Log.isDebug() && node != null) {
58 String dump = node.dump();
59 log.message(Kind.ERROR, null, null, null, dump);
60 }
61 return node;
62 }
63
64 @Override
65 protected NodeData filterErrorElements(NodeData model) {
66 for (Iterator<NodeData> iterator = model.getEnclosingNodes().iterator(); iterator.hasNext();) {
67 NodeData node = filterErrorElements(iterator.next());
68 if (node == null) {
69 iterator.remove();
70 }
71 }
72 if (model.hasErrors()) {
73 return null;
74 }
75 return model;
76 }
77
78 @Override
79 public boolean isDelegateToRootDeclaredType() {
80 return true;
81 }
82
83 @Override
84 public Class<? extends Annotation> getAnnotationType() {
85 return null;
86 }
87
88 @Override
89 public List<Class<? extends Annotation>> getTypeDelegatedAnnotationTypes() {
90 return ANNOTATIONS;
91 }
92
93 private NodeData parseRootType(TypeElement rootType) {
94 List<NodeData> enclosedNodes = new ArrayList<>();
95 for (TypeElement enclosedType : ElementFilter.typesIn(rootType.getEnclosedElements())) {
96 NodeData enclosedChild = parseRootType(enclosedType);
97 if (enclosedChild != null) {
98 enclosedNodes.add(enclosedChild);
99 }
100 }
101 NodeData node;
102 try {
103 node = parseNode(rootType);
104 } catch (CompileErrorException e) {
105 throw e;
106 } catch (Throwable e) {
107 RuntimeException e2 = new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)));
108 e2.addSuppressed(e);
109 throw e2;
110 }
111 if (node == null && !enclosedNodes.isEmpty()) {
112 node = new NodeData(context, rootType);
113 }
114
115 if (node != null) {
116 for (NodeData enclosedNode : enclosedNodes) {
117 node.addEnclosedNode(enclosedNode);
118 }
119 }
120 return node;
121 }
122
123 private NodeData parseNode(TypeElement originalTemplateType) {
124 // reloading the type elements is needed for ecj
125 TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
126
127 if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
128 // generated nodes should not get called again.
129 return null;
130 }
131
132 if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
133 return null;
134 }
135
136 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
137 List<Element> members = loadMembers(templateType);
138 // ensure the processed element has at least one @Specialization annotation.
139 if (!containsSpecializations(members)) {
140 return null;
141 }
142
143 NodeData node = parseNodeData(templateType, lookupTypes);
144 if (node.hasErrors()) {
145 return node;
146 }
147
148 node.getFields().addAll(parseFields(lookupTypes, members));
149 node.getChildren().addAll(parseChildren(lookupTypes, members));
150 node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members));
151 node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, node.getSignatureSize(), context.getFrameTypes(), false));
152
153 initializeExecutableTypes(node);
154 initializeImportGuards(node, lookupTypes, members);
155 initializeChildren(node);
156
157 if (node.hasErrors()) {
158 return node; // error sync point
159 }
160
161 if (node.hasErrors()) {
162 return node; // error sync point
163 }
164
165 node.getSpecializations().addAll(new SpecializationMethodParser(context, node).parse(members));
166 node.getSpecializations().addAll(new FallbackParser(context, node).parse(members));
167 node.getCasts().addAll(new CreateCastParser(context, node).parse(members));
168 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members));
169
170 if (node.hasErrors()) {
171 return node; // error sync point
172 }
173 initializeSpecializations(members, node);
174 initializeExecutableTypeHierarchy(node);
175
176 verifySpecializationSameLength(node);
177 initializeShortCircuits(node); // requires specializations and polymorphic specializations
178
179 verifyVisibilities(node);
180 verifyMissingAbstractMethods(node, members);
181 verifyConstructors(node);
182 verifyNamingConvention(node.getShortCircuits(), "needs");
183 verifySpecializationThrows(node);
184 return node;
185 }
186
187 private static void initializeExecutableTypeHierarchy(NodeData node) {
188 SpecializationData polymorphic = node.getPolymorphicSpecialization();
189 if (polymorphic != null) {
190 boolean polymorphicSignatureFound = false;
191 List<TypeMirror> dynamicTypes = polymorphic.getDynamicTypes();
192 TypeMirror frame = null;
193 if (polymorphic.getFrame() != null) {
194 frame = dynamicTypes.remove(0);
195 }
196
197 ExecutableTypeData polymorphicType = new ExecutableTypeData(node, polymorphic.getReturnType().getType(), "execute", frame, dynamicTypes);
198 String genericName = ExecutableTypeData.createName(polymorphicType) + "_";
199 polymorphicType.setUniqueName(genericName);
200
201 for (ExecutableTypeData type : node.getExecutableTypes()) {
202 if (polymorphicType.sameSignature(type)) {
203 polymorphicSignatureFound = true;
204 break;
205 }
206 }
207
208 if (!polymorphicSignatureFound) {
209 node.getExecutableTypes().add(polymorphicType);
210 }
211 }
212
213 List<ExecutableTypeData> rootTypes = buildExecutableHierarchy(node);
214 List<ExecutableTypeData> additionalAbstractRootTypes = new ArrayList<>();
215 for (int i = 1; i < rootTypes.size(); i++) {
216 ExecutableTypeData rootType = rootTypes.get(i);
217 if (rootType.isAbstract()) {
218 // cannot implemement root
219 additionalAbstractRootTypes.add(rootType);
220 } else {
221 node.getExecutableTypes().remove(rootType);
222 }
223 }
224 if (!additionalAbstractRootTypes.isEmpty()) {
225 node.addError("Incompatible abstract execute methods found %s.", additionalAbstractRootTypes);
226 }
227
228 namesUnique(node.getExecutableTypes());
229
230 }
231
232 private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) {
233 List<ExecutableTypeData> executes = node.getExecutableTypes();
234 if (executes.isEmpty()) {
235 return Collections.emptyList();
236 }
237 List<ExecutableTypeData> hierarchyExecutes = new ArrayList<>(executes);
238 Collections.sort(hierarchyExecutes);
239 ExecutableTypeData parent = hierarchyExecutes.get(0);
240 ListIterator<ExecutableTypeData> executesIterator = hierarchyExecutes.listIterator(1);
241 buildExecutableHierarchy(node, parent, executesIterator);
242 return hierarchyExecutes;
243 }
244
245 private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) {
246 while (executesIterator.hasNext()) {
247 ExecutableTypeData other = executesIterator.next();
248 if (other.canDelegateTo(parent)) {
249 parent.addDelegatedFrom(other);
250 executesIterator.remove();
251 }
252 }
253 for (int i = 1; i < parent.getDelegatedFrom().size(); i++) {
254 buildExecutableHierarchy(node, parent.getDelegatedFrom().get(i - 1), parent.getDelegatedFrom().listIterator(i));
255 }
256 }
257
258 private List<Element> loadMembers(TypeElement templateType) {
259 List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
260
261 return members;
262 }
263
264 private boolean containsSpecializations(List<Element> elements) {
265 boolean foundSpecialization = false;
266 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
267 if (ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class) != null) {
268 foundSpecialization = true;
269 break;
270 }
271 }
272 return foundSpecialization;
273 }
274
275 private void initializeImportGuards(NodeData node, List<TypeElement> lookupTypes, List<Element> elements) {
276 for (TypeElement lookupType : lookupTypes) {
277 AnnotationMirror importAnnotation = ElementUtils.findAnnotationMirror(processingEnv, lookupType, ImportStatic.class);
278 if (importAnnotation == null) {
279 continue;
280 }
281 AnnotationValue importClassesValue = ElementUtils.getAnnotationValue(importAnnotation, "value");
282 List<TypeMirror> importClasses = ElementUtils.getAnnotationValueList(TypeMirror.class, importAnnotation, "value");
283 if (importClasses.isEmpty()) {
284 node.addError(importAnnotation, importClassesValue, "At least import guard classes must be specified.");
285 continue;
286 }
287 for (TypeMirror importGuardClass : importClasses) {
288 if (importGuardClass.getKind() != TypeKind.DECLARED) {
289 node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' is not a declared type.", ElementUtils.getQualifiedName(importGuardClass));
290 continue;
291 }
292
293 TypeElement typeElement = ElementUtils.fromTypeMirror(importGuardClass);
294 if (typeElement.getEnclosingElement().getKind().isClass() && !typeElement.getModifiers().contains(Modifier.PUBLIC)) {
295 node.addError(importAnnotation, importClassesValue, "The specified import guard class '%s' must be public.", ElementUtils.getQualifiedName(importGuardClass));
296 continue;
297 }
298 elements.addAll(importPublicStaticMembers(typeElement, false));
299 }
300 }
301 }
302
303 private List<? extends Element> importPublicStaticMembers(TypeElement importGuardClass, boolean includeConstructors) {
304 // hack to reload type is necessary for incremental compiling in eclipse.
305 // otherwise methods inside of import guard types are just not found.
306 TypeElement typeElement = ElementUtils.fromTypeMirror(context.reloadType(importGuardClass.asType()));
307
308 List<Element> members = new ArrayList<>();
309 for (Element importElement : processingEnv.getElementUtils().getAllMembers(typeElement)) {
310 if (!importElement.getModifiers().contains(Modifier.PUBLIC)) {
311 continue;
312 }
313
314 if (includeConstructors && importElement.getKind() == ElementKind.CONSTRUCTOR) {
315 members.add(importElement);
316 }
317
318 if (!importElement.getModifiers().contains(Modifier.STATIC)) {
319 continue;
320 }
321
322 ElementKind kind = importElement.getKind();
323 if (kind.isField() || kind == ElementKind.METHOD) {
324 members.add(importElement);
325 }
326 }
327 return members;
328 }
329
330 private NodeData parseNodeData(TypeElement templateType, List<TypeElement> typeHierarchy) {
331 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
332 TypeSystemData typeSystem = null;
333 if (typeSystemMirror != null) {
334 TypeMirror typeSystemType = ElementUtils.getAnnotationValue(TypeMirror.class, typeSystemMirror, "value");
335 typeSystem = (TypeSystemData) context.getTemplate(typeSystemType, true);
336 if (typeSystem == null) {
337 NodeData nodeData = new NodeData(context, templateType);
338 nodeData.addError("The used type system '%s' is invalid. Fix errors in the type system first.", ElementUtils.getQualifiedName(typeSystemType));
339 return nodeData;
340 }
341 } else {
342 // default dummy type system
343 typeSystem = new TypeSystemData(context, templateType, null, NodeParser.class.getAnnotation(DSLOptions.class), true);
344 }
345 AnnotationMirror nodeInfoMirror = findFirstAnnotation(typeHierarchy, NodeInfo.class);
346 String shortName = null;
347 if (nodeInfoMirror != null) {
348 shortName = ElementUtils.getAnnotationValue(String.class, nodeInfoMirror, "shortName");
349 }
350 boolean useNodeFactory = findFirstAnnotation(typeHierarchy, GenerateNodeFactory.class) != null;
351 return new NodeData(context, templateType, shortName, typeSystem, useNodeFactory);
352
353 }
354
355 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) {
356 Set<String> names = new HashSet<>();
357
358 List<NodeFieldData> fields = new ArrayList<>();
359 for (VariableElement field : ElementFilter.fieldsIn(elements)) {
360 if (field.getModifiers().contains(Modifier.STATIC)) {
361 continue;
362 }
363 if (field.getModifiers().contains(Modifier.PUBLIC) || field.getModifiers().contains(Modifier.PROTECTED)) {
364 String name = field.getSimpleName().toString();
365 fields.add(new NodeFieldData(field, null, field, false));
366 names.add(name);
367 }
368 }
369
370 List<TypeElement> reversedTypeHierarchy = new ArrayList<>(typeHierarchy);
371 Collections.reverse(reversedTypeHierarchy);
372 for (TypeElement typeElement : reversedTypeHierarchy) {
373 AnnotationMirror nodeChildrenMirror = ElementUtils.findAnnotationMirror(processingEnv, typeElement, NodeFields.class);
374 List<AnnotationMirror> children = ElementUtils.collectAnnotations(context, nodeChildrenMirror, "value", typeElement, NodeField.class);
375
376 for (AnnotationMirror mirror : children) {
377 String name = ElementUtils.firstLetterLowerCase(ElementUtils.getAnnotationValue(String.class, mirror, "name"));
378 TypeMirror type = ElementUtils.getAnnotationValue(TypeMirror.class, mirror, "type");
379
380 NodeFieldData field = new NodeFieldData(typeElement, mirror, new CodeVariableElement(type, name), true);
381 if (name.isEmpty()) {
382 field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Field name cannot be empty.");
383 } else if (names.contains(name)) {
384 field.addError(ElementUtils.getAnnotationValue(mirror, "name"), "Duplicate field name '%s'.", name);
385 }
386 names.add(name);
387
388 fields.add(field);
389 }
390 }
391
392 for (NodeFieldData nodeFieldData : fields) {
393 nodeFieldData.setGetter(findGetter(elements, nodeFieldData.getName(), nodeFieldData.getType()));
394 }
395
396 return fields;
397 }
398
399 private List<NodeChildData> parseChildren(final List<TypeElement> typeHierarchy, List<? extends Element> elements) {
400 Set<String> shortCircuits = new HashSet<>();
401 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
402 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
403 if (mirror != null) {
404 shortCircuits.add(ElementUtils.getAnnotationValue(String.class, mirror, "value"));
405 }
406 }
407 Map<String, TypeMirror> castNodeTypes = new HashMap<>();
408 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
409 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, CreateCast.class);
410 if (mirror != null) {
411 List<String> children = (ElementUtils.getAnnotationValueList(String.class, mirror, "value"));
412 if (children != null) {
413 for (String child : children) {
414 castNodeTypes.put(child, method.getReturnType());
415 }
416 }
417 }
418 }
419
420 List<NodeChildData> parsedChildren = new ArrayList<>();
421 List<TypeElement> typeHierarchyReversed = new ArrayList<>(typeHierarchy);
422 Collections.reverse(typeHierarchyReversed);
423 for (TypeElement type : typeHierarchyReversed) {
424 AnnotationMirror nodeChildrenMirror = ElementUtils.findAnnotationMirror(processingEnv, type, NodeChildren.class);
425
426 TypeMirror nodeClassType = type.getSuperclass();
427 if (!ElementUtils.isAssignable(nodeClassType, context.getTruffleTypes().getNode())) {
428 nodeClassType = null;
429 }
430
431 List<AnnotationMirror> children = ElementUtils.collectAnnotations(context, nodeChildrenMirror, "value", type, NodeChild.class);
432 int index = 0;
433 for (AnnotationMirror childMirror : children) {
434 String name = ElementUtils.getAnnotationValue(String.class, childMirror, "value");
435 if (name.equals("")) {
436 name = "child" + index;
437 }
438
439 Cardinality cardinality = Cardinality.ONE;
440
441 TypeMirror childType = inheritType(childMirror, "type", nodeClassType);
442 if (childType.getKind() == TypeKind.ARRAY) {
443 cardinality = Cardinality.MANY;
444 }
445
446 TypeMirror originalChildType = childType;
447 TypeMirror castNodeType = castNodeTypes.get(name);
448 if (castNodeType != null) {
449 childType = castNodeType;
450 }
451
452 Element getter = findGetter(elements, name, childType);
453 NodeChildData nodeChild = new NodeChildData(type, childMirror, name, childType, originalChildType, getter, cardinality);
454
455 parsedChildren.add(nodeChild);
456
457 if (nodeChild.getNodeType() == null) {
458 nodeChild.addError("No valid node type could be resoleved.");
459 }
460 if (nodeChild.hasErrors()) {
461 continue;
462 }
463
464 index++;
465 }
466 }
467
468 List<NodeChildData> filteredChildren = new ArrayList<>();
469 Set<String> encounteredNames = new HashSet<>();
470 for (int i = parsedChildren.size() - 1; i >= 0; i--) {
471 NodeChildData child = parsedChildren.get(i);
472 if (!encounteredNames.contains(child.getName())) {
473 filteredChildren.add(0, child);
474 encounteredNames.add(child.getName());
475 }
476 }
477
478 return filteredChildren;
479 }
480
481 private List<NodeExecutionData> parseExecutions(List<NodeFieldData> fields, List<NodeChildData> children, List<? extends Element> elements) {
482 // pre-parse short circuits
483 Set<String> shortCircuits = new HashSet<>();
484 List<ExecutableElement> methods = ElementFilter.methodsIn(elements);
485 for (ExecutableElement method : methods) {
486 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, ShortCircuit.class);
487 if (mirror != null) {
488 shortCircuits.add(ElementUtils.getAnnotationValue(String.class, mirror, "value"));
489 }
490 }
491
492 boolean hasVarArgs = false;
493 int maxSignatureSize = 0;
494 if (!children.isEmpty()) {
495 int lastIndex = children.size() - 1;
496 hasVarArgs = children.get(lastIndex).getCardinality() == Cardinality.MANY;
497 if (hasVarArgs) {
498 maxSignatureSize = lastIndex;
499 } else {
500 maxSignatureSize = children.size();
501 }
502 }
503
504 List<NodeFieldData> nonGetterFields = new ArrayList<>();
505 for (NodeFieldData field : fields) {
506 if (field.getGetter() == null && field.isGenerated()) {
507 nonGetterFields.add(field);
508 }
509 }
510
511 TypeMirror cacheAnnotation = context.getType(Cached.class);
512 List<TypeMirror> frameTypes = context.getFrameTypes();
513 // pre-parse specializations to find signature size
514 for (ExecutableElement method : methods) {
515 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, method, Specialization.class);
516 if (mirror == null) {
517 continue;
518 }
519 int currentArgumentIndex = 0;
520 boolean skipShortCircuit = false;
521 parameter: for (VariableElement var : method.getParameters()) {
522 if (skipShortCircuit) {
523 skipShortCircuit = false;
524 continue parameter;
525 }
526
527 TypeMirror type = var.asType();
528 if (currentArgumentIndex == 0) {
529 // skip optionals
530 for (TypeMirror frameType : frameTypes) {
531 if (ElementUtils.typeEquals(type, frameType)) {
532 continue parameter;
533 }
534 }
535 }
536
537 if (currentArgumentIndex < nonGetterFields.size()) {
538 for (NodeFieldData field : nonGetterFields) {
539 if (ElementUtils.typeEquals(var.asType(), field.getType())) {
540 continue parameter;
541 }
542 }
543 }
544
545 if (ElementUtils.findAnnotationMirror(var.getAnnotationMirrors(), cacheAnnotation) != null) {
546 continue parameter;
547 }
548
549 int childIndex = currentArgumentIndex < children.size() ? currentArgumentIndex : children.size() - 1;
550 if (childIndex != -1) {
551 NodeChildData child = children.get(childIndex);
552 if (shortCircuits.contains(NodeExecutionData.createIndexedName(child, currentArgumentIndex - childIndex))) {
553 skipShortCircuit = true;
554 }
555 }
556
557 currentArgumentIndex++;
558 }
559 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentIndex);
560 }
561
562 List<NodeExecutionData> executions = new ArrayList<>();
563 for (int i = 0; i < maxSignatureSize; i++) {
564 boolean varArgParameter = false;
565 int childIndex = i;
566 if (i >= children.size() - 1) {
567 if (hasVarArgs) {
568 varArgParameter = hasVarArgs;
569 childIndex = Math.min(i, children.size() - 1);
570 } else if (i >= children.size()) {
571 childIndex = -1;
572 }
573 }
574 int varArgsIndex = -1;
575 boolean shortCircuit = false;
576 NodeChildData child = null;
577 if (childIndex != -1) {
578 varArgsIndex = varArgParameter ? Math.abs(childIndex - i) : -1;
579 child = children.get(childIndex);
580 shortCircuit = shortCircuits.contains(NodeExecutionData.createIndexedName(child, varArgsIndex));
581 }
582 executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit));
583 }
584 return executions;
585 }
586
587 private List<ExecutableTypeData> parseExecutableTypeData(NodeData node, List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
588 List<ExecutableTypeData> typeData = new ArrayList<>();
589 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
590 Set<Modifier> modifiers = method.getModifiers();
591 if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) {
592 continue;
593 }
594 if (!includeFinals && modifiers.contains(Modifier.FINAL)) {
595 continue;
596 }
597
598 if (!method.getSimpleName().toString().startsWith("execute")) {
599 continue;
600 }
601 if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) {
602 continue;
603 }
604
605 ExecutableTypeData executableType = new ExecutableTypeData(node, method, signatureSize, context.getFrameTypes());
606
607 if (executableType.getFrameParameter() != null) {
608 boolean supportedType = false;
609 for (TypeMirror type : frameTypes) {
610 if (ElementUtils.isAssignable(type, executableType.getFrameParameter())) {
611 supportedType = true;
612 break;
613 }
614 }
615 if (!supportedType) {
616 continue;
617 }
618 }
619
620 typeData.add(executableType);
621 }
622
623 namesUnique(typeData);
624
625 return typeData;
626 }
627
628 private static void namesUnique(List<ExecutableTypeData> typeData) {
629 List<String> names = new ArrayList<>();
630 for (ExecutableTypeData type : typeData) {
631 names.add(type.getUniqueName());
632 }
633 while (renameDuplicateIds(names)) {
634 // fix point
635 }
636
637 for (int i = 0; i < typeData.size(); i++) {
638 typeData.get(i).setUniqueName(names.get(i));
639 }
640 }
641
642 private void initializeExecutableTypes(NodeData node) {
643 List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
644
645 Set<String> inconsistentFrameTypes = new HashSet<>();
646 TypeMirror frameType = null;
647 for (ExecutableTypeData execute : allExecutes) {
648
649 TypeMirror frame = execute.getFrameParameter();
650 TypeMirror resolvedFrameType;
651 if (frame != null) {
652 resolvedFrameType = frame;
653 if (frameType == null) {
654 frameType = resolvedFrameType;
655 } else if (!ElementUtils.typeEquals(frameType, resolvedFrameType)) {
656 // found inconsistent frame types
657 inconsistentFrameTypes.add(ElementUtils.getSimpleName(frameType));
658 inconsistentFrameTypes.add(ElementUtils.getSimpleName(resolvedFrameType));
659 }
660 }
661 }
662 if (!inconsistentFrameTypes.isEmpty()) {
663 // ensure they are sorted somehow
664 List<String> inconsistentFrameTypesList = new ArrayList<>(inconsistentFrameTypes);
665 Collections.sort(inconsistentFrameTypesList);
666 node.addError("Invalid inconsistent frame types %s found for the declared execute methods. The frame type must be identical for all execute methods.", inconsistentFrameTypesList);
667 }
668 if (frameType == null) {
669 frameType = context.getType(void.class);
670 }
671
672 node.setFrameType(frameType);
673
674 boolean genericFound = false;
675 for (ExecutableTypeData type : node.getExecutableTypes()) {
676 if (!type.hasUnexpectedValue(context)) {
677 genericFound = true;
678 break;
679 }
680 }
681
682 // no generic executes
683 if (!genericFound) {
684 node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
685 + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions.");
686 }
687
688 int nodeChildDeclarations = 0;
689 int nodeChildDeclarationsRequired = 0;
690 List<NodeExecutionData> executions = node.getChildExecutions();
691 for (NodeExecutionData execution : executions) {
692 if (execution.getChild() == null) {
693 nodeChildDeclarationsRequired = execution.getIndex() + 1;
694 } else {
695 nodeChildDeclarations++;
696 }
697 }
698
699 List<String> requireNodeChildDeclarations = new ArrayList<>();
700 for (ExecutableTypeData type : allExecutes) {
701 if (type.getEvaluatedCount() < nodeChildDeclarationsRequired) {
702 requireNodeChildDeclarations.add(ElementUtils.createReferenceName(type.getMethod()));
703 }
704 }
705
706 if (!requireNodeChildDeclarations.isEmpty()) {
707 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. "
708 + "The following execute methods do not provide all evaluated values for the expected signature size %s: %s.", executions.size(), requireNodeChildDeclarations);
709 }
710
711 if (nodeChildDeclarations > 0 && executions.size() == node.getMinimalEvaluatedParameters()) {
712 for (NodeChildData child : node.getChildren()) {
713 child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods.");
714 }
715 }
716
717 }
718
719 private void initializeChildren(NodeData node) {
720 initializeExecuteWith(node);
721
722 for (NodeChildData child : node.getChildren()) {
723 TypeMirror nodeType = child.getNodeType();
724 NodeData fieldNodeData = parseChildNodeData(node, child, ElementUtils.fromTypeMirror(nodeType));
725
726 child.setNode(fieldNodeData);
727 if (fieldNodeData == null || fieldNodeData.hasErrors()) {
728 child.addError("Node type '%s' is invalid or not a subclass of Node.", ElementUtils.getQualifiedName(nodeType));
729 } else {
730 List<ExecutableTypeData> types = child.findGenericExecutableTypes(context);
731 if (types.isEmpty()) {
732 AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
733 child.addError(executeWithValue, "No generic execute method found with %s evaluated arguments for node type %s and frame types %s.", child.getExecuteWith().size(),
734 ElementUtils.getSimpleName(nodeType), ElementUtils.getUniqueIdentifiers(createAllowedChildFrameTypes(node)));
735 }
736 }
737 }
738 }
739
740 private static void initializeExecuteWith(NodeData node) {
741 for (NodeChildData child : node.getChildren()) {
742 List<String> executeWithStrings = ElementUtils.getAnnotationValueList(String.class, child.getMessageAnnotation(), "executeWith");
743 AnnotationValue executeWithValue = ElementUtils.getAnnotationValue(child.getMessageAnnotation(), "executeWith");
744 List<NodeExecutionData> executeWith = new ArrayList<>();
745 for (String executeWithString : executeWithStrings) {
746 if (child.getName().equals(executeWithString)) {
747 child.addError(executeWithValue, "The child node '%s' cannot be executed with itself.", executeWithString);
748 continue;
749 }
750 NodeExecutionData found = null;
751 boolean before = true;
752 for (NodeExecutionData resolveChild : node.getChildExecutions()) {
753 if (resolveChild.getChild() == child) {
754 before = false;
755 continue;
756 }
757 if (resolveChild.getIndexedName().equals(executeWithString)) {
758 found = resolveChild;
759 break;
760 }
761 }
762
763 if (found == null) {
764 child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The child node was not found.", child.getName(), executeWithString);
765 continue;
766 } else if (!before) {
767 child.addError(executeWithValue, "The child node '%s' cannot be executed with '%s'. The node %s is executed after the current node.", child.getName(), executeWithString,
768 executeWithString);
769 continue;
770 }
771 executeWith.add(found);
772 }
773 child.setExecuteWith(executeWith);
774 }
775 }
776
777 private NodeData parseChildNodeData(NodeData parentNode, NodeChildData child, TypeElement originalTemplateType) {
778 TypeElement templateType = ElementUtils.fromTypeMirror(context.reloadTypeElement(originalTemplateType));
779
780 if (ElementUtils.findAnnotationMirror(processingEnv, originalTemplateType, GeneratedBy.class) != null) {
781 // generated nodes should not get called again.
782 return null;
783 }
784
785 if (!ElementUtils.isAssignable(templateType.asType(), context.getTruffleTypes().getNode())) {
786 return null;
787 }
788
789 List<TypeElement> lookupTypes = collectSuperClasses(new ArrayList<TypeElement>(), templateType);
790
791 // Declaration order is not required for child nodes.
792 List<? extends Element> members = processingEnv.getElementUtils().getAllMembers(templateType);
793 NodeData node = parseNodeData(templateType, lookupTypes);
794 if (node.hasErrors()) {
795 return node;
796 }
797 List<TypeMirror> frameTypes = Collections.emptyList();
798 if (parentNode.getFrameType() != null) {
799 frameTypes = Arrays.asList(parentNode.getFrameType());
800 }
801 node.getExecutableTypes().addAll(parseExecutableTypeData(node, members, child.getExecuteWith().size(), frameTypes, true));
802 node.setFrameType(parentNode.getFrameType());
803 return node;
804 }
805
806 private List<TypeMirror> createAllowedChildFrameTypes(NodeData parentNode) {
807 List<TypeMirror> allowedFrameTypes = new ArrayList<>();
808 for (TypeMirror frameType : context.getFrameTypes()) {
809 if (ElementUtils.isAssignable(parentNode.getFrameType(), frameType)) {
810 allowedFrameTypes.add(frameType);
811 }
812 }
813 return allowedFrameTypes;
814 }
815
816 private void initializeSpecializations(List<? extends Element> elements, final NodeData node) {
817 if (node.getSpecializations().isEmpty()) {
818 return;
819 }
820
821 initializeExpressions(elements, node);
822
823 if (node.hasErrors()) {
824 return;
825 }
826
827 initializeGeneric(node);
828 initializeUninitialized(node);
829 initializeOrder(node);
830 initializePolymorphism(node); // requires specializations
831 initializeReachability(node);
832 initializeContains(node);
833 resolveContains(node);
834
835 List<SpecializationData> specializations = node.getSpecializations();
836 for (SpecializationData cur : specializations) {
837 for (SpecializationData contained : cur.getContains()) {
838 if (contained != cur) {
839 contained.getExcludedBy().add(cur);
840 }
841 }
842 }
843
844 initializeSpecializationIdsWithMethodNames(node.getSpecializations());
845 }
846
847 private static void initializeOrder(NodeData node) {
848 List<SpecializationData> specializations = node.getSpecializations();
849 Collections.sort(specializations);
850
851 for (SpecializationData specialization : specializations) {
852 String searchName = specialization.getInsertBeforeName();
853 if (searchName == null || specialization.getMethod() == null) {
854 continue;
855 }
856 SpecializationData found = lookupSpecialization(node, searchName);
857 if (found == null || found.getMethod() == null) {
858 AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore");
859 specialization.addError(value, "The referenced specialization '%s' could not be found.", searchName);
860 continue;
861 }
862
863 ExecutableElement currentMethod = specialization.getMethod();
864 ExecutableElement insertBeforeMethod = found.getMethod();
865
866 TypeMirror currentEnclosedType = currentMethod.getEnclosingElement().asType();
867 TypeMirror insertBeforeEnclosedType = insertBeforeMethod.getEnclosingElement().asType();
868
869 if (ElementUtils.typeEquals(currentEnclosedType, insertBeforeEnclosedType) || !ElementUtils.isSubtype(currentEnclosedType, insertBeforeEnclosedType)) {
870 AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "insertBefore");
871 specialization.addError(value, "Specializations can only be inserted before specializations in superclasses.", searchName);
872 continue;
873 }
874
875 specialization.setInsertBefore(found);
876 }
877
878 for (int i = 0; i < specializations.size(); i++) {
879 SpecializationData specialization = specializations.get(i);
880 SpecializationData insertBefore = specialization.getInsertBefore();
881 if (insertBefore != null) {
882 int insertIndex = specializations.indexOf(insertBefore);
883 if (insertIndex < i) {
884 specializations.remove(i);
885 specializations.add(insertIndex, specialization);
886 }
887 }
888 }
889
890 for (int i = 0; i < specializations.size(); i++) {
891 specializations.get(i).setIndex(i);
892 }
893 }
894
895 private static void initializeContains(NodeData node) {
896 for (SpecializationData specialization : node.getSpecializations()) {
897 Set<SpecializationData> resolvedSpecializations = specialization.getContains();
898 resolvedSpecializations.clear();
899 Set<String> includeNames = specialization.getContainsNames();
900 for (String includeName : includeNames) {
901 // TODO reduce complexity of this lookup.
902 SpecializationData foundSpecialization = lookupSpecialization(node, includeName);
903
904 if (foundSpecialization == null) {
905 AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
906 specialization.addError(value, "The referenced specialization '%s' could not be found.", includeName);
907 } else {
908 if (foundSpecialization.compareTo(specialization) > 0) {
909 AnnotationValue value = ElementUtils.getAnnotationValue(specialization.getMarkerAnnotation(), "contains");
910 if (foundSpecialization.compareTo(specialization) > 0) {
911 specialization.addError(value, "The contained specialization '%s' must be declared before the containing specialization.", includeName);
912 }
913
914 }
915 resolvedSpecializations.add(foundSpecialization);
916 }
917 }
918 }
919 }
920
921 private void resolveContains(NodeData node) {
922 // flatten transitive includes
923 for (SpecializationData specialization : node.getSpecializations()) {
924 if (specialization.getContains().isEmpty()) {
925 continue;
926 }
927 Set<SpecializationData> foundSpecializations = new HashSet<>();
928 collectIncludes(specialization, foundSpecializations, new HashSet<SpecializationData>());
929 specialization.getContains().addAll(foundSpecializations);
930 }
931 }
932
933 private static SpecializationData lookupSpecialization(NodeData node, String includeName) {
934 SpecializationData foundSpecialization = null;
935 for (SpecializationData searchSpecialization : node.getSpecializations()) {
936 if (searchSpecialization.getMethodName().equals(includeName)) {
937 foundSpecialization = searchSpecialization;
938 break;
939 }
940 }
941 return foundSpecialization;
942 }
943
944 private void collectIncludes(SpecializationData specialization, Set<SpecializationData> found, Set<SpecializationData> visited) {
945 if (visited.contains(specialization)) {
946 // circle found
947 specialization.addError("Circular contained specialization '%s' found.", specialization.createReferenceName());
948 return;
949 }
950 visited.add(specialization);
951
952 for (SpecializationData included : specialization.getContains()) {
953 collectIncludes(included, found, new HashSet<>(visited));
954 found.add(included);
955 }
956 }
957
958 private static void initializeReachability(final NodeData node) {
959 List<SpecializationData> specializations = node.getSpecializations();
960 for (int i = specializations.size() - 1; i >= 0; i--) {
961 SpecializationData current = specializations.get(i);
962 if (current.isPolymorphic()) {
963 current.setReachable(true);
964 continue;
965 }
966
967 List<SpecializationData> shadowedBy = null;
968 for (int j = i - 1; j >= 0; j--) {
969 SpecializationData prev = specializations.get(j);
970 if (prev.isPolymorphic()) {
971 continue;
972 }
973 if (!current.isReachableAfter(prev)) {
974 if (shadowedBy == null) {
975 shadowedBy = new ArrayList<>();
976 }
977 shadowedBy.add(prev);
978 }
979 }
980
981 if (shadowedBy != null) {
982 StringBuilder name = new StringBuilder();
983 String sep = "";
984 for (SpecializationData shadowSpecialization : shadowedBy) {
985 name.append(sep);
986 name.append(shadowSpecialization.createReferenceName());
987 sep = ", ";
988 }
989 current.addError("%s is not reachable. It is shadowed by %s.", current.isFallback() ? "Generic" : "Specialization", name);
990 }
991 current.setReachable(shadowedBy == null);
992 }
993 }
994
995 private static void initializeSpecializationIdsWithMethodNames(List<SpecializationData> specializations) {
996 List<String> signatures = new ArrayList<>();
997 for (SpecializationData specialization : specializations) {
998 if (specialization.isFallback()) {
999 signatures.add("Fallback");
1000 } else if (specialization.isUninitialized()) {
1001 signatures.add("Uninitialized");
1002 } else if (specialization.isPolymorphic()) {
1003 signatures.add("Polymorphic");
1004 } else {
1005 String name = specialization.getMethodName();
1006
1007 // hack for name clashes with BaseNode.
1008 if (name.equalsIgnoreCase("base")) {
1009 name = name + "0";
1010 } else if (name.startsWith("do")) {
1011 String filteredDo = name.substring(2, name.length());
1012 if (!filteredDo.isEmpty() && Character.isJavaIdentifierStart(filteredDo.charAt(0))) {
1013 name = filteredDo;
1014 }
1015 }
1016 signatures.add(ElementUtils.firstLetterUpperCase(name));
1017 }
1018 }
1019
1020 while (renameDuplicateIds(signatures)) {
1021 // fix point
1022 }
1023
1024 for (int i = 0; i < specializations.size(); i++) {
1025 specializations.get(i).setId(signatures.get(i));
1026 }
1027 }
1028
1029 private static boolean renameDuplicateIds(List<String> signatures) {
1030 boolean changed = false;
1031 Map<String, Integer> counts = new HashMap<>();
1032 for (String s1 : signatures) {
1033 Integer count = counts.get(s1.toLowerCase());
1034 if (count == null) {
1035 count = 0;
1036 }
1037 count++;
1038 counts.put(s1.toLowerCase(), count);
1039 }
1040
1041 for (String s : counts.keySet()) {
1042 int count = counts.get(s);
1043 if (count > 1) {
1044 changed = true;
1045 int number = 0;
1046 for (ListIterator<String> iterator = signatures.listIterator(); iterator.hasNext();) {
1047 String s2 = iterator.next();
1048 if (s.equalsIgnoreCase(s2)) {
1049 iterator.set(s2 + number);
1050 number++;
1051 }
1052 }
1053 }
1054 }
1055 return changed;
1056 }
1057
1058 private void initializeExpressions(List<? extends Element> elements, NodeData node) {
1059 List<Element> members = filterNotAccessibleElements(node.getTemplateType(), elements);
1060
1061 List<VariableElement> fields = new ArrayList<>();
1062 for (NodeFieldData field : node.getFields()) {
1063 fields.add(field.getVariable());
1064 }
1065
1066 for (SpecializationData specialization : node.getSpecializations()) {
1067 if (specialization.getMethod() == null) {
1068 continue;
1069 }
1070
1071 List<Element> specializationMembers = new ArrayList<>(members.size() + specialization.getParameters().size() + fields.size());
1072 for (Parameter p : specialization.getParameters()) {
1073 specializationMembers.add(p.getVariableElement());
1074 }
1075 specializationMembers.addAll(fields);
1076 specializationMembers.addAll(members);
1077 DSLExpressionResolver resolver = new DSLExpressionResolver(context, specializationMembers);
1078
1079 initializeCaches(specialization, resolver);
1080 initializeGuards(specialization, resolver);
1081 if (specialization.hasErrors()) {
1082 continue;
1083 }
1084 initializeLimit(specialization, resolver);
1085 initializeAssumptions(specialization, resolver);
1086 }
1087 }
1088
1089 private void initializeAssumptions(SpecializationData specialization, DSLExpressionResolver resolver) {
1090 final DeclaredType assumptionType = context.getDeclaredType(Assumption.class);
1091 final TypeMirror assumptionArrayType = new ArrayCodeTypeMirror(assumptionType);
1092 final List<String> assumptionDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "assumptions");
1093 List<AssumptionExpression> assumptionExpressions = new ArrayList<>();
1094 int assumptionId = 0;
1095 for (String assumption : assumptionDefinitions) {
1096 AssumptionExpression assumptionExpression;
1097 DSLExpression expression = null;
1098 try {
1099 expression = DSLExpression.parse(assumption);
1100 expression.accept(resolver);
1101 assumptionExpression = new AssumptionExpression(specialization, expression, "assumption" + assumptionId);
1102 if (!ElementUtils.isAssignable(expression.getResolvedType(), assumptionType) && !ElementUtils.isAssignable(expression.getResolvedType(), assumptionArrayType)) {
1103 assumptionExpression.addError("Incompatible return type %s. Assumptions must be assignable to %s or %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
1104 ElementUtils.getSimpleName(assumptionType), ElementUtils.getSimpleName(assumptionArrayType));
1105 }
1106 if (specialization.isDynamicParameterBound(expression)) {
1107 specialization.addError("Assumption expressions must not bind dynamic parameter values.");
1108 }
1109 } catch (InvalidExpressionException e) {
1110 assumptionExpression = new AssumptionExpression(specialization, null, "assumption" + assumptionId);
1111 assumptionExpression.addError("Error parsing expression '%s': %s", assumption, e.getMessage());
1112 }
1113 assumptionExpressions.add(assumptionExpression);
1114 }
1115 specialization.setAssumptionExpressions(assumptionExpressions);
1116 }
1117
1118 private void initializeLimit(SpecializationData specialization, DSLExpressionResolver resolver) {
1119 AnnotationValue annotationValue = ElementUtils.getAnnotationValue(specialization.getMessageAnnotation(), "limit");
1120
1121 String limitValue;
1122 if (annotationValue == null) {
1123 limitValue = "";
1124 } else {
1125 limitValue = (String) annotationValue.getValue();
1126 }
1127 if (limitValue.isEmpty()) {
1128 limitValue = "3";
1129 } else if (!specialization.hasMultipleInstances()) {
1130 specialization.addWarning(annotationValue, "The limit expression has no effect. Multiple specialization instantiations are impossible for this specialization.");
1131 return;
1132 }
1133
1134 TypeMirror expectedType = context.getType(int.class);
1135 try {
1136 DSLExpression expression = DSLExpression.parse(limitValue);
1137 expression.accept(resolver);
1138 if (!ElementUtils.typeEquals(expression.getResolvedType(), expectedType)) {
1139 specialization.addError(annotationValue, "Incompatible return type %s. Limit expressions must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
1140 ElementUtils.getSimpleName(expectedType));
1141 }
1142 if (specialization.isDynamicParameterBound(expression)) {
1143 specialization.addError(annotationValue, "Limit expressions must not bind dynamic parameter values.");
1144 }
1145
1146 specialization.setLimitExpression(expression);
1147 } catch (InvalidExpressionException e) {
1148 specialization.addError(annotationValue, "Error parsing expression '%s': %s", limitValue, e.getMessage());
1149 }
1150 }
1151
1152 private void initializeCaches(SpecializationData specialization, DSLExpressionResolver resolver) {
1153 TypeMirror cacheMirror = context.getType(Cached.class);
1154 List<CacheExpression> expressions = new ArrayList<>();
1155 for (Parameter parameter : specialization.getParameters()) {
1156 AnnotationMirror annotationMirror = ElementUtils.findAnnotationMirror(parameter.getVariableElement().getAnnotationMirrors(), cacheMirror);
1157 if (annotationMirror != null) {
1158 String initializer = ElementUtils.getAnnotationValue(String.class, annotationMirror, "value");
1159
1160 TypeMirror parameterType = parameter.getType();
1161
1162 DSLExpressionResolver localResolver = resolver;
1163 if (parameterType.getKind() == TypeKind.DECLARED) {
1164 localResolver = localResolver.copy(importPublicStaticMembers(ElementUtils.fromTypeMirror(parameterType), true));
1165 }
1166
1167 CacheExpression cacheExpression;
1168 DSLExpression expression = null;
1169 try {
1170 expression = DSLExpression.parse(initializer);
1171 expression.accept(localResolver);
1172 cacheExpression = new CacheExpression(parameter, annotationMirror, expression);
1173 if (!ElementUtils.typeEquals(expression.getResolvedType(), parameter.getType())) {
1174 cacheExpression.addError("Incompatible return type %s. The expression type must be equal to the parameter type %s.", ElementUtils.getSimpleName(expression.getResolvedType()),
1175 ElementUtils.getSimpleName(parameter.getType()));
1176 }
1177 } catch (InvalidExpressionException e) {
1178 cacheExpression = new CacheExpression(parameter, annotationMirror, null);
1179 cacheExpression.addError("Error parsing expression '%s': %s", initializer, e.getMessage());
1180 }
1181 expressions.add(cacheExpression);
1182 }
1183 }
1184 specialization.setCaches(expressions);
1185
1186 if (specialization.hasErrors()) {
1187 return;
1188 }
1189
1190 // verify that cache expressions are bound in the correct order.
1191 for (int i = 0; i < expressions.size(); i++) {
1192 CacheExpression currentExpression = expressions.get(i);
1193 Set<VariableElement> boundVariables = currentExpression.getExpression().findBoundVariableElements();
1194 for (int j = i + 1; j < expressions.size(); j++) {
1195 CacheExpression boundExpression = expressions.get(j);
1196 if (boundVariables.contains(boundExpression.getParameter().getVariableElement())) {
1197 currentExpression.addError("The initializer expression of parameter '%s' binds unitialized parameter '%s. Reorder the parameters to resolve the problem.",
1198 currentExpression.getParameter().getLocalName(), boundExpression.getParameter().getLocalName());
1199 break;
1200 }
1201 }
1202 }
1203 }
1204
1205 private void initializeGuards(SpecializationData specialization, DSLExpressionResolver resolver) {
1206 final TypeMirror booleanType = context.getType(boolean.class);
1207 List<String> guardDefinitions = ElementUtils.getAnnotationValueList(String.class, specialization.getMarkerAnnotation(), "guards");
1208 List<GuardExpression> guardExpressions = new ArrayList<>();
1209 for (String guard : guardDefinitions) {
1210 GuardExpression guardExpression;
1211 DSLExpression expression = null;
1212 try {
1213 expression = DSLExpression.parse(guard);
1214 expression.accept(resolver);
1215 guardExpression = new GuardExpression(specialization, expression);
1216 if (!ElementUtils.typeEquals(expression.getResolvedType(), booleanType)) {
1217 guardExpression.addError("Incompatible return type %s. Guards must return %s.", ElementUtils.getSimpleName(expression.getResolvedType()), ElementUtils.getSimpleName(booleanType));
1218 }
1219 } catch (InvalidExpressionException e) {
1220 guardExpression = new GuardExpression(specialization, null);
1221 guardExpression.addError("Error parsing expression '%s': %s", guard, e.getMessage());
1222 }
1223 guardExpressions.add(guardExpression);
1224 }
1225 specialization.setGuards(guardExpressions);
1226 }
1227
1228 private static List<Element> filterNotAccessibleElements(TypeElement templateType, List<? extends Element> elements) {
1229 String packageName = ElementUtils.getPackageName(templateType);
1230 List<Element> filteredElements = new ArrayList<>(elements);
1231 for (Element element : elements) {
1232 Modifier visibility = ElementUtils.getVisibility(element.getModifiers());
1233 if (visibility == Modifier.PRIVATE) {
1234 continue;
1235 } else if (visibility == null) {
1236 String elementPackageName = ElementUtils.getPackageName(element.getEnclosingElement().asType());
1237 if (!Objects.equals(packageName, elementPackageName) && !elementPackageName.equals("java.lang")) {
1238 continue;
1239 }
1240 }
1241
1242 filteredElements.add(element);
1243 }
1244 return filteredElements;
1245 }
1246
1247 private void initializeGeneric(final NodeData node) {
1248 List<SpecializationData> generics = new ArrayList<>();
1249 for (SpecializationData spec : node.getSpecializations()) {
1250 if (spec.isFallback()) {
1251 generics.add(spec);
1252 }
1253 }
1254
1255 if (generics.size() == 1 && node.getSpecializations().size() == 1) {
1256 // TODO this limitation should be lifted
1257 for (SpecializationData generic : generics) {
1258 generic.addError("@%s defined but no @%s.", Fallback.class.getSimpleName(), Specialization.class.getSimpleName());
1259 }
1260 }
1261
1262 if (generics.isEmpty()) {
1263 node.getSpecializations().add(createGenericSpecialization(node));
1264 } else {
1265 if (generics.size() > 1) {
1266 for (SpecializationData generic : generics) {
1267 generic.addError("Only one @%s is allowed per operation.", Fallback.class.getSimpleName());
1268 }
1269 }
1270 }
1271 }
1272
1273 private SpecializationData createGenericSpecialization(final NodeData node) {
1274 FallbackParser parser = new FallbackParser(context, node);
1275 MethodSpec specification = parser.createDefaultMethodSpec(node.getSpecializations().iterator().next().getMethod(), null, true, null);
1276
1277 List<VariableElement> parameterTypes = new ArrayList<>();
1278 int signatureIndex = 1;
1279 for (ParameterSpec spec : specification.getRequired()) {
1280 parameterTypes.add(new CodeVariableElement(createGenericType(node, spec), "arg" + signatureIndex));
1281 if (spec.isSignature()) {
1282 signatureIndex++;
1283 }
1284 }
1285
1286 TypeMirror returnType = createGenericType(node, specification.getReturnType());
1287 SpecializationData generic = parser.create("Generic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, parameterTypes);
1288 if (generic == null) {
1289 throw new RuntimeException("Unable to create generic signature for node " + node.getNodeId() + " with " + parameterTypes + ". Specification " + specification + ".");
1290 }
1291
1292 return generic;
1293 }
1294
1295 private TypeMirror createGenericType(NodeData node, ParameterSpec spec) {
1296 NodeExecutionData execution = spec.getExecution();
1297 Collection<TypeMirror> allowedTypes;
1298 if (execution == null) {
1299 allowedTypes = spec.getAllowedTypes();
1300 } else {
1301 allowedTypes = Arrays.asList(node.getGenericType(execution));
1302 }
1303 if (allowedTypes.size() == 1) {
1304 return allowedTypes.iterator().next();
1305 } else {
1306 return ElementUtils.getCommonSuperType(context, allowedTypes);
1307 }
1308 }
1309
1310 private static void initializeUninitialized(final NodeData node) {
1311 SpecializationData generic = node.getGenericSpecialization();
1312 if (generic == null) {
1313 return;
1314 }
1315 TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", -1, node, generic.getSpecification(), null, null, generic.getReturnType(), generic.getParameters());
1316 // should not use messages from generic specialization
1317 uninializedMethod.getMessages().clear();
1318 node.getSpecializations().add(new SpecializationData(node, uninializedMethod, SpecializationKind.UNINITIALIZED));
1319 }
1320
1321 private void initializePolymorphism(NodeData node) {
1322 if (!node.needsRewrites(context)) {
1323 return;
1324 }
1325
1326 SpecializationData generic = node.getGenericSpecialization();
1327 List<VariableElement> types = new ArrayList<>();
1328
1329 Collection<TypeMirror> frameTypes = new HashSet<>();
1330 for (SpecializationData specialization : node.getSpecializations()) {
1331 if (specialization.getFrame() != null) {
1332 frameTypes.add(specialization.getFrame().getType());
1333 }
1334 }
1335 if (node.supportsFrame()) {
1336 frameTypes.add(node.getFrameType());
1337 }
1338
1339 if (!frameTypes.isEmpty()) {
1340 frameTypes = ElementUtils.uniqueSortedTypes(frameTypes, false);
1341 TypeMirror frameType;
1342 if (frameTypes.size() == 1) {
1343 frameType = frameTypes.iterator().next();
1344 } else {
1345 frameType = context.getType(Frame.class);
1346 }
1347 types.add(new CodeVariableElement(frameType, TemplateMethod.FRAME_NAME));
1348 }
1349
1350 TypeMirror returnType = null;
1351 int index = 0;
1352 for (Parameter genericParameter : generic.getReturnTypeAndParameters()) {
1353 TypeMirror polymorphicType;
1354 if (genericParameter.getLocalName().equals(TemplateMethod.FRAME_NAME)) {
1355 continue;
1356 }
1357 boolean isReturnParameter = genericParameter == generic.getReturnType();
1358 if (!genericParameter.getSpecification().isSignature()) {
1359 polymorphicType = genericParameter.getType();
1360 } else {
1361 Collection<TypeMirror> usedTypes = new HashSet<>();
1362 for (SpecializationData specialization : node.getSpecializations()) {
1363 if (specialization.isUninitialized()) {
1364 continue;
1365 }
1366 Parameter parameter = specialization.findParameter(genericParameter.getLocalName());
1367 if (parameter == specialization.getReturnType() && specialization.isFallback() && specialization.getMethod() == null) {
1368 continue;
1369 }
1370 if (parameter == null) {
1371 throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
1372 }
1373 usedTypes.add(parameter.getType());
1374 }
1375 usedTypes = ElementUtils.uniqueSortedTypes(usedTypes, false);
1376
1377 if (usedTypes.size() == 1) {
1378 polymorphicType = usedTypes.iterator().next();
1379 } else {
1380 polymorphicType = ElementUtils.getCommonSuperType(context, usedTypes);
1381 }
1382
1383 NodeExecutionData execution = genericParameter.getSpecification().getExecution();
1384 if (execution != null && !ElementUtils.isSubtypeBoxed(context, polymorphicType, node.getGenericType(execution))) {
1385 throw new AssertionError(String.format("Polymorphic types %s not compatible to generic type %s.", polymorphicType, node.getGenericType(execution)));
1386 }
1387
1388 }
1389 if (isReturnParameter) {
1390 returnType = polymorphicType;
1391 } else {
1392 types.add(new CodeVariableElement(polymorphicType, "param" + index));
1393 }
1394 index++;
1395 }
1396
1397 SpecializationMethodParser parser = new SpecializationMethodParser(context, node);
1398 SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
1399 if (polymorphic == null) {
1400 throw new AssertionError("Failed to parse polymorphic signature. " + parser.createDefaultMethodSpec(null, null, false, null) + " Types: " + returnType + " - " + types);
1401 }
1402
1403 polymorphic.setKind(SpecializationKind.POLYMORPHIC);
1404 node.getSpecializations().add(polymorphic);
1405 }
1406
1407 private void initializeShortCircuits(NodeData node) {
1408 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());
1409
1410 boolean valid = true;
1411 List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>();
1412 for (NodeExecutionData execution : node.getChildExecutions()) {
1413 if (!execution.isShortCircuit()) {
1414 continue;
1415 }
1416 shortCircuitExecutions.add(execution);
1417 String valueName = execution.getIndexedName();
1418 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName);
1419
1420 if (availableCircuits == null || availableCircuits.isEmpty()) {
1421 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName);
1422 valid = false;
1423 continue;
1424 }
1425
1426 boolean sameMethodName = true;
1427 String methodName = availableCircuits.get(0).getMethodName();
1428 for (ShortCircuitData circuit : availableCircuits) {
1429 if (!circuit.getMethodName().equals(methodName)) {
1430 sameMethodName = false;
1431 }
1432 }
1433
1434 if (!sameMethodName) {
1435 for (ShortCircuitData circuit : availableCircuits) {
1436 circuit.addError("All short circuits for short cut value '%s' must have the same method name.", valueName);
1437 }
1438 valid = false;
1439 continue;
1440 }
1441
1442 ShortCircuitData genericCircuit = null;
1443 for (ShortCircuitData circuit : availableCircuits) {
1444 if (isGenericShortCutMethod(circuit)) {
1445 genericCircuit = circuit;
1446 break;
1447 }
1448 }
1449
1450 if (genericCircuit == null) {
1451 node.addError("No generic @%s method available for short cut value '%s'.", ShortCircuit.class.getSimpleName(), valueName);
1452 valid = false;
1453 continue;
1454 }
1455
1456 for (ShortCircuitData circuit : availableCircuits) {
1457 if (circuit != genericCircuit) {
1458 circuit.setGenericShortCircuitMethod(genericCircuit);
1459 }
1460 }
1461 }
1462
1463 if (!valid) {
1464 return;
1465 }
1466
1467 List<SpecializationData> specializations = new ArrayList<>();
1468 specializations.addAll(node.getSpecializations());
1469 for (SpecializationData specialization : specializations) {
1470 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size());
1471
1472 for (NodeExecutionData shortCircuit : shortCircuitExecutions) {
1473 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getIndexedName());
1474
1475 ShortCircuitData genericShortCircuit = null;
1476 ShortCircuitData compatibleShortCircuit = null;
1477 for (ShortCircuitData circuit : availableShortCuts) {
1478 if (circuit.isGeneric()) {
1479 genericShortCircuit = circuit;
1480 } else if (circuit.isCompatibleTo(specialization)) {
1481 compatibleShortCircuit = circuit;
1482 }
1483 }
1484
1485 if (compatibleShortCircuit == null) {
1486 compatibleShortCircuit = genericShortCircuit;
1487 }
1488 assignedShortCuts.add(compatibleShortCircuit);
1489 }
1490 specialization.setShortCircuits(assignedShortCuts);
1491 }
1492 }
1493
1494 private boolean isGenericShortCutMethod(ShortCircuitData method) {
1495 for (Parameter parameter : method.getParameters()) {
1496 NodeExecutionData execution = parameter.getSpecification().getExecution();
1497 if (execution == null) {
1498 continue;
1499 }
1500 ExecutableTypeData found = null;
1501 List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context);
1502 for (ExecutableTypeData executable : executableElements) {
1503 if (ElementUtils.typeEquals(executable.getReturnType(), parameter.getType())) {
1504 found = executable;
1505 break;
1506 }
1507 }
1508 if (found == null) {
1509 return false;
1510 }
1511 }
1512 return true;
1513 }
1514
1515 private static Map<String, List<ShortCircuitData>> groupShortCircuits(List<ShortCircuitData> shortCircuits) {
1516 Map<String, List<ShortCircuitData>> group = new HashMap<>();
1517 for (ShortCircuitData shortCircuit : shortCircuits) {
1518 List<ShortCircuitData> circuits = group.get(shortCircuit.getValueName());
1519 if (circuits == null) {
1520 circuits = new ArrayList<>();
1521 group.put(shortCircuit.getValueName(), circuits);
1522 }
1523 circuits.add(shortCircuit);
1524 }
1525 return group;
1526 }
1527
1528 private static boolean verifySpecializationSameLength(NodeData nodeData) {
1529 int lastArgs = -1;
1530 for (SpecializationData specializationData : nodeData.getSpecializations()) {
1531 int signatureArgs = specializationData.getSignatureSize();
1532 if (lastArgs == signatureArgs) {
1533 continue;
1534 }
1535 if (lastArgs != -1) {
1536 for (SpecializationData specialization : nodeData.getSpecializations()) {
1537 specialization.addError("All specializations must have the same number of arguments.");
1538 }
1539 return false;
1540 } else {
1541 lastArgs = signatureArgs;
1542 }
1543 }
1544 return true;
1545 }
1546
1547 private static void verifyVisibilities(NodeData node) {
1548 if (node.getTemplateType().getModifiers().contains(Modifier.PRIVATE) && node.getSpecializations().size() > 0) {
1549 node.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName());
1550 }
1551 }
1552
1553 private static void verifyMissingAbstractMethods(NodeData nodeData, List<? extends Element> originalElements) {
1554 if (!nodeData.needsFactory()) {
1555 // missing abstract methods only needs to be implemented
1556 // if we need go generate factory for it.
1557 return;
1558 }
1559
1560 List<Element> elements = new ArrayList<>(originalElements);
1561 Set<Element> unusedElements = new HashSet<>(elements);
1562 for (ExecutableElement method : nodeData.getAllTemplateMethods()) {
1563 unusedElements.remove(method);
1564 }
1565
1566 for (NodeFieldData field : nodeData.getFields()) {
1567 if (field.getGetter() != null) {
1568 unusedElements.remove(field.getGetter());
1569 }
1570 }
1571
1572 for (NodeChildData child : nodeData.getChildren()) {
1573 if (child.getAccessElement() != null) {
1574 unusedElements.remove(child.getAccessElement());
1575 }
1576 }
1577
1578 for (ExecutableElement unusedMethod : ElementFilter.methodsIn(unusedElements)) {
1579 if (unusedMethod.getModifiers().contains(Modifier.ABSTRACT)) {
1580 nodeData.addError("The type %s must implement the inherited abstract method %s.", ElementUtils.getSimpleName(nodeData.getTemplateType()),
1581 ElementUtils.getReadableSignature(unusedMethod));
1582 }
1583 }
1584 }
1585
1586 private static void verifyNamingConvention(List<? extends TemplateMethod> methods, String prefix) {
1587 for (int i = 0; i < methods.size(); i++) {
1588 TemplateMethod m1 = methods.get(i);
1589 if (m1.getMethodName().length() < 3 || !m1.getMethodName().startsWith(prefix)) {
1590 m1.addError("Naming convention: method name must start with '%s'.", prefix);
1591 }
1592 }
1593 }
1594
1595 private static void verifySpecializationThrows(NodeData node) {
1596 Map<String, SpecializationData> specializationMap = new HashMap<>();
1597 for (SpecializationData spec : node.getSpecializations()) {
1598 specializationMap.put(spec.getMethodName(), spec);
1599 }
1600 for (SpecializationData sourceSpecialization : node.getSpecializations()) {
1601 if (sourceSpecialization.getExceptions() != null) {
1602 for (SpecializationThrowsData throwsData : sourceSpecialization.getExceptions()) {
1603 for (SpecializationThrowsData otherThrowsData : sourceSpecialization.getExceptions()) {
1604 if (otherThrowsData != throwsData && ElementUtils.typeEquals(otherThrowsData.getJavaClass(), throwsData.getJavaClass())) {
1605 throwsData.addError("Duplicate exception type.");
1606 }
1607 }
1608 }
1609 }
1610 }
1611 }
1612
1613 private static void verifyConstructors(NodeData nodeData) {
1614 List<ExecutableElement> constructors = ElementFilter.constructorsIn(nodeData.getTemplateType().getEnclosedElements());
1615 if (constructors.isEmpty()) {
1616 return;
1617 }
1618
1619 boolean oneNonPrivate = false;
1620 for (ExecutableElement constructor : constructors) {
1621 if (ElementUtils.getVisibility(constructor.getModifiers()) != Modifier.PRIVATE) {
1622 oneNonPrivate = true;
1623 break;
1624 }
1625 }
1626 if (!oneNonPrivate && !nodeData.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) {
1627 nodeData.addError("At least one constructor must be non-private.");
1628 }
1629 }
1630
1631 private AnnotationMirror findFirstAnnotation(List<? extends Element> elements, Class<? extends Annotation> annotation) {
1632 for (Element element : elements) {
1633 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(processingEnv, element, annotation);
1634 if (mirror != null) {
1635 return mirror;
1636 }
1637 }
1638 return null;
1639 }
1640
1641 private TypeMirror inheritType(AnnotationMirror annotation, String valueName, TypeMirror parentType) {
1642 TypeMirror inhertNodeType = context.getTruffleTypes().getNode();
1643 TypeMirror value = ElementUtils.getAnnotationValue(TypeMirror.class, annotation, valueName);
1644 if (ElementUtils.typeEquals(inhertNodeType, value)) {
1645 return parentType;
1646 } else {
1647 return value;
1648 }
1649 }
1650
1651 private ExecutableElement findGetter(List<? extends Element> elements, String variableName, TypeMirror type) {
1652 if (type == null) {
1653 return null;
1654 }
1655 String methodName;
1656 if (ElementUtils.typeEquals(type, context.getType(boolean.class))) {
1657 methodName = "is" + ElementUtils.firstLetterUpperCase(variableName);
1658 } else {
1659 methodName = "get" + ElementUtils.firstLetterUpperCase(variableName);
1660 }
1661
1662 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
1663 if (method.getSimpleName().toString().equals(methodName) && method.getParameters().size() == 0 && ElementUtils.isAssignable(type, method.getReturnType())) {
1664 return method;
1665 }
1666 }
1667 return null;
1668 }
1669
1670 private static List<TypeElement> collectSuperClasses(List<TypeElement> collection, TypeElement element) {
1671 if (element != null) {
1672 collection.add(element);
1673 if (element.getSuperclass() != null) {
1674 collectSuperClasses(collection, ElementUtils.fromTypeMirror(element.getSuperclass()));
1675 }
1676 }
1677 return collection;
1678 }
1679
1680 }