Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 20947:824ef485081f
Truffle-DSL: performance optimization for types * specialization complexity in shouldOverrideExecutableType.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Tue, 14 Apr 2015 19:23:33 +0200 |
parents | 1ed58a90b510 |
children | a0d97b639d57 |
comparison
equal
deleted
inserted
replaced
20946:56eb34a5aa22 | 20947:824ef485081f |
---|---|
65 private final DSLOptions options; | 65 private final DSLOptions options; |
66 private final boolean singleSpecializable; | 66 private final boolean singleSpecializable; |
67 private final int varArgsThreshold; | 67 private final int varArgsThreshold; |
68 private final Set<TypeMirror> expectedTypes = new HashSet<>(); | 68 private final Set<TypeMirror> expectedTypes = new HashSet<>(); |
69 private boolean nextUsed; | 69 private boolean nextUsed; |
70 private List<ExecutableTypeData> usedTypes; | |
71 private List<SpecializationData> reachableSpecializations; | |
70 | 72 |
71 public NodeGenFactory(ProcessorContext context, NodeData node) { | 73 public NodeGenFactory(ProcessorContext context, NodeData node) { |
72 this.context = context; | 74 this.context = context; |
73 this.node = node; | 75 this.node = node; |
74 this.typeSystem = node.getTypeSystem(); | 76 this.typeSystem = node.getTypeSystem(); |
75 this.genericType = context.getType(Object.class); | 77 this.genericType = context.getType(Object.class); |
76 this.options = typeSystem.getOptions(); | 78 this.options = typeSystem.getOptions(); |
79 this.varArgsThreshold = calculateVarArgsThreshold(); | |
80 this.reachableSpecializations = calculateReachableSpecializations(); | |
77 this.singleSpecializable = isSingleSpecializableImpl(); | 81 this.singleSpecializable = isSingleSpecializableImpl(); |
78 this.varArgsThreshold = calculateVarArgsThreshold(); | 82 this.usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), reachableSpecializations); |
79 } | 83 } |
80 | 84 |
81 private int calculateVarArgsThreshold() { | 85 private int calculateVarArgsThreshold() { |
82 TypeMirror specialization = context.getType(SpecializationNode.class); | 86 TypeMirror specialization = context.getType(SpecializationNode.class); |
83 TypeElement specializationType = fromTypeMirror(specialization); | 87 TypeElement specializationType = fromTypeMirror(specialization); |
203 if (mayBeExcluded(specialization)) { | 207 if (mayBeExcluded(specialization)) { |
204 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); | 208 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); |
205 } | 209 } |
206 } | 210 } |
207 | 211 |
208 List<ExecutableTypeData> usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), getReachableSpecializations()); | |
209 for (ExecutableTypeData execType : usedTypes) { | 212 for (ExecutableTypeData execType : usedTypes) { |
210 if (execType.getMethod() == null) { | 213 if (execType.getMethod() == null) { |
211 continue; | 214 continue; |
212 } | 215 } |
213 clazz.add(createExecutableTypeOverride(usedTypes, execType)); | 216 clazz.add(createExecutableTypeOverride(usedTypes, execType)); |
354 private static boolean mayBeExcluded(SpecializationData specialization) { | 357 private static boolean mayBeExcluded(SpecializationData specialization) { |
355 return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); | 358 return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); |
356 } | 359 } |
357 | 360 |
358 private SpecializationData createSpecializations(CodeTypeElement clazz) { | 361 private SpecializationData createSpecializations(CodeTypeElement clazz) { |
359 List<SpecializationData> reachableSpecializations = getReachableSpecializations(); | |
360 | |
361 CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization()); | 362 CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization()); |
362 TypeMirror baseSpecializationType = baseSpecialization.asType(); | 363 TypeMirror baseSpecializationType = baseSpecialization.asType(); |
363 | 364 |
364 Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>(); | 365 Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>(); |
365 | 366 |
382 | 383 |
383 return node.getUninitializedSpecialization(); | 384 return node.getUninitializedSpecialization(); |
384 } | 385 } |
385 | 386 |
386 private boolean needsPolymorphic() { | 387 private boolean needsPolymorphic() { |
387 List<SpecializationData> reachableSpecializations = getReachableSpecializations(); | |
388 if (reachableSpecializations.size() != 1) { | 388 if (reachableSpecializations.size() != 1) { |
389 return true; | 389 return true; |
390 } | 390 } |
391 | 391 |
392 SpecializationData specialization = reachableSpecializations.get(0); | 392 SpecializationData specialization = reachableSpecializations.get(0); |
414 clazz.addOptional(createUnsupported()); | 414 clazz.addOptional(createUnsupported()); |
415 clazz.add(createGetSuppliedChildrenMethod()); | 415 clazz.add(createGetSuppliedChildrenMethod()); |
416 clazz.add(createGetNext(clazz)); | 416 clazz.add(createGetNext(clazz)); |
417 clazz.add(createAcceptAndExecute()); | 417 clazz.add(createAcceptAndExecute()); |
418 | 418 |
419 List<ExecutableTypeData> usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), getReachableSpecializations()); | |
420 for (ExecutableTypeData type : usedTypes) { | 419 for (ExecutableTypeData type : usedTypes) { |
421 clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); | 420 clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); |
422 } | 421 } |
423 | 422 |
424 for (NodeExecutionData execution : node.getChildExecutions()) { | 423 for (NodeExecutionData execution : node.getChildExecutions()) { |
458 // always implement the root execute method. they are declared abstract in the base node. | 457 // always implement the root execute method. they are declared abstract in the base node. |
459 if (executableType.getDelegatedTo() == null) { | 458 if (executableType.getDelegatedTo() == null) { |
460 return true; | 459 return true; |
461 } | 460 } |
462 | 461 |
463 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) { | |
464 return false; | |
465 } | |
466 | |
467 // specializations with more parameters are just ignored | 462 // specializations with more parameters are just ignored |
468 if (executableType.getEvaluatedCount() > node.getSignatureSize()) { | 463 if (executableType.getEvaluatedCount() > node.getSignatureSize()) { |
464 return false; | |
465 } | |
466 | |
467 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) { | |
469 return false; | 468 return false; |
470 } | 469 } |
471 | 470 |
472 // the evaluated signature might be compatible to the specialization | 471 // the evaluated signature might be compatible to the specialization |
473 boolean specializationCompatible = true; | 472 boolean specializationCompatible = true; |
527 | 526 |
528 return false; | 527 return false; |
529 } | 528 } |
530 | 529 |
531 private List<ExecutableTypeData> filterBaseExecutableTypes(List<ExecutableTypeData> executableTypes, List<SpecializationData> specializations) { | 530 private List<ExecutableTypeData> filterBaseExecutableTypes(List<ExecutableTypeData> executableTypes, List<SpecializationData> specializations) { |
532 Set<ExecutableTypeData> usedTypes = new HashSet<>(); | 531 Set<TypeMirror> returnTypes = new HashSet<>(); |
533 type: for (ExecutableTypeData type : executableTypes) { | 532 for (SpecializationData specialization : node.getSpecializations()) { |
533 returnTypes.add(specialization.getReturnType().getType()); | |
534 } | |
535 | |
536 List<ExecutableTypeData> prefilteredTypes = new ArrayList<>(); | |
537 for (ExecutableTypeData type : executableTypes) { | |
538 if (type.getDelegatedTo() == null || shouldAlwaysImplementExecutableType(type)) { | |
539 prefilteredTypes.add(type); | |
540 } else { | |
541 boolean foundSubtype = false; | |
542 for (TypeMirror returnType : returnTypes) { | |
543 if (isSubtypeBoxed(context, returnType, type.getReturnType())) { | |
544 foundSubtype = true; | |
545 } | |
546 } | |
547 if (foundSubtype) { | |
548 prefilteredTypes.add(type); | |
549 } | |
550 } | |
551 } | |
552 | |
553 Set<ExecutableTypeData> types = new HashSet<>(); | |
554 type: for (ExecutableTypeData type : prefilteredTypes) { | |
534 for (SpecializationData specialization : specializations) { | 555 for (SpecializationData specialization : specializations) { |
535 if (shouldImplementExecutableType(specialization, type) || type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null)) { | 556 if (shouldImplementExecutableType(specialization, type) || shouldAlwaysImplementExecutableType(type)) { |
536 usedTypes.add(type); | 557 types.add(type); |
537 continue type; | 558 continue type; |
538 } | 559 } |
539 } | 560 } |
540 } | 561 } |
541 Set<ExecutableTypeData> delegatesToAdd = new HashSet<>(); | 562 Set<ExecutableTypeData> delegatesToAdd = new HashSet<>(); |
542 do { | 563 do { |
543 delegatesToAdd.clear(); | 564 delegatesToAdd.clear(); |
544 for (ExecutableTypeData type : usedTypes) { | 565 for (ExecutableTypeData type : types) { |
545 ExecutableTypeData delegate = type.getDelegatedTo(); | 566 ExecutableTypeData delegate = type.getDelegatedTo(); |
546 if (delegate != null && !usedTypes.contains(delegate)) { | 567 if (delegate != null && !types.contains(delegate)) { |
547 delegatesToAdd.add(delegate); | 568 delegatesToAdd.add(delegate); |
548 } | 569 } |
549 } | 570 } |
550 usedTypes.addAll(delegatesToAdd); | 571 types.addAll(delegatesToAdd); |
551 } while (!delegatesToAdd.isEmpty()); | 572 } while (!delegatesToAdd.isEmpty()); |
552 List<ExecutableTypeData> newUsedTypes = new ArrayList<>(usedTypes); | 573 List<ExecutableTypeData> newUsedTypes = new ArrayList<>(types); |
553 Collections.sort(newUsedTypes); | 574 Collections.sort(newUsedTypes); |
554 return newUsedTypes; | 575 return newUsedTypes; |
576 } | |
577 | |
578 private boolean shouldAlwaysImplementExecutableType(ExecutableTypeData type) { | |
579 return type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null); | |
555 } | 580 } |
556 | 581 |
557 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { | 582 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { |
558 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); | 583 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); |
559 | 584 |
874 | 899 |
875 return method; | 900 return method; |
876 } | 901 } |
877 | 902 |
878 private boolean isSingleSpecializableImpl() { | 903 private boolean isSingleSpecializableImpl() { |
879 List<SpecializationData> reachableSpecializations = getReachableSpecializations(); | |
880 if (reachableSpecializations.size() != 1) { | 904 if (reachableSpecializations.size() != 1) { |
881 return false; | 905 return false; |
882 } | 906 } |
883 | 907 |
884 SpecializationData specialization = reachableSpecializations.get(0); | 908 SpecializationData specialization = reachableSpecializations.get(0); |
900 return false; | 924 return false; |
901 } | 925 } |
902 return true; | 926 return true; |
903 } | 927 } |
904 | 928 |
905 private List<SpecializationData> getReachableSpecializations() { | 929 private List<SpecializationData> calculateReachableSpecializations() { |
906 List<SpecializationData> specializations = new ArrayList<>(); | 930 List<SpecializationData> specializations = new ArrayList<>(); |
907 for (SpecializationData specialization : node.getSpecializations()) { | 931 for (SpecializationData specialization : node.getSpecializations()) { |
908 if (specialization.isReachable() && // | 932 if (specialization.isReachable() && // |
909 (specialization.isSpecialized() // | 933 (specialization.isSpecialized() // |
910 || (specialization.isFallback() && optimizeFallback(specialization)))) { | 934 || (specialization.isFallback() && optimizeFallback(specialization)))) { |
931 LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); | 955 LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); |
932 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true); | 956 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true); |
933 | 957 |
934 CodeTreeBuilder builder = method.createBuilder(); | 958 CodeTreeBuilder builder = method.createBuilder(); |
935 if (singleSpecializable) { | 959 if (singleSpecializable) { |
936 SpecializationData specialization = getReachableSpecializations().iterator().next(); | 960 SpecializationData specialization = reachableSpecializations.iterator().next(); |
937 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals)); | 961 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals)); |
938 } else { | 962 } else { |
939 // create acceptAndExecute | 963 // create acceptAndExecute |
940 ExecutableTypeData delegate = execType; | 964 ExecutableTypeData delegate = execType; |
941 CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName()); | 965 CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName()); |
1074 } | 1098 } |
1075 return valueReference; | 1099 return valueReference; |
1076 } | 1100 } |
1077 | 1101 |
1078 private SpecializationGroup createSpecializationGroups() { | 1102 private SpecializationGroup createSpecializationGroups() { |
1079 return SpecializationGroup.create(getReachableSpecializations()); | 1103 return SpecializationGroup.create(reachableSpecializations); |
1080 } | 1104 } |
1081 | 1105 |
1082 private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { | 1106 private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { |
1083 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | 1107 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); |
1084 if (specialization.isFallback()) { | 1108 if (specialization.isFallback()) { |
1607 | 1631 |
1608 signatureIndex++; | 1632 signatureIndex++; |
1609 } | 1633 } |
1610 } else { | 1634 } else { |
1611 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE); | 1635 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE); |
1612 if (executedType.hasUnexpectedValue(context)) { | 1636 } |
1613 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class)); | 1637 executable.getThrownTypes().clear(); |
1614 } | 1638 |
1639 if (executedType.hasUnexpectedValue(context)) { | |
1640 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class)); | |
1615 } | 1641 } |
1616 | 1642 |
1617 return executable; | 1643 return executable; |
1618 } | 1644 } |
1619 | 1645 |