comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java @ 8245:703c09f8640c

Implemented support for @NodeClass annotation to support builtins.
author Christian Humer <christian.humer@gmail.com>
date Wed, 06 Mar 2013 18:32:33 +0100
parents d81ff782fa1a
children c4c3f50fa9c2
comparison
equal deleted inserted replaced
8244:10d37f893471 8245:703c09f8640c
42 public class NodeParser extends TemplateParser<NodeData> { 42 public class NodeParser extends TemplateParser<NodeData> {
43 43
44 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class); 44 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class);
45 45
46 private Map<String, NodeData> parsedNodes; 46 private Map<String, NodeData> parsedNodes;
47 private TypeElement originalType;
48 47
49 public NodeParser(ProcessorContext c) { 48 public NodeParser(ProcessorContext c) {
50 super(c); 49 super(c);
51 } 50 }
52 51
53 @Override 52 @Override
54 protected NodeData parse(Element element, AnnotationMirror mirror) { 53 protected NodeData parse(Element element, AnnotationMirror mirror) {
55 assert element instanceof TypeElement; 54 assert element instanceof TypeElement;
55 NodeData node = null;
56 try { 56 try {
57 parsedNodes = new HashMap<>(); 57 parsedNodes = new HashMap<>();
58 originalType = (TypeElement) element; 58 node = parseInnerClassHierarchy((TypeElement) element);
59
60 return parseInnerClassHierarchy((TypeElement) element);
61 } finally { 59 } finally {
62 if (Log.DEBUG) {
63 NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType));
64 if (parsed != null) {
65 String dump = parsed.dump();
66 log.error("Node parsed: %s", dump);
67 System.out.println("Parsed: " + dump);
68 }
69 }
70 parsedNodes = null; 60 parsedNodes = null;
71 originalType = null; 61 }
72 } 62 return node;
73 } 63 }
74 64
75 @Override 65 @Override
76 public boolean isDelegateToRootDeclaredType() { 66 public boolean isDelegateToRootDeclaredType() {
77 return true; 67 return true;
86 children.add(childNode); 76 children.add(childNode);
87 } 77 }
88 } 78 }
89 NodeData rootNode = resolveNode(rootType); 79 NodeData rootNode = resolveNode(rootType);
90 if (rootNode == null && children.size() > 0) { 80 if (rootNode == null && children.size() > 0) {
91 rootNode = new NodeData(rootType, null); 81 rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString());
92 } 82 }
93 if (rootNode != null) { 83 if (rootNode != null) {
84 children.addAll(rootNode.getDeclaredChildren());
94 rootNode.setDeclaredChildren(children); 85 rootNode.setDeclaredChildren(children);
95 } 86 }
96 87
97 return rootNode; 88 return rootNode;
98 } 89 }
102 if (!parsedNodes.containsKey(typeName)) { 93 if (!parsedNodes.containsKey(typeName)) {
103 NodeData node = parseNode(currentType); 94 NodeData node = parseNode(currentType);
104 if (node != null) { 95 if (node != null) {
105 parsedNodes.put(typeName, node); 96 parsedNodes.put(typeName, node);
106 } 97 }
98
99 if (Log.DEBUG) {
100 NodeData parsed = parsedNodes.get(Utils.getQualifiedName(currentType));
101 if (parsed != null) {
102 String dump = parsed.dump();
103 String valid = node != null ? "" : " failed";
104 String msg = String.format("Node parsing %s : %s", valid, dump);
105 log.error(msg);
106 System.out.println(msg);
107 }
108 }
109
107 return node; 110 return node;
108 } 111 }
109 return parsedNodes.get(typeName); 112 return parsedNodes.get(typeName);
110 } 113 }
111 114
119 122
120 if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) { 123 if (methodNodes == null && !Utils.isAssignable(type.asType(), context.getTruffleTypes().getNode())) {
121 return null; // not a node 124 return null; // not a node
122 } 125 }
123 126
127 TypeElement nodeType;
128 boolean needsSplit;
129 if (methodNodes != null) {
130 needsSplit = methodNodes != null;
131 nodeType = Utils.fromTypeMirror(Utils.getAnnotationValueType(methodNodes, "value"));
132 } else {
133 needsSplit = false;
134 nodeType = type;
135 }
136
124 if (type.getModifiers().contains(Modifier.PRIVATE)) { 137 if (type.getModifiers().contains(Modifier.PRIVATE)) {
125 return null; // not visible 138 return null; // not visible
126 } 139 }
127 140
128 final NodeData nodeData = parseNodeData(type); 141 NodeData nodeData = parseNodeData(type, nodeType);
129 if (nodeData == null) { 142 if (nodeData == null) {
130 // TODO error message for instanceBaseClass?
131 return null; 143 return null;
132 } 144 }
133 145
134 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); 146 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type));
135 nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements)); 147 nodeData.setExtensionElements(getExtensionParser().parseAll(type, elements));
138 } 150 }
139 151
140 if (!parseMethods(nodeData, elements)) { 152 if (!parseMethods(nodeData, elements)) {
141 return null; 153 return null;
142 } 154 }
143 // TODO split 155
144 156 List<NodeData> nodes;
145 if (!finalizeSpecializations(nodeData)) { 157 if (needsSplit) {
158 nodes = splitNodeData(nodeData);
159 if (nodes == null) {
160 return null;
161 }
162 } else {
163 nodes = new ArrayList<>();
164 nodes.add(nodeData);
165 }
166
167 boolean valid = true;
168 for (NodeData splittedNode : nodes) {
169 if (!finalizeSpecializations(splittedNode)) {
170 valid = false;
171 }
172 if (!verifyNode(splittedNode)) {
173 valid = false;
174 }
175 }
176 if (!valid) {
146 return null; 177 return null;
147 } 178 }
148 179
149 if (!verifyNode(nodeData)) { 180 if (needsSplit) {
150 return null; 181 nodeData.setDeclaredChildren(nodes);
151 } 182 nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
152 183 nodeData.setSpecializations(new ArrayList<SpecializationData>());
153 return nodeData; 184 return nodeData;
185 } else {
186 return nodeData;
187 }
188 }
189
190 private static List<NodeData> splitNodeData(NodeData node) {
191 SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations());
192 SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners());
193
194 Set<String> ids = new TreeSet<>();
195 ids.addAll(groupedSpecializations.keySet());
196 ids.addAll(groupedListeners.keySet());
197
198 List<NodeData> splitted = new ArrayList<>();
199 for (String id : ids) {
200 List<SpecializationData> specializations = groupedSpecializations.get(id);
201 List<SpecializationListenerData> listeners = groupedListeners.get(id);
202
203 if (specializations == null) {
204 specializations = new ArrayList<>();
205 }
206
207 if (listeners == null) {
208 listeners = new ArrayList<>();
209 }
210
211 String nodeId = node.getNodeId();
212 if (nodeId.endsWith("Node") && !nodeId.equals("Node")) {
213 nodeId = nodeId.substring(0, nodeId.length() - 4);
214 }
215 String newNodeId = nodeId + Utils.firstLetterUpperCase(id);
216 NodeData copy = new NodeData(node, newNodeId);
217
218 copy.setSpecializations(specializations);
219 copy.setSpecializationListeners(listeners);
220
221 splitted.add(copy);
222 }
223
224 if (splitted.isEmpty()) {
225 splitted.add(node);
226 }
227
228 node.setSpecializations(new ArrayList<SpecializationData>());
229 node.setSpecializationListeners(new ArrayList<SpecializationListenerData>());
230
231 return splitted;
232 }
233
234 private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) {
235 SortedMap<String, List<M>> grouped = new TreeMap<>();
236 for (M m : methods) {
237 List<M> list = grouped.get(m.getId());
238 if (list == null) {
239 list = new ArrayList<>();
240 grouped.put(m.getId(), list);
241 }
242 list.add(m);
243 }
244 return grouped;
154 } 245 }
155 246
156 private boolean parseMethods(final NodeData node, List<Element> elements) { 247 private boolean parseMethods(final NodeData node, List<Element> elements) {
157 node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements)); 248 node.setGuards(new GuardParser(context, node, node.getTypeSystem()).parse(elements));
158 node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements)); 249 node.setShortCircuits(new ShortCircuitParser(context, node).parse(elements));
174 } 265 }
175 266
176 private boolean finalizeSpecializations(final NodeData node) { 267 private boolean finalizeSpecializations(final NodeData node) {
177 List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); 268 List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations());
178 269
270 if (specializations.isEmpty()) {
271 return true;
272 }
273
179 List<SpecializationData> generics = new ArrayList<>(); 274 List<SpecializationData> generics = new ArrayList<>();
180 for (SpecializationData spec : specializations) { 275 for (SpecializationData spec : specializations) {
181 if (spec.isGeneric()) { 276 if (spec.isGeneric()) {
182 generics.add(spec); 277 generics.add(spec);
183 } 278 }
189 log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); 284 log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName());
190 } 285 }
191 return false; 286 return false;
192 } else if (generics.size() == 1) { 287 } else if (generics.size() == 1) {
193 genericSpecialization = generics.get(0); 288 genericSpecialization = generics.get(0);
289 } else {
290 // TODO support generation of generic if not ambiguous.
194 } 291 }
195 292
196 if (specializations.size() > 1 && genericSpecialization == null) { 293 if (specializations.size() > 1 && genericSpecialization == null) {
197 log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName()); 294 log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName());
198 return false; 295 return false;
213 } 310 }
214 }); 311 });
215 312
216 node.setSpecializations(specializations); 313 node.setSpecializations(specializations);
217 314
315 for (SpecializationData specialization : specializations) {
316 specialization.setId(findUniqueSpecializationId(specialization));
317 }
318
218 return true; 319 return true;
320 }
321
322 private static String findUniqueSpecializationId(SpecializationData specialization) {
323
324 String name;
325 if (specialization.isGeneric()) {
326 name = "Generic";
327 } else if (specialization.isUninitialized()) {
328 name = "Uninitialized";
329 } else {
330 List<SpecializationData> specializations = new ArrayList<>(specialization.getNode().getSpecializations());
331 for (ListIterator<SpecializationData> iterator = specializations.listIterator(); iterator.hasNext();) {
332 SpecializationData data = iterator.next();
333 if (data.isGeneric() || data.isUninitialized()) {
334 iterator.remove();
335 }
336 }
337
338 Map<ParameterSpec, Set<String>> usedIds = new HashMap<>();
339 for (SpecializationData other : specializations) {
340 for (ActualParameter param : other.getReturnTypeAndParameters()) {
341 if (other.getNode().findField(param.getSpecification().getName()) == null) {
342 continue;
343 }
344
345 Set<String> types = usedIds.get(param.getSpecification());
346 if (types == null) {
347 types = new HashSet<>();
348 usedIds.put(param.getSpecification(), types);
349 }
350 types.add(Utils.getTypeId(param.getActualType()));
351 }
352 }
353
354 List<ParameterSpec> ambiguousSpecs = new ArrayList<>();
355 for (ActualParameter param : specialization.getReturnTypeAndParameters()) {
356 Set<String> ids = usedIds.get(param.getSpecification());
357 if (ids != null && ids.size() > 1) {
358 ambiguousSpecs.add(param.getSpecification());
359 }
360 }
361
362 String specializationId = findSpecializationId(specialization, ambiguousSpecs);
363 int specializationIndex = 0;
364 int totalIndex = 0;
365
366 for (SpecializationData other : specializations) {
367 String id = findSpecializationId(other, ambiguousSpecs);
368 if (id.equals(specializationId)) {
369 totalIndex++;
370 if (specialization == other) {
371 specializationIndex = totalIndex;
372 }
373 }
374 }
375
376 if (specializationIndex != totalIndex) {
377 name = specializationId + specializationIndex;
378 } else {
379 name = specializationId;
380 }
381 }
382 return name;
383 }
384
385 private static String findSpecializationId(SpecializationData specialization, List<ParameterSpec> specs) {
386 boolean allSame = true;
387 ActualParameter prevParam = specialization.getReturnType();
388 for (ParameterSpec spec : specs) {
389 ActualParameter param = specialization.findParameter(spec);
390 if (!Utils.typeEquals(prevParam.getActualType(), param.getActualType())) {
391 allSame = false;
392 break;
393 }
394 prevParam = param;
395 }
396
397 if (allSame) {
398 return Utils.getTypeId(prevParam.getActualType());
399 } else {
400 StringBuilder nameBuilder = new StringBuilder();
401 nameBuilder.append(Utils.getTypeId(prevParam.getActualType()));
402 for (ParameterSpec spec : specs) {
403 ActualParameter param = specialization.findParameter(spec);
404 nameBuilder.append(Utils.getTypeId(param.getActualType()));
405 }
406 return nameBuilder.toString();
407 }
219 } 408 }
220 409
221 private boolean verifyNode(NodeData nodeData) { 410 private boolean verifyNode(NodeData nodeData) {
222 // verify specialization parameter length 411 // verify specialization parameter length
223 if (!verifySpecializationParameters(nodeData)) { 412 if (!verifySpecializationParameters(nodeData)) {
258 } 447 }
259 448
260 return true; 449 return true;
261 } 450 }
262 451
263 private NodeData parseNodeData(TypeElement type) { 452 private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) {
264 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); 453 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType));
265 List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), type); 454 List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType);
266 Collections.reverse(typeHierarchy); 455 Collections.reverse(typeHierarchy);
267 456
268 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); 457 AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class);
269 if (typeSystemMirror == null) { 458 if (typeSystemMirror == null) {
270 log.error(type, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), type.getQualifiedName().toString()); 459 log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString());
271 return null; 460 return null;
272 } 461 }
273 462
274 TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); 463 TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value");
275 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); 464 final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true);
276 if (typeSystem == null) { 465 if (typeSystem == null) {
277 log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); 466 log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType));
278 return null; 467 return null;
279 } 468 }
280 469
281 NodeData nodeData = new NodeData(type, typeSystem); 470 String nodeId = templateType.getSimpleName().toString();
471 if (nodeId.endsWith("Node") && !nodeId.equals("Node")) {
472 nodeId = nodeId.substring(0, nodeId.length() - 4);
473 }
474
475 NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString());
476 nodeData.setNodeType(nodeType.asType());
282 477
283 List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); 478 List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements));
284 479
285 nodeData.setExecutableTypes(executableTypes); 480 nodeData.setExecutableTypes(executableTypes);
286 481
287 parsedNodes.put(Utils.getQualifiedName(type), nodeData); 482 parsedNodes.put(Utils.getQualifiedName(nodeType), nodeData);
288 483
289 List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy); 484 List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy);
290 if (fields == null) { 485 if (fields == null) {
291 return null; 486 return null;
292 } 487 }
293 nodeData.setFields(fields); 488 nodeData.setFields(fields);
489
490 if (!Utils.isAssignable(templateType.asType(), nodeType.asType())) {
491 // nodeData.setInstanceParameterSpec(new ParameterSpec("instance", templateType.asType(), false,
492 // true));
493 }
494
294 return nodeData; 495 return nodeData;
295 } 496 }
296 497
297 private boolean verifySpecializationParameters(NodeData nodeData) { 498 private boolean verifySpecializationParameters(NodeData nodeData) {
298 boolean valid = true; 499 boolean valid = true;
667 } 868 }
668 } 869 }
669 return valid; 870 return valid;
670 } 871 }
671 872
873 @SuppressWarnings("unused")
672 private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) { 874 private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) {
673 boolean valid = true; 875 boolean valid = true;
674 for (int i = 0; i < methods.size(); i++) { 876 for (int i = 0; i < methods.size(); i++) {
675 TemplateMethod m1 = methods.get(i); 877 TemplateMethod m1 = methods.get(i);
676 for (int j = i + 1; j < methods.size(); j++) { 878 for (int j = i + 1; j < methods.size(); j++) {
768 } 970 }
769 return true; 971 return true;
770 } 972 }
771 973
772 private boolean verifySpecializationThrows(NodeData node) { 974 private boolean verifySpecializationThrows(NodeData node) {
773 TypeSystemData typeSystem = node.getTypeSystem();
774
775 Map<String, SpecializationData> specializationMap = new HashMap<>(); 975 Map<String, SpecializationData> specializationMap = new HashMap<>();
776 for (SpecializationData spec : node.getSpecializations()) { 976 for (SpecializationData spec : node.getSpecializations()) {
777 specializationMap.put(spec.getMethodName(), spec); 977 specializationMap.put(spec.getMethodName(), spec);
778 } 978 }
779 boolean valid = true; 979 boolean valid = true;