Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeParser.java @ 13527:25ecb47a6d0e
Truffle-DSL: Added support for references to child arrays in @ShortCircuit;
Introduced new layer NodeExecutionData to the implementation model which is in between NodeChildData and the actual parameters..
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 07 Jan 2014 12:22:47 +0100 |
parents | 2b9fcffd6f36 |
children | 5a0c694ef735 |
comparison
equal
deleted
inserted
replaced
13483:37ec2cabf397 | 13527:25ecb47a6d0e |
---|---|
32 | 32 |
33 import com.oracle.truffle.api.dsl.*; | 33 import com.oracle.truffle.api.dsl.*; |
34 import com.oracle.truffle.api.nodes.*; | 34 import com.oracle.truffle.api.nodes.*; |
35 import com.oracle.truffle.dsl.processor.*; | 35 import com.oracle.truffle.dsl.processor.*; |
36 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; | 36 import com.oracle.truffle.dsl.processor.node.NodeChildData.Cardinality; |
37 import com.oracle.truffle.dsl.processor.node.NodeChildData.ExecutionKind; | |
38 import com.oracle.truffle.dsl.processor.template.*; | 37 import com.oracle.truffle.dsl.processor.template.*; |
39 import com.oracle.truffle.dsl.processor.template.TemplateMethod.Signature; | 38 import com.oracle.truffle.dsl.processor.template.TemplateMethod.TypeSignature; |
40 import com.oracle.truffle.dsl.processor.typesystem.*; | 39 import com.oracle.truffle.dsl.processor.typesystem.*; |
41 | 40 |
42 public class NodeParser extends TemplateParser<NodeData> { | 41 public class NodeParser extends TemplateParser<NodeData> { |
43 | 42 |
44 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, | 43 public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class, |
203 splittedNode.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); | 202 splittedNode.addError("Classes containing a @%s annotation must not be private.", Specialization.class.getSimpleName()); |
204 } | 203 } |
205 | 204 |
206 finalizeSpecializations(elements, splittedNode); | 205 finalizeSpecializations(elements, splittedNode); |
207 verifyNode(splittedNode, elements); | 206 verifyNode(splittedNode, elements); |
208 expandExecutableTypeVarArgs(splittedNode); | |
209 createPolymorphicSpecializations(splittedNode); | 207 createPolymorphicSpecializations(splittedNode); |
210 assignShortCircuitsToSpecializations(splittedNode); | 208 assignShortCircuitsToSpecializations(splittedNode); |
211 } | 209 } |
212 | 210 |
213 if (node.isNodeContainer()) { | 211 if (node.isNodeContainer()) { |
214 node.setDeclaredNodes(nodes); | 212 node.setDeclaredNodes(nodes); |
215 node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); | 213 node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); |
216 node.setSpecializations(new ArrayList<SpecializationData>()); | 214 node.setSpecializations(new ArrayList<SpecializationData>()); |
217 } | 215 } |
218 return node; | 216 return node; |
219 } | |
220 | |
221 private static void expandExecutableTypeVarArgs(NodeData node) { | |
222 for (ExecutableTypeData executableMethod : node.getExecutableTypes()) { | |
223 if (!(executableMethod.getMethod().isVarArgs() && executableMethod.getSpecification().isVariableRequiredArguments())) { | |
224 continue; | |
225 } | |
226 int expandArguments = node.getSignatureSize() - executableMethod.getSignatureSize(); | |
227 if (expandArguments > 0) { | |
228 int signatureSize = executableMethod.getSignatureSize(); | |
229 ActualParameter parameter = executableMethod.getSignatureParameter(signatureSize - 1); | |
230 for (int i = 0; i < expandArguments; i++) { | |
231 int newVarArgsIndex = parameter.getVarArgsIndex() + i + 1; | |
232 int newSpecificationIndex = parameter.getSpecificationIndex() + i + 1; | |
233 executableMethod.getParameters().add( | |
234 new ActualParameter(parameter.getSpecification(), parameter.getTypeSystemType(), newSpecificationIndex, newVarArgsIndex, parameter.isImplicit())); | |
235 } | |
236 | |
237 } | |
238 } | |
239 } | 217 } |
240 | 218 |
241 private void createPolymorphicSpecializations(NodeData node) { | 219 private void createPolymorphicSpecializations(NodeData node) { |
242 if (!node.needsRewrites(context) || !node.isPolymorphic()) { | 220 if (!node.needsRewrites(context) || !node.isPolymorphic()) { |
243 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); | 221 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); |
275 } | 253 } |
276 polymorphicSignature.add(polymorphicType); | 254 polymorphicSignature.add(polymorphicType); |
277 } | 255 } |
278 | 256 |
279 SpecializationData specialization = new SpecializationData(generic, false, false, true); | 257 SpecializationData specialization = new SpecializationData(generic, false, false, true); |
280 specialization.updateSignature(new Signature(polymorphicSignature)); | 258 specialization.updateSignature(new TypeSignature(polymorphicSignature)); |
281 specialization.setNode(node); | 259 specialization.setNode(node); |
282 node.setGenericPolymorphicSpecialization(specialization); | 260 node.setGenericPolymorphicSpecialization(specialization); |
283 // TODO remove polymoprhic specializations | 261 // TODO remove polymoprhic specializations |
284 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); | 262 node.setPolymorphicSpecializations(Collections.<SpecializationData> emptyList()); |
285 } | 263 } |
334 AnnotationMirror nodeContainer = findFirstAnnotation(typeHierarchy, NodeContainer.class); | 312 AnnotationMirror nodeContainer = findFirstAnnotation(typeHierarchy, NodeContainer.class); |
335 nodeData.setNodeContainer(nodeContainer != null); | 313 nodeData.setNodeContainer(nodeContainer != null); |
336 nodeData.setTypeSystem(typeSystem); | 314 nodeData.setTypeSystem(typeSystem); |
337 nodeData.setFields(parseFields(typeHierarchy, elements)); | 315 nodeData.setFields(parseFields(typeHierarchy, elements)); |
338 nodeData.setChildren(parseChildren(nodeData, elements, typeHierarchy)); | 316 nodeData.setChildren(parseChildren(nodeData, elements, typeHierarchy)); |
317 nodeData.setChildExecutions(parseDefaultSignature(nodeData, elements)); | |
339 nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); | 318 nodeData.setExecutableTypes(groupExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements))); |
340 | 319 |
341 // resolveChildren invokes cyclic parsing. | 320 // resolveChildren invokes cyclic parsing. |
342 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); | 321 parsedNodes.put(Utils.getQualifiedName(templateType), nodeData); |
343 resolveChildren(nodeData); | 322 resolveChildren(nodeData); |
344 | 323 |
345 return nodeData; | 324 return nodeData; |
325 } | |
326 | |
327 private List<NodeExecutionData> parseDefaultSignature(NodeData node, List<? extends Element> elements) { | |
328 if (node.getChildren() == null) { | |
329 return null; | |
330 } | |
331 | |
332 // pre-parse short circuits | |
333 Set<String> shortCircuits = new HashSet<>(); | |
334 List<ExecutableElement> methods = ElementFilter.methodsIn(elements); | |
335 for (ExecutableElement method : methods) { | |
336 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, ShortCircuit.class); | |
337 if (mirror != null) { | |
338 shortCircuits.add(Utils.getAnnotationValue(String.class, mirror, "value")); | |
339 } | |
340 } | |
341 | |
342 boolean hasVarArgs = false; | |
343 int maxSignatureSize = 0; | |
344 if (!node.getChildren().isEmpty()) { | |
345 int lastIndex = node.getChildren().size() - 1; | |
346 hasVarArgs = node.getChildren().get(lastIndex).getCardinality() == Cardinality.MANY; | |
347 if (hasVarArgs) { | |
348 maxSignatureSize = lastIndex; | |
349 } else { | |
350 maxSignatureSize = node.getChildren().size(); | |
351 } | |
352 } | |
353 | |
354 // pre-parse specializations | |
355 for (ExecutableElement method : methods) { | |
356 AnnotationMirror mirror = Utils.findAnnotationMirror(processingEnv, method, Specialization.class); | |
357 if (mirror == null) { | |
358 continue; | |
359 } | |
360 | |
361 int currentArgumentCount = 0; | |
362 boolean skipShortCircuit = false; | |
363 for (VariableElement var : method.getParameters()) { | |
364 TypeMirror type = var.asType(); | |
365 if (currentArgumentCount == 0) { | |
366 // skip optionals | |
367 if (Utils.typeEquals(type, context.getTruffleTypes().getFrame())) { | |
368 continue; | |
369 } | |
370 // TODO skip optional fields? | |
371 } | |
372 int childIndex = currentArgumentCount < node.getChildren().size() ? currentArgumentCount : node.getChildren().size() - 1; | |
373 if (childIndex == -1) { | |
374 continue; | |
375 } | |
376 if (!skipShortCircuit) { | |
377 NodeChildData child = node.getChildren().get(childIndex); | |
378 if (shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, currentArgumentCount - childIndex))) { | |
379 skipShortCircuit = true; | |
380 continue; | |
381 } | |
382 } else { | |
383 skipShortCircuit = false; | |
384 } | |
385 | |
386 currentArgumentCount++; | |
387 } | |
388 maxSignatureSize = Math.max(maxSignatureSize, currentArgumentCount); | |
389 } | |
390 | |
391 List<NodeExecutionData> executions = new ArrayList<>(); | |
392 for (int i = 0; i < maxSignatureSize; i++) { | |
393 int childIndex = i; | |
394 boolean varArg = false; | |
395 if (childIndex >= node.getChildren().size() - 1) { | |
396 if (hasVarArgs) { | |
397 childIndex = node.getChildren().size() - 1; | |
398 varArg = hasVarArgs; | |
399 } else if (childIndex >= node.getChildren().size()) { | |
400 break; | |
401 } | |
402 } | |
403 int varArgsIndex = varArg ? Math.abs(childIndex - i) : -1; | |
404 NodeChildData child = node.getChildren().get(childIndex); | |
405 boolean shortCircuit = shortCircuits.contains(NodeExecutionData.createShortCircuitId(child, varArgsIndex)); | |
406 executions.add(new NodeExecutionData(child, varArgsIndex, shortCircuit)); | |
407 } | |
408 return executions; | |
346 } | 409 } |
347 | 410 |
348 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) { | 411 private List<NodeFieldData> parseFields(List<TypeElement> typeHierarchy, List<? extends Element> elements) { |
349 Set<String> names = new HashSet<>(); | 412 Set<String> names = new HashSet<>(); |
350 | 413 |
468 childType = castNodeType; | 531 childType = castNodeType; |
469 } | 532 } |
470 | 533 |
471 Element getter = findGetter(elements, name, childType); | 534 Element getter = findGetter(elements, name, childType); |
472 | 535 |
473 ExecutionKind kind = ExecutionKind.DEFAULT; | 536 NodeChildData nodeChild = new NodeChildData(parent, type, childMirror, name, childType, originalChildType, getter, cardinality); |
474 if (shortCircuits.contains(name)) { | |
475 kind = ExecutionKind.SHORT_CIRCUIT; | |
476 } | |
477 | |
478 NodeChildData nodeChild = new NodeChildData(parent, type, childMirror, name, childType, originalChildType, getter, cardinality, kind); | |
479 | 537 |
480 parsedChildren.add(nodeChild); | 538 parsedChildren.add(nodeChild); |
481 | 539 |
482 verifyNodeChild(nodeChild); | 540 verifyNodeChild(nodeChild); |
483 if (nodeChild.hasErrors()) { | 541 if (nodeChild.hasErrors()) { |
725 node.setPolymorphicDepth(1); | 783 node.setPolymorphicDepth(1); |
726 } | 784 } |
727 } | 785 } |
728 | 786 |
729 private SpecializationData createGenericSpecialization(final NodeData node, List<SpecializationData> specializations) { | 787 private SpecializationData createGenericSpecialization(final NodeData node, List<SpecializationData> specializations) { |
730 SpecializationData genericSpecialization; | |
731 SpecializationData specialization = specializations.get(0); | 788 SpecializationData specialization = specializations.get(0); |
732 GenericParser parser = new GenericParser(context, node); | 789 GenericParser parser = new GenericParser(context, node); |
733 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); | 790 MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, true, null); |
734 | 791 specification.getImplicitRequiredTypes().clear(); |
735 List<ActualParameter> parameters = new ArrayList<>(); | 792 |
736 for (ActualParameter parameter : specialization.getReturnTypeAndParameters()) { | 793 List<TypeMirror> parameterTypes = new ArrayList<>(); |
737 if (!parameter.getSpecification().isSignature()) { | 794 int signatureIndex = 1; |
738 parameters.add(new ActualParameter(parameter)); | 795 for (ParameterSpec spec : specification.getRequired()) { |
739 continue; | 796 parameterTypes.add(createGenericType(spec, specializations, signatureIndex)); |
740 } | 797 if (spec.isSignature()) { |
741 NodeData childNode = node; | 798 signatureIndex++; |
742 NodeChildData child = node.findChild(parameter.getSpecification().getName()); | 799 } |
743 if (child != null) { | 800 } |
744 childNode = child.getNodeData(); | 801 TypeMirror returnType = createGenericType(specification.getReturnType(), specializations, 0); |
745 } | 802 return parser.create("Generic", null, null, returnType, parameterTypes); |
803 } | |
804 | |
805 private TypeMirror createGenericType(ParameterSpec spec, List<SpecializationData> specializations, int signatureIndex) { | |
806 NodeExecutionData execution = spec.getExecution(); | |
807 if (execution == null) { | |
808 if (spec.getAllowedTypes().size() == 1) { | |
809 return spec.getAllowedTypes().get(0); | |
810 } else { | |
811 return Utils.getCommonSuperType(context, spec.getAllowedTypes().toArray(new TypeMirror[0])); | |
812 } | |
813 } else { | |
814 Set<TypeData> types = new HashSet<>(); | |
815 for (SpecializationData specialization : specializations) { | |
816 types.add(specialization.getTypeSignature().get(signatureIndex)); | |
817 } | |
818 | |
819 NodeChildData child = execution.getChild(); | |
746 | 820 |
747 TypeData genericType = null; | 821 TypeData genericType = null; |
748 | |
749 Set<TypeData> types = new HashSet<>(); | |
750 for (SpecializationData otherSpecialization : specializations) { | |
751 ActualParameter otherParameter = otherSpecialization.findParameter(parameter.getLocalName()); | |
752 if (otherParameter != null) { | |
753 types.add(otherParameter.getTypeSystemType()); | |
754 } | |
755 } | |
756 | |
757 assert !types.isEmpty(); | |
758 | |
759 if (types.size() == 1) { | 822 if (types.size() == 1) { |
760 ExecutableTypeData executable = childNode.findExecutableType(types.iterator().next(), 0); | 823 ExecutableTypeData executable = child.findExecutableType(context, types.iterator().next()); |
761 if (executable != null && !executable.hasUnexpectedValue(context)) { | 824 if (executable != null && !executable.hasUnexpectedValue(context)) { |
762 genericType = types.iterator().next(); | 825 genericType = types.iterator().next(); |
763 } else { | 826 } |
764 genericType = childNode.findAnyGenericExecutableType(context, 0).getType(); | 827 } |
765 } | 828 if (genericType == null) { |
766 } else { | 829 genericType = child.findAnyGenericExecutableType(context).getType(); |
767 genericType = childNode.findAnyGenericExecutableType(context, 0).getType(); | 830 } |
768 } | 831 return genericType.getPrimitiveType(); |
769 | 832 } |
770 parameters.add(new ActualParameter(parameter, genericType)); | |
771 } | |
772 ActualParameter returnType = parameters.get(0); | |
773 parameters = parameters.subList(1, parameters.size()); | |
774 | |
775 TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters); | |
776 genericSpecialization = new SpecializationData(genericMethod, true, false, false); | |
777 return genericSpecialization; | |
778 } | 833 } |
779 | 834 |
780 private void assignShortCircuitsToSpecializations(NodeData node) { | 835 private void assignShortCircuitsToSpecializations(NodeData node) { |
781 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); | 836 Map<String, List<ShortCircuitData>> groupedShortCircuits = groupShortCircuits(node.getShortCircuits()); |
782 | 837 |
783 boolean valid = true; | 838 boolean valid = true; |
784 for (NodeChildData field : node.filterFields(ExecutionKind.SHORT_CIRCUIT)) { | 839 List<NodeExecutionData> shortCircuitExecutions = new ArrayList<>(); |
785 String valueName = field.getName(); | 840 for (NodeExecutionData execution : node.getChildExecutions()) { |
841 if (!execution.isShortCircuit()) { | |
842 continue; | |
843 } | |
844 shortCircuitExecutions.add(execution); | |
845 String valueName = execution.getShortCircuitId(); | |
786 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); | 846 List<ShortCircuitData> availableCircuits = groupedShortCircuits.get(valueName); |
787 | 847 |
788 if (availableCircuits == null || availableCircuits.isEmpty()) { | 848 if (availableCircuits == null || availableCircuits.isEmpty()) { |
789 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); | 849 node.addError("@%s method for short cut value '%s' required.", ShortCircuit.class.getSimpleName(), valueName); |
790 valid = false; | 850 valid = false; |
807 continue; | 867 continue; |
808 } | 868 } |
809 | 869 |
810 ShortCircuitData genericCircuit = null; | 870 ShortCircuitData genericCircuit = null; |
811 for (ShortCircuitData circuit : availableCircuits) { | 871 for (ShortCircuitData circuit : availableCircuits) { |
812 if (isGenericShortCutMethod(node, circuit)) { | 872 if (isGenericShortCutMethod(circuit)) { |
813 genericCircuit = circuit; | 873 genericCircuit = circuit; |
814 break; | 874 break; |
815 } | 875 } |
816 } | 876 } |
817 | 877 |
830 | 890 |
831 if (!valid) { | 891 if (!valid) { |
832 return; | 892 return; |
833 } | 893 } |
834 | 894 |
835 NodeChildData[] fields = node.filterFields(ExecutionKind.SHORT_CIRCUIT); | |
836 List<SpecializationData> specializations = new ArrayList<>(); | 895 List<SpecializationData> specializations = new ArrayList<>(); |
837 specializations.addAll(node.getSpecializations()); | 896 specializations.addAll(node.getSpecializations()); |
838 specializations.addAll(node.getPolymorphicSpecializations()); | 897 specializations.addAll(node.getPolymorphicSpecializations()); |
839 | 898 |
840 for (SpecializationData specialization : specializations) { | 899 for (SpecializationData specialization : specializations) { |
841 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(fields.length); | 900 List<ShortCircuitData> assignedShortCuts = new ArrayList<>(shortCircuitExecutions.size()); |
842 | 901 |
843 for (int i = 0; i < fields.length; i++) { | 902 for (NodeExecutionData shortCircuit : shortCircuitExecutions) { |
844 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(fields[i].getName()); | 903 List<ShortCircuitData> availableShortCuts = groupedShortCircuits.get(shortCircuit.getShortCircuitId()); |
845 | 904 |
846 ShortCircuitData genericShortCircuit = null; | 905 ShortCircuitData genericShortCircuit = null; |
847 ShortCircuitData compatibleShortCircuit = null; | 906 ShortCircuitData compatibleShortCircuit = null; |
848 for (ShortCircuitData circuit : availableShortCuts) { | 907 for (ShortCircuitData circuit : availableShortCuts) { |
849 if (circuit.isGeneric()) { | 908 if (circuit.isGeneric()) { |
895 continue; | 954 continue; |
896 } | 955 } |
897 List<String> paramIds = new LinkedList<>(); | 956 List<String> paramIds = new LinkedList<>(); |
898 paramIds.add(Utils.getTypeId(other.getReturnType().getType())); | 957 paramIds.add(Utils.getTypeId(other.getReturnType().getType())); |
899 for (ActualParameter param : other.getParameters()) { | 958 for (ActualParameter param : other.getParameters()) { |
900 if (other.getNode().findChild(param.getSpecification().getName()) == null) { | 959 if (param.getSpecification().getExecution() == null) { |
901 continue; | 960 continue; |
902 } | 961 } |
903 paramIds.add(Utils.getTypeId(param.getType())); | 962 paramIds.add(Utils.getTypeId(param.getType())); |
904 } | 963 } |
905 assert lastSize == -1 || lastSize == paramIds.size(); | 964 assert lastSize == -1 || lastSize == paramIds.size(); |
1228 } | 1287 } |
1229 } | 1288 } |
1230 return null; | 1289 return null; |
1231 } | 1290 } |
1232 | 1291 |
1233 private boolean isGenericShortCutMethod(NodeData node, TemplateMethod method) { | 1292 private boolean isGenericShortCutMethod(ShortCircuitData method) { |
1234 for (ActualParameter parameter : method.getParameters()) { | 1293 for (ActualParameter parameter : method.getParameters()) { |
1235 NodeChildData field = node.findChild(parameter.getSpecification().getName()); | 1294 NodeExecutionData execution = parameter.getSpecification().getExecution(); |
1236 if (field == null) { | 1295 if (execution == null) { |
1237 continue; | 1296 continue; |
1238 } | 1297 } |
1239 ExecutableTypeData found = null; | 1298 ExecutableTypeData found = null; |
1240 List<ExecutableTypeData> executableElements = field.findGenericExecutableTypes(context); | 1299 List<ExecutableTypeData> executableElements = execution.getChild().findGenericExecutableTypes(context); |
1241 for (ExecutableTypeData executable : executableElements) { | 1300 for (ExecutableTypeData executable : executableElements) { |
1242 if (executable.getType().equalsType(parameter.getTypeSystemType())) { | 1301 if (executable.getType().equalsType(parameter.getTypeSystemType())) { |
1243 found = executable; | 1302 found = executable; |
1244 break; | 1303 break; |
1245 } | 1304 } |