comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/NodeParser.java @ 20940:476374f3fe9a

Truffle-DSL: generate better polymorphic execute signatures
author Christian Humer <christian.humer@gmail.com>
date Tue, 14 Apr 2015 15:12:48 +0200
parents 18c0f02fa4d2
children 4f45e4d3361c
comparison
equal deleted inserted replaced
20939:f83fd99b2962 20940:476374f3fe9a
31 import javax.tools.Diagnostic.Kind; 31 import javax.tools.Diagnostic.Kind;
32 32
33 import com.oracle.truffle.api.*; 33 import com.oracle.truffle.api.*;
34 import com.oracle.truffle.api.dsl.*; 34 import com.oracle.truffle.api.dsl.*;
35 import com.oracle.truffle.api.dsl.internal.*; 35 import com.oracle.truffle.api.dsl.internal.*;
36 import com.oracle.truffle.api.frame.*;
36 import com.oracle.truffle.api.nodes.*; 37 import com.oracle.truffle.api.nodes.*;
37 import com.oracle.truffle.dsl.processor.*; 38 import com.oracle.truffle.dsl.processor.*;
38 import com.oracle.truffle.dsl.processor.expression.*; 39 import com.oracle.truffle.dsl.processor.expression.*;
39 import com.oracle.truffle.dsl.processor.java.*; 40 import com.oracle.truffle.dsl.processor.java.*;
40 import com.oracle.truffle.dsl.processor.java.compiler.*; 41 import com.oracle.truffle.dsl.processor.java.compiler.*;
41 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror; 42 import com.oracle.truffle.dsl.processor.java.model.CodeTypeMirror.ArrayCodeTypeMirror;
42 import com.oracle.truffle.dsl.processor.java.model.*; 43 import com.oracle.truffle.dsl.processor.java.model.*;
43 import com.oracle.truffle.dsl.processor.model.*; 44 import com.oracle.truffle.dsl.processor.model.*;
44 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality; 45 import com.oracle.truffle.dsl.processor.model.NodeChildData.Cardinality;
45 import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind; 46 import com.oracle.truffle.dsl.processor.model.SpecializationData.SpecializationKind;
46 import com.oracle.truffle.dsl.processor.model.TemplateMethod.TypeSignature;
47 47
48 @DSLOptions 48 @DSLOptions
49 public class NodeParser extends AbstractParser<NodeData> { 49 public class NodeParser extends AbstractParser<NodeData> {
50 50
51 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class, 51 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Fallback.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, NodeChild.class,
102 try { 102 try {
103 node = parseNode(rootType); 103 node = parseNode(rootType);
104 } catch (CompileErrorException e) { 104 } catch (CompileErrorException e) {
105 throw e; 105 throw e;
106 } catch (Throwable e) { 106 } catch (Throwable e) {
107 e.addSuppressed(new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)), e)); 107 RuntimeException e2 = new RuntimeException(String.format("Parsing of Node %s failed.", ElementUtils.getQualifiedName(rootType)));
108 throw e; 108 e2.addSuppressed(e);
109 throw e2;
109 } 110 }
110 if (node == null && !enclosedNodes.isEmpty()) { 111 if (node == null && !enclosedNodes.isEmpty()) {
111 node = new NodeData(context, rootType); 112 node = new NodeData(context, rootType);
112 } 113 }
113 114
145 } 146 }
146 147
147 node.getFields().addAll(parseFields(lookupTypes, members)); 148 node.getFields().addAll(parseFields(lookupTypes, members));
148 node.getChildren().addAll(parseChildren(lookupTypes, members)); 149 node.getChildren().addAll(parseChildren(lookupTypes, members));
149 node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members)); 150 node.getChildExecutions().addAll(parseExecutions(node.getFields(), node.getChildren(), members));
150 node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes()))); 151 node.getExecutableTypes().addAll(parseExecutableTypeData(members, node.getChildExecutions().size(), context.getFrameTypes(), false));
151 152
152 initializeExecutableTypes(node); 153 initializeExecutableTypes(node);
153 initializeImportGuards(node, lookupTypes, members); 154 initializeImportGuards(node, lookupTypes, members);
155 initializeChildren(node);
154 156
155 if (node.hasErrors()) { 157 if (node.hasErrors()) {
156 return node; // error sync point 158 return node; // error sync point
157 } 159 }
158
159 initializeChildren(node);
160 160
161 if (node.hasErrors()) { 161 if (node.hasErrors()) {
162 return node; // error sync point 162 return node; // error sync point
163 } 163 }
164 164
168 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members)); 168 node.getShortCircuits().addAll(new ShortCircuitParser(context, node).parse(members));
169 169
170 if (node.hasErrors()) { 170 if (node.hasErrors()) {
171 return node; // error sync point 171 return node; // error sync point
172 } 172 }
173 initializeSpecializations(members, node);
174 initializeExecutableTypeHierarchy(node);
173 175
174 verifySpecializationSameLength(node); 176 verifySpecializationSameLength(node);
175 initializeSpecializations(members, node);
176 initializeShortCircuits(node); // requires specializations and polymorphic specializations 177 initializeShortCircuits(node); // requires specializations and polymorphic specializations
177 178
178 verifyVisibilities(node); 179 verifyVisibilities(node);
179 verifyMissingAbstractMethods(node, members); 180 verifyMissingAbstractMethods(node, members);
180 verifyConstructors(node); 181 verifyConstructors(node);
181 verifyNamingConvention(node.getShortCircuits(), "needs"); 182 verifyNamingConvention(node.getShortCircuits(), "needs");
182 verifySpecializationThrows(node); 183 verifySpecializationThrows(node);
183 return 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 TypeMirror frame = polymorphic.getFrame() != null ? polymorphic.getFrame().getType() : null;
192 ExecutableTypeData polymorphicType = new ExecutableTypeData(polymorphic.getReturnType().getType(), "execute", frame, TemplateMethod.getSignatureTypes(polymorphic));
193 for (ExecutableTypeData type : node.getExecutableTypes()) {
194 if (polymorphicType.sameSignature(type)) {
195 polymorphicSignatureFound = true;
196 break;
197 }
198 }
199
200 if (!polymorphicSignatureFound) {
201 node.getExecutableTypes().add(polymorphicType);
202 }
203 }
204
205 List<ExecutableTypeData> rootTypes = buildExecutableHierarchy(node);
206 List<ExecutableTypeData> additionalAbstractRootTypes = new ArrayList<>();
207 for (int i = 1; i < rootTypes.size(); i++) {
208 ExecutableTypeData rootType = rootTypes.get(i);
209 if (rootType.isAbstract()) {
210 // cannot implemement root
211 additionalAbstractRootTypes.add(rootType);
212 } else {
213 node.getExecutableTypes().remove(rootType);
214 }
215 }
216 if (!additionalAbstractRootTypes.isEmpty()) {
217 node.addError("Incompatible abstract execute methods found %s.", rootTypes);
218 }
219
220 }
221
222 private static List<ExecutableTypeData> buildExecutableHierarchy(NodeData node) {
223 List<ExecutableTypeData> executes = node.getExecutableTypes();
224 if (executes.isEmpty()) {
225 return Collections.emptyList();
226 }
227 List<ExecutableTypeData> hierarchyExecutes = new ArrayList<>(executes);
228 Collections.sort(hierarchyExecutes);
229 ExecutableTypeData parent = hierarchyExecutes.get(0);
230 ListIterator<ExecutableTypeData> executesIterator = hierarchyExecutes.listIterator(1);
231 buildExecutableHierarchy(node, parent, executesIterator);
232 return hierarchyExecutes;
233 }
234
235 private static void buildExecutableHierarchy(NodeData node, ExecutableTypeData parent, ListIterator<ExecutableTypeData> executesIterator) {
236 while (executesIterator.hasNext()) {
237 ExecutableTypeData other = executesIterator.next();
238 if (other.canDelegateTo(node, parent)) {
239 parent.addDelegatedFrom(other);
240 executesIterator.remove();
241 }
242 }
243 for (int i = 1; i < parent.getDelegatedFrom().size(); i++) {
244 buildExecutableHierarchy(node, parent.getDelegatedFrom().get(i - 1), parent.getDelegatedFrom().listIterator(i));
245 }
184 } 246 }
185 247
186 private List<Element> loadMembers(TypeElement templateType) { 248 private List<Element> loadMembers(TypeElement templateType) {
187 List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType)); 249 List<Element> members = new ArrayList<>(CompilerFactory.getCompiler(templateType).getAllMembersInDeclarationOrder(context.getEnvironment(), templateType));
188 250
510 executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit)); 572 executions.add(new NodeExecutionData(child, i, varArgsIndex, shortCircuit));
511 } 573 }
512 return executions; 574 return executions;
513 } 575 }
514 576
515 private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes) { 577 private List<ExecutableTypeData> parseExecutableTypeData(List<? extends Element> elements, int signatureSize, List<TypeMirror> frameTypes, boolean includeFinals) {
516 List<ExecutableTypeData> typeData = new ArrayList<>(); 578 List<ExecutableTypeData> typeData = new ArrayList<>();
517 for (ExecutableElement method : ElementFilter.methodsIn(elements)) { 579 for (ExecutableElement method : ElementFilter.methodsIn(elements)) {
518 Set<Modifier> modifiers = method.getModifiers(); 580 Set<Modifier> modifiers = method.getModifiers();
519 if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) { 581 if (modifiers.contains(Modifier.PRIVATE) || modifiers.contains(Modifier.STATIC)) {
520 continue; 582 continue;
521 } 583 }
584 if (!includeFinals && modifiers.contains(Modifier.FINAL)) {
585 continue;
586 }
587
522 if (!method.getSimpleName().toString().startsWith("execute")) { 588 if (!method.getSimpleName().toString().startsWith("execute")) {
523 continue; 589 continue;
524 } 590 }
525 if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) { 591 if (ElementUtils.findAnnotationMirror(context.getEnvironment(), method, Specialization.class) != null) {
526 continue; 592 continue;
543 609
544 typeData.add(executableType); 610 typeData.add(executableType);
545 } 611 }
546 612
547 Collections.sort(typeData); 613 Collections.sort(typeData);
614
615 List<String> names = new ArrayList<>();
616 for (ExecutableTypeData type : typeData) {
617 names.add(type.getUniqueName());
618 }
619 while (renameDuplicateIds(names)) {
620 // fix point
621 }
622
623 for (int i = 0; i < typeData.size(); i++) {
624 typeData.get(i).setUniqueName(names.get(i));
625 }
626
548 return typeData; 627 return typeData;
549 } 628 }
550 629
551 private void initializeExecutableTypes(NodeData node) { 630 private void initializeExecutableTypes(NodeData node) {
552 List<ExecutableTypeData> allExecutes = node.getExecutableTypes(); 631 List<ExecutableTypeData> allExecutes = node.getExecutableTypes();
580 frameType = context.getType(void.class); 659 frameType = context.getType(void.class);
581 } 660 }
582 661
583 node.setFrameType(frameType); 662 node.setFrameType(frameType);
584 663
585 int totalGenericCount = 0; 664 boolean genericFound = false;
586 int totalVoidCount = 0; 665 for (ExecutableTypeData type : node.getExecutableTypes()) {
587 for (Integer evaluatedCount : evaluatedCounts) { 666 if (!type.hasUnexpectedValue(context)) {
588 List<ExecutableTypeData> genericExecutes = node.findGenericExecutableTypes(context, evaluatedCount); 667 genericFound = true;
589 int genericCount = 0; 668 break;
590 int voidCount = 0; 669 }
591 for (ExecutableTypeData executableTypeData : genericExecutes) {
592 if (!executableTypeData.getMethod().getModifiers().contains(Modifier.FINAL)) {
593 if (ElementUtils.isVoid(executableTypeData.getReturnType())) {
594 voidCount++;
595 } else {
596 genericCount++;
597 }
598 }
599 }
600 // multiple generic execute
601 if (evaluatedCount == 0) {
602 if (voidCount > 1) {
603 List<String> methodSignatures = new ArrayList<>();
604 for (ExecutableTypeData type : genericExecutes) {
605 if (context.isType(type.getReturnType(), void.class)) {
606 methodSignatures.add(ElementUtils.createReferenceName(type.getMethod()));
607 }
608 }
609 node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
610 } else if (genericCount > 1) {
611 List<String> methodSignatures = new ArrayList<>();
612 for (ExecutableTypeData type : genericExecutes) {
613 if (!context.isType(type.getReturnType(), void.class)) {
614 methodSignatures.add(ElementUtils.createReferenceName(type.getMethod()));
615 }
616 }
617 node.addWarning("Multiple accessible and overridable generic execute methods found %s. Remove all but one or mark all but one as final.", methodSignatures);
618 }
619 }
620 totalGenericCount += genericCount;
621 totalVoidCount += voidCount;
622 } 670 }
623 671
624 // no generic executes 672 // no generic executes
625 if (totalGenericCount + totalVoidCount == 0) { 673 if (!genericFound) {
626 node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the " 674 node.addError("No accessible and overridable generic execute method found. Generic execute methods usually have the "
627 + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions."); 675 + "signature 'public abstract {Type} execute(VirtualFrame)' and must not throw any checked exceptions.");
628 } 676 }
629 677
630 int nodeChildDeclarations = 0; 678 int nodeChildDeclarations = 0;
654 for (NodeChildData child : node.getChildren()) { 702 for (NodeChildData child : node.getChildren()) {
655 child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods."); 703 child.addError("Unnecessary @NodeChild declaration. All evaluated child values are provided as parameters in execute methods.");
656 } 704 }
657 } 705 }
658 706
659 }
660
661 private static Map<Integer, List<ExecutableTypeData>> groupExecutableTypes(List<ExecutableTypeData> executableTypes) {
662 Map<Integer, List<ExecutableTypeData>> groupedTypes = new TreeMap<>();
663 for (ExecutableTypeData type : executableTypes) {
664 int evaluatedCount = type.getEvaluatedCount();
665
666 List<ExecutableTypeData> types = groupedTypes.get(evaluatedCount);
667 if (types == null) {
668 types = new ArrayList<>();
669 groupedTypes.put(evaluatedCount, types);
670 }
671 types.add(type);
672 }
673
674 for (List<ExecutableTypeData> types : groupedTypes.values()) {
675 Collections.sort(types);
676 }
677 return groupedTypes;
678 } 707 }
679 708
680 private void initializeChildren(NodeData node) { 709 private void initializeChildren(NodeData node) {
681 initializeExecuteWith(node); 710 initializeExecuteWith(node);
682 711
757 } 786 }
758 List<TypeMirror> frameTypes = Collections.emptyList(); 787 List<TypeMirror> frameTypes = Collections.emptyList();
759 if (parentNode.getFrameType() != null) { 788 if (parentNode.getFrameType() != null) {
760 frameTypes = Arrays.asList(parentNode.getFrameType()); 789 frameTypes = Arrays.asList(parentNode.getFrameType());
761 } 790 }
762 node.setExecutableTypes(groupExecutableTypes(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes))); 791 node.getExecutableTypes().addAll(parseExecutableTypeData(members, child.getExecuteWith().size(), frameTypes, true));
763 node.setFrameType(parentNode.getFrameType()); 792 node.setFrameType(parentNode.getFrameType());
764 return node; 793 return node;
765 } 794 }
766 795
767 private List<TypeMirror> createAllowedChildFrameTypes(NodeData parentNode) { 796 private List<TypeMirror> createAllowedChildFrameTypes(NodeData parentNode) {
1257 NodeExecutionData execution = spec.getExecution(); 1286 NodeExecutionData execution = spec.getExecution();
1258 Collection<TypeMirror> allowedTypes; 1287 Collection<TypeMirror> allowedTypes;
1259 if (execution == null) { 1288 if (execution == null) {
1260 allowedTypes = spec.getAllowedTypes(); 1289 allowedTypes = spec.getAllowedTypes();
1261 } else { 1290 } else {
1262 allowedTypes = node.getPossibleTypes(execution); 1291 allowedTypes = node.getGenericTypes(execution);
1263 } 1292 }
1264 if (allowedTypes.size() == 1) { 1293 if (allowedTypes.size() == 1) {
1265 return allowedTypes.iterator().next(); 1294 return allowedTypes.iterator().next();
1266 } else { 1295 } else {
1267 return ElementUtils.getCommonSuperType(context, allowedTypes.toArray(new TypeMirror[allowedTypes.size()])); 1296 return ElementUtils.getCommonSuperType(context, allowedTypes.toArray(new TypeMirror[allowedTypes.size()]));
1299 return; 1328 return;
1300 } 1329 }
1301 1330
1302 SpecializationData generic = node.getGenericSpecialization(); 1331 SpecializationData generic = node.getGenericSpecialization();
1303 1332
1304 List<TypeMirror> polymorphicSignature = new ArrayList<>(); 1333 List<VariableElement> types = new ArrayList<>();
1305 List<Parameter> updatePolymorphic = Arrays.asList(); 1334
1306 for (Parameter genericParameter : updatePolymorphic) { 1335 Set<TypeMirror> frameTypes = new HashSet<>();
1336 for (SpecializationData specialization : node.getSpecializations()) {
1337 if (specialization.getFrame() != null) {
1338 frameTypes.add(specialization.getFrame().getType());
1339 }
1340 }
1341 if (!frameTypes.isEmpty()) {
1342 TypeMirror frameType;
1343 if (frameTypes.size() == 1) {
1344 frameType = frameTypes.iterator().next();
1345 } else {
1346 frameType = context.getType(Frame.class);
1347 }
1348 types.add(new CodeVariableElement(frameType, "frameValue"));
1349 }
1350
1351 TypeMirror returnType = null;
1352 int index = 0;
1353 for (Parameter genericParameter : generic.getReturnTypeAndParameters()) {
1354 TypeMirror polymorphicType;
1307 if (!genericParameter.getSpecification().isSignature()) { 1355 if (!genericParameter.getSpecification().isSignature()) {
1308 continue; 1356 polymorphicType = genericParameter.getType();
1309 }
1310
1311 Set<TypeMirror> usedTypes = new HashSet<>();
1312 for (SpecializationData specialization : node.getSpecializations()) {
1313 if (!specialization.isSpecialized()) {
1314 continue;
1315 }
1316 Parameter parameter = specialization.findParameter(genericParameter.getLocalName());
1317 if (parameter == null) {
1318 throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
1319 }
1320 usedTypes.add(parameter.getType());
1321 }
1322
1323 TypeMirror polymorphicType;
1324 if (usedTypes.size() == 1) {
1325 polymorphicType = usedTypes.iterator().next();
1326 } else { 1357 } else {
1327 polymorphicType = context.getType(Object.class); 1358 Set<TypeMirror> usedTypes = new HashSet<>();
1328 } 1359 for (SpecializationData specialization : node.getSpecializations()) {
1329 polymorphicSignature.add(polymorphicType); 1360 if (specialization.isUninitialized()) {
1330 } 1361 continue;
1331 1362 }
1332 SpecializationData polymorphic = new SpecializationData(node, generic, SpecializationKind.POLYMORPHIC); 1363 Parameter parameter = specialization.findParameter(genericParameter.getLocalName());
1333 polymorphic.updateSignature(new TypeSignature(polymorphicSignature)); 1364 if (parameter == specialization.getReturnType() && specialization.isFallback() && specialization.getMethod() == null) {
1365 continue;
1366 }
1367 if (parameter == null) {
1368 throw new AssertionError("Parameter existed in generic specialization but not in specialized. param = " + genericParameter.getLocalName());
1369 }
1370 usedTypes.add(parameter.getType());
1371 }
1372
1373 if (usedTypes.size() == 1) {
1374 polymorphicType = usedTypes.iterator().next();
1375
1376 if (node.getTypeSystem().hasImplicitSourceTypes(polymorphicType)) {
1377 polymorphicType = context.getType(Object.class);
1378 }
1379 } else {
1380 polymorphicType = context.getType(Object.class);
1381 }
1382 }
1383 if (genericParameter == generic.getReturnType()) {
1384 returnType = polymorphicType;
1385 } else {
1386 types.add(new CodeVariableElement(polymorphicType, "param" + index));
1387 }
1388 index++;
1389 }
1390
1391 SpecializationMethodParser parser = new SpecializationMethodParser(context, node);
1392
1393 SpecializationData polymorphic = parser.create("Polymorphic", TemplateMethod.NO_NATURAL_ORDER, null, null, returnType, types);
1394 polymorphic.setKind(SpecializationKind.POLYMORPHIC);
1334 node.getSpecializations().add(polymorphic); 1395 node.getSpecializations().add(polymorphic);
1335 } 1396 }
1336 1397
1337 private void initializeShortCircuits(NodeData node) { 1398 private void initializeShortCircuits(NodeData node) {
1338 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); 1399 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits());