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