comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.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 354b7f1b4acf
comparison
equal deleted inserted replaced
20939:f83fd99b2962 20940:476374f3fe9a
60 60
61 private final ProcessorContext context; 61 private final ProcessorContext context;
62 private final NodeData node; 62 private final NodeData node;
63 private final TypeSystemData typeSystem; 63 private final TypeSystemData typeSystem;
64 private final TypeMirror genericType; 64 private final TypeMirror genericType;
65 private final TypeMirror voidType;
66 private final DSLOptions options; 65 private final DSLOptions options;
67 private final boolean singleSpecializable; 66 private final boolean singleSpecializable;
68 private final int varArgsThreshold; 67 private final int varArgsThreshold;
69 private final Set<TypeMirror> expectedTypes = new HashSet<>(); 68 private final Set<TypeMirror> expectedTypes = new HashSet<>();
69 private boolean nextUsed;
70 70
71 public NodeGenFactory(ProcessorContext context, NodeData node) { 71 public NodeGenFactory(ProcessorContext context, NodeData node) {
72 this.context = context; 72 this.context = context;
73 this.node = node; 73 this.node = node;
74 this.typeSystem = node.getTypeSystem(); 74 this.typeSystem = node.getTypeSystem();
75 this.genericType = context.getType(Object.class); 75 this.genericType = context.getType(Object.class);
76 this.voidType = context.getType(void.class);
77 this.options = typeSystem.getOptions(); 76 this.options = typeSystem.getOptions();
78 this.singleSpecializable = isSingleSpecializableImpl(); 77 this.singleSpecializable = isSingleSpecializableImpl();
79 this.varArgsThreshold = calculateVarArgsThreshold(); 78 this.varArgsThreshold = calculateVarArgsThreshold();
80 } 79 }
81 80
204 if (mayBeExcluded(specialization)) { 203 if (mayBeExcluded(specialization)) {
205 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); 204 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class));
206 } 205 }
207 } 206 }
208 207
209 Collection<TypeMirror> specializedTypes = node.findSpecializedReturnTypes(); 208 List<ExecutableTypeData> usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), getReachableSpecializations());
210 List<ExecutableTypeData> implementedExecutables = new ArrayList<>(); 209 for (ExecutableTypeData execType : usedTypes) {
211 for (ExecutableTypeData execType : node.getExecutableTypes()) { 210 if (execType.getMethod() == null) {
212 if (shouldImplementExecutableType(specializedTypes, execType)) { 211 continue;
213 implementedExecutables.add(execType); 212 }
214 } 213 clazz.add(createExecutableTypeOverride(usedTypes, execType));
215 } 214 }
216 for (ExecutableTypeData execType : implementedExecutables) { 215
217 clazz.add(createExecutableTypeOverride(implementedExecutables, execType));
218 }
219 clazz.add(createGetCostMethod()); 216 clazz.add(createGetCostMethod());
220 217
221 avoidFindbugsProblems(clazz); 218 avoidFindbugsProblems(clazz);
222 219
223 if (singleSpecializable) { 220 if (singleSpecializable) {
375 372
376 for (SpecializationData specialization : generateSpecializations) { 373 for (SpecializationData specialization : generateSpecializations) {
377 generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType))); 374 generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType)));
378 } 375 }
379 376
380 baseSpecialization.addOptional(createCreateNext(generated)); 377 if (nextUsed) {
378 baseSpecialization.addOptional(createCreateNext(generated));
379 }
381 baseSpecialization.addOptional(createCreateFallback(generated)); 380 baseSpecialization.addOptional(createCreateFallback(generated));
382 baseSpecialization.addOptional(createCreatePolymorphic(generated)); 381 baseSpecialization.addOptional(createCreatePolymorphic(generated));
383 382
384 return node.getUninitializedSpecialization(); 383 return node.getUninitializedSpecialization();
385 } 384 }
412 clazz.addOptional(createSpecializationConstructor(clazz, null, null)); 411 clazz.addOptional(createSpecializationConstructor(clazz, null, null));
413 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); 412 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root"));
414 413
415 clazz.addOptional(createUnsupported()); 414 clazz.addOptional(createUnsupported());
416 clazz.add(createGetSuppliedChildrenMethod()); 415 clazz.add(createGetSuppliedChildrenMethod());
417 416 clazz.add(createGetNext(clazz));
418 int signatureSize = node.getSignatureSize(); 417 clazz.add(createAcceptAndExecute());
419 Set<Integer> evaluatedCount = getEvaluatedCounts(); 418
420 for (int evaluated : evaluatedCount) { 419 List<ExecutableTypeData> usedTypes = filterBaseExecutableTypes(node.getExecutableTypes(), getReachableSpecializations());
421 if (signatureSize != evaluated || signatureSize == 0) { 420 for (ExecutableTypeData type : usedTypes) {
422 clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated)); 421 clazz.add(createFastPathExecuteMethod(null, type, usedTypes));
423 }
424 } 422 }
425 423
426 for (NodeExecutionData execution : node.getChildExecutions()) { 424 for (NodeExecutionData execution : node.getChildExecutions()) {
427 Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution); 425 Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
428 specializedTypes.add(genericType); 426 specializedTypes.add(genericType);
432 } 430 }
433 } 431 }
434 } 432 }
435 433
436 return clazz; 434 return clazz;
435 }
436
437 private Element createAcceptAndExecute() {
438
439 TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()];
440 Arrays.fill(parameters, genericType);
441
442 ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
443
444 LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
445 CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false);
446
447 executable.getModifiers().add(FINAL);
448 CodeTreeBuilder builder = executable.createBuilder();
449
450 CodeTree receiver = CodeTreeBuilder.singleString("this");
451
452 builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null)));
453
454 return executable;
455 }
456
457 private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) {
458 // always implement the root execute method. they are declared abstract in the base node.
459 if (executableType.getDelegatedTo() == null) {
460 return true;
461 }
462
463 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) {
464 return false;
465 }
466
467 // specializations with more parameters are just ignored
468 if (executableType.getEvaluatedCount() > node.getSignatureSize()) {
469 return false;
470 }
471
472 // the evaluated signature might be compatible to the specialization
473 boolean specializationCompatible = true;
474 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
475 TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
476 TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType();
477
478 if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) {
479 specializationCompatible = false;
480 break;
481 }
482 }
483 if (!specializationCompatible) {
484 return false;
485 }
486
487 // possibly trigger void optimization for a specialization if it is enabled
488 if (isVoid(executableType.getReturnType())) {
489 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specialization.getReturnType().getType())) {
490 return true;
491 }
492 }
493
494 // trigger type boxing elimination for unevaluated arguments
495 for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) {
496 NodeExecutionData execution = node.getChildExecutions().get(i);
497 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
498 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) {
499 // it does not make sense to do type boxing elimination for children with
500 // no type specialized execute method
501 if (execution.getChild() != null) {
502 ExecutableTypeData executedType = execution.getChild().findExecutableType(specializedType);
503 if (executedType != null) {
504 return true;
505 }
506 }
507 }
508 }
509
510 // trigger type boxing elimination for return types
511 if (typeEquals(executableType.getReturnType(), specialization.getReturnType().getType())) {
512 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), executableType.getReturnType())) {
513 return true;
514 }
515 }
516
517 // trigger generation for evaluated assignable type matches other than generic
518 for (int i = 0; i < executableType.getEvaluatedCount(); i++) {
519 TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i);
520 NodeExecutionData execution = node.getChildExecutions().get(i);
521 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
522
523 if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) {
524 return true;
525 }
526 }
527
528 return false;
529 }
530
531 private List<ExecutableTypeData> filterBaseExecutableTypes(List<ExecutableTypeData> executableTypes, List<SpecializationData> specializations) {
532 Set<ExecutableTypeData> usedTypes = new HashSet<>();
533 type: for (ExecutableTypeData type : executableTypes) {
534 for (SpecializationData specialization : specializations) {
535 if (shouldImplementExecutableType(specialization, type) || type.isAbstract() || !(type.hasUnexpectedValue(context) && type.getMethod() != null)) {
536 usedTypes.add(type);
537 continue type;
538 }
539 }
540 }
541 Set<ExecutableTypeData> delegatesToAdd = new HashSet<>();
542 do {
543 delegatesToAdd.clear();
544 for (ExecutableTypeData type : usedTypes) {
545 ExecutableTypeData delegate = type.getDelegatedTo();
546 if (delegate != null && !usedTypes.contains(delegate)) {
547 delegatesToAdd.add(delegate);
548 }
549 }
550 usedTypes.addAll(delegatesToAdd);
551 } while (!delegatesToAdd.isEmpty());
552 List<ExecutableTypeData> newUsedTypes = new ArrayList<>(usedTypes);
553 Collections.sort(newUsedTypes);
554 return newUsedTypes;
437 } 555 }
438 556
439 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { 557 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) {
440 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); 558 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType);
441 559
461 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); 579 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor));
462 clazz.addOptional(createMergeMethod(specialization)); 580 clazz.addOptional(createMergeMethod(specialization));
463 clazz.addOptional(createIsSameMethod(specialization)); 581 clazz.addOptional(createIsSameMethod(specialization));
464 clazz.addOptional(createIsIdenticalMethod(specialization)); 582 clazz.addOptional(createIsIdenticalMethod(specialization));
465 583
466 TypeMirror returnType = specialization.getReturnType().getType(); 584 // get types that should get implemented
467 int signatureSize = specialization.getSignatureSize(); 585 List<ExecutableTypeData> types = new ArrayList<>();
468 586 for (ExecutableTypeData type : node.getExecutableTypes()) {
469 clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize)); 587 if (shouldImplementExecutableType(specialization, type)) {
470 588 types.add(type);
471 if (isTypeBoxingEliminated(specialization)) { 589 }
472 if (node.getMinimalEvaluatedParameters() == 0 || signatureSize == 0) { 590 }
473 clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); 591 for (ExecutableTypeData type : types) {
474 if (signatureSize > 0 && !isObject(returnType)) { 592 clazz.add(createFastPathExecuteMethod(specialization, type, types));
475 clazz.add(createFastPathWrapExecuteMethod(genericType, returnType));
476 }
477 ExecutableTypeData voidExecutableType = node.findExecutableType(voidType, 0);
478 if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) {
479 clazz.add(createFastPathWrapVoidMethod(returnType));
480 }
481 }
482 } 593 }
483 594
484 return clazz; 595 return clazz;
596 }
597
598 public static List<Parameter> getDynamicParameters(TemplateMethod method) {
599 List<Parameter> parameters = new ArrayList<>();
600 for (Parameter param : method.getReturnTypeAndParameters()) {
601 if (param.getSpecification().isLocal()) {
602 // ignore parameters passed by locals
603 continue;
604 } else if (param.getVariableElement() != null && param.getVariableElement().getAnnotation(Cached.class) != null) {
605 // ignore cached parameters
606 continue;
607 }
608 parameters.add(param);
609 }
610 return parameters;
485 } 611 }
486 612
487 private Element createDeepCopyMethod() { 613 private Element createDeepCopyMethod() {
488 if (singleSpecializable) { 614 if (singleSpecializable) {
489 return null; 615 return null;
504 builder.startReturn().staticReference(getType(NodeCost.class), "MONOMORPHIC").end().end(); 630 builder.startReturn().staticReference(getType(NodeCost.class), "MONOMORPHIC").end().end();
505 } else { 631 } else {
506 builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end(); 632 builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end();
507 } 633 }
508 return executable; 634 return executable;
635
509 } 636 }
510 637
511 private Element createIsIdenticalMethod(SpecializationData specialization) { 638 private Element createIsIdenticalMethod(SpecializationData specialization) {
512 boolean cacheBoundGuard = specialization.hasMultipleInstances(); 639 boolean cacheBoundGuard = specialization.hasMultipleInstances();
513 if (!cacheBoundGuard) { 640 if (!cacheBoundGuard) {
617 } 744 }
618 745
619 return executable; 746 return executable;
620 } 747 }
621 748
622 private Element createFastPathWrapVoidMethod(TypeMirror wrap) {
623
624 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), voidType, TypeSystemNodeFactory.executeName(voidType));
625 executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
626 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
627 CodeTreeBuilder builder = executable.createBuilder();
628 builder.startStatement();
629 builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap));
630 builder.string(FRAME_VALUE);
631 builder.end();
632 builder.end();
633
634 return executable;
635 }
636
637 private Element createFastPathWrapExecuteMethod(TypeMirror override, TypeMirror wrap) {
638 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override, TypeSystemNodeFactory.executeName(override));
639 executable.addParameter(new CodeVariableElement(getType(Frame.class), FRAME_VALUE));
640 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
641 CodeTreeBuilder builder = executable.createBuilder();
642 if (wrap != null) {
643 builder.startTryBlock();
644 }
645 builder.startReturn();
646 builder.startCall(TypeSystemNodeFactory.executeName(wrap));
647 builder.string(FRAME_VALUE);
648 builder.end();
649 builder.end();
650 if (wrap != null) {
651 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
652 builder.statement("return ex.getResult()");
653 builder.end();
654 }
655
656 return executable;
657 }
658
659 private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) { 749 private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) {
660 SpecializationData fallback = node.getGenericSpecialization(); 750 SpecializationData fallback = node.getGenericSpecialization();
661 if (fallback == null) { 751 if (fallback == null) {
662 return null; 752 return null;
663 } 753 }
763 } 853 }
764 } 854 }
765 return method; 855 return method;
766 } 856 }
767 return null; 857 return null;
768 }
769
770 private boolean isTypeBoxingEliminated(SpecializationData specialization) {
771 if (specialization.getMethod() == null) {
772 return false;
773 }
774
775 TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization();
776 if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getType())) {
777 return true;
778 }
779 for (Parameter p : specialization.getSignatureParameters()) {
780 if (isTypeBoxingOptimized(optimization, p.getType())) {
781 return true;
782 }
783 }
784 return false;
785
786 }
787
788 private Set<Integer> getEvaluatedCounts() {
789 Set<Integer> evaluatedCount = new TreeSet<>();
790 Collection<TypeMirror> returnSpecializedTypes = node.findSpecializedReturnTypes();
791 for (ExecutableTypeData execType : node.getExecutableTypes()) {
792 if (shouldImplementExecutableType(returnSpecializedTypes, execType)) {
793 evaluatedCount.add(execType.getEvaluatedCount());
794 }
795 }
796 return evaluatedCount;
797 } 858 }
798 859
799 private Element createUnsupported() { 860 private Element createUnsupported() {
800 SpecializationData fallback = node.getGenericSpecialization(); 861 SpecializationData fallback = node.getGenericSpecialization();
801 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { 862 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
864 default: 925 default:
865 throw new AssertionError(); 926 throw new AssertionError();
866 } 927 }
867 } 928 }
868 929
869 private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> implementedExecutables, ExecutableTypeData execType) { 930 private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) {
870 final String varArgsName = "args";
871 final TypeMirror returnType = execType.getReturnType();
872 final TypeMirror executedType = execType.getEvaluatedCount() > 0 ? null : returnType;
873
874 LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); 931 LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE);
875 CodeExecutableElement method = cloneExecutableTypeOverride(locals, execType, varArgsName); 932 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true);
876 933
877 // rename varargs parameter
878 int signatureIndex = 0;
879 for (TypeMirror parameter : execType.getEvaluatedParameters()) {
880 LocalVariable var = locals.getValue(signatureIndex);
881 if (var != null) {
882 int varArgsIndex = execType.getVarArgsIndex(execType.getParameterIndex(signatureIndex));
883 if (varArgsIndex >= 0) {
884 var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
885 }
886 if (!isObject(parameter)) {
887 var = var.newType(parameter);
888 }
889 locals.setValue(node.getChildExecutions().get(signatureIndex), var);
890 }
891
892 signatureIndex++;
893 }
894
895 TypeMirror frame = execType.getFrameParameter();
896 CodeTreeBuilder builder = method.createBuilder(); 934 CodeTreeBuilder builder = method.createBuilder();
897 if (singleSpecializable) { 935 if (singleSpecializable) {
898 LocalVariable frameVar = null;
899 if (frame != null) {
900 frameVar = locals.get(FRAME_VALUE).newType(frame);
901 }
902 method.getThrownTypes().clear();
903 locals.set(FRAME_VALUE, frameVar);
904
905 SpecializationData specialization = getReachableSpecializations().iterator().next(); 936 SpecializationData specialization = getReachableSpecializations().iterator().next();
906 ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType); 937 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals));
907 if (wrappedExecutableType != null) {
908 builder.startReturn().tree(callExecuteMethod(null, wrappedExecutableType, locals)).end();
909 } else {
910 builder.tree(createFastPath(builder, specialization, execType.getReturnType(), locals));
911 }
912 } else { 938 } else {
913 // create acceptAndExecute 939 // create acceptAndExecute
914 CodeTreeBuilder executeBuilder = builder.create(); 940 ExecutableTypeData delegate = execType;
915 executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); 941 CodeTree receiver = CodeTreeBuilder.singleString(specializationStartFieldName());
916 if (frame == null) { 942 builder.tree(createCallDelegateExecute(builder, receiver, locals, execType, delegate));
917 executeBuilder.nullLiteral();
918 } else {
919 executeBuilder.string(locals.get(FRAME_VALUE).getName());
920 }
921 locals.addReferencesTo(executeBuilder);
922 executeBuilder.end();
923
924 boolean hasExecutedUnexpected = executedType != null && !isObject(executedType) && !isVoid(executedType);
925
926 CodeTreeBuilder contentBuilder = builder.create();
927 contentBuilder.startReturn();
928 if (!hasExecutedUnexpected && !execType.hasUnexpectedValue(context)) {
929 if (executedType == null || needsCastTo(executedType, returnType)) {
930 contentBuilder.cast(returnType, executeBuilder.build());
931 } else {
932 contentBuilder.tree(executeBuilder.build());
933 }
934 } else {
935 contentBuilder.tree(expect(executedType, returnType, executeBuilder.build()));
936 }
937 contentBuilder.end();
938 // try catch assert if unexpected value is not expected
939 CodeTree content = contentBuilder.build();
940 if (!execType.hasUnexpectedValue(context) && hasExecutedUnexpected) {
941 content = wrapTryCatchUnexpected(content);
942 }
943 builder.tree(content);
944 } 943 }
945 return method; 944 return method;
946 }
947
948 private CodeTree wrapTryCatchUnexpected(CodeTree content) {
949 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
950 builder.startTryBlock();
951 builder.tree(content);
952 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex");
953 builder.startThrow().startNew(getType(AssertionError.class)).end().end();
954 builder.end();
955 return builder.build();
956 }
957
958 private static ExecutableTypeData findWrappedExecutable(SpecializationData specialization, List<ExecutableTypeData> implementedExecutables, ExecutableTypeData executedType) {
959 if (specialization.getReturnType().getType() == executedType.getReturnType()) {
960 return null;
961 }
962 for (ExecutableTypeData otherType : implementedExecutables) {
963 if (otherType != executedType && //
964 otherType.getReturnType() == specialization.getReturnType().getType() && //
965 otherType.getEvaluatedCount() == executedType.getEvaluatedCount()) {
966 return otherType;
967 }
968 }
969 return null;
970 }
971
972 private CodeExecutableElement cloneExecutableTypeOverride(LocalContext locals, ExecutableTypeData execType, final String varArgsName) throws AssertionError {
973 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod());
974
975 method.getAnnotationMirrors().clear();
976 method.getModifiers().remove(Modifier.ABSTRACT);
977
978 // align argument names
979 int parameterIndex = 0;
980 if (execType.getFrameParameter() != null) {
981 CodeVariableElement frameParameter = (CodeVariableElement) method.getParameters().get(0);
982 frameParameter.setName(FRAME_VALUE);
983 frameParameter.getAnnotationMirrors().clear();
984 parameterIndex++;
985 }
986
987 for (int signatureIndex = 0; signatureIndex < execType.getEvaluatedCount(); signatureIndex++) {
988 CodeVariableElement var = (CodeVariableElement) method.getParameters().get(parameterIndex);
989 if (signatureIndex < node.getSignatureSize()) {
990 if (execType.getVarArgsIndex(parameterIndex) >= 0) {
991 var.getAnnotationMirrors().clear();
992 var.setName(varArgsName);
993 break;
994 }
995 var.setName(locals.getValue(signatureIndex).getName());
996 var.getAnnotationMirrors().clear();
997 } else {
998 var.setName("other" + signatureIndex);
999 }
1000 parameterIndex++;
1001 }
1002 return method;
1003 }
1004
1005 private boolean shouldImplementExecutableType(Collection<TypeMirror> specializedTypes, ExecutableTypeData execType) {
1006 TypeMirror type = execType.getReturnType();
1007 Set<Modifier> modifiers = execType.getMethod().getModifiers();
1008 if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) {
1009 return false;
1010 } else if (execType.isAbstract()) {
1011 return true;
1012 } else if (ElementUtils.isObject(type)) {
1013 return true;
1014 } else if (ElementUtils.isVoid(type)) {
1015 for (TypeMirror specializedType : specializedTypes) {
1016 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) {
1017 return true;
1018 }
1019 }
1020 return false;
1021 } else if (!specializedTypes.contains(type)) {
1022 return false;
1023 } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) {
1024 return false;
1025 }
1026 return true;
1027 } 945 }
1028 946
1029 private Element createMethodGetSpecializationNode() { 947 private Element createMethodGetSpecializationNode() {
1030 TypeMirror returntype = getType(SpecializationNode.class); 948 TypeMirror returntype = getType(SpecializationNode.class);
1031 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode"); 949 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode");
1089 } 1007 }
1090 builder.end(); 1008 builder.end();
1091 return builder.build(); 1009 return builder.build();
1092 } 1010 }
1093 1011
1094 private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { 1012 private CodeTree[] bindExecuteMethodParameters(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
1095 CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null;
1096 List<NodeExecutionData> executeWith = execution != null ? execution.getChild().getExecuteWith() : null; 1013 List<NodeExecutionData> executeWith = execution != null ? execution.getChild().getExecuteWith() : null;
1097 1014
1098 List<CodeTree> values = new ArrayList<>(); 1015 List<CodeTree> values = new ArrayList<>();
1099 if (method.getFrameParameter() != null) { 1016 if (method.getFrameParameter() != null) {
1100 LocalVariable frameLocal = currentValues.get(FRAME_VALUE); 1017 LocalVariable frameLocal = currentValues.get(FRAME_VALUE);
1112 } else { 1029 } else {
1113 variable = currentValues.getValue(parameterIndex); 1030 variable = currentValues.getValue(parameterIndex);
1114 } 1031 }
1115 values.add(createTypeSafeReference(variable, targetParameter)); 1032 values.add(createTypeSafeReference(variable, targetParameter));
1116 } 1033 }
1117 return callMethod(receiver, method.getMethod(), values.toArray(new CodeTree[values.size()])); 1034
1035 return values.toArray(new CodeTree[values.size()]);
1036 }
1037
1038 private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
1039 CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null;
1040 return callMethod(receiver, method.getMethod(), bindExecuteMethodParameters(execution, method, currentValues));
1118 } 1041 }
1119 1042
1120 private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) { 1043 private CodeTree callTemplateMethod(CodeTree receiver, TemplateMethod method, LocalContext currentValues) {
1121 CodeTree[] bindings = new CodeTree[method.getParameters().size()]; 1044 CodeTree[] bindings = new CodeTree[method.getParameters().size()];
1122 1045
1146 if (targetType == null || sourceType == null) { 1069 if (targetType == null || sourceType == null) {
1147 return valueReference; 1070 return valueReference;
1148 } 1071 }
1149 if (needsCastTo(sourceType, targetType)) { 1072 if (needsCastTo(sourceType, targetType)) {
1150 valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference); 1073 valueReference = TypeSystemCodeGenerator.cast(typeSystem, targetType, valueReference);
1151 } else if (ElementUtils.needsCastTo(sourceType, targetType)) {
1152 valueReference = CodeTreeBuilder.createBuilder().cast(targetType, valueReference).build();
1153 } 1074 }
1154 return valueReference; 1075 return valueReference;
1155 } 1076 }
1156 1077
1157 private SpecializationGroup createSpecializationGroups() { 1078 private SpecializationGroup createSpecializationGroups() {
1300 if (!groupChildren.isEmpty()) { 1221 if (!groupChildren.isEmpty()) {
1301 return hasFallthrough(groupChildren.get(groupChildren.size() - 1), forType, currentValues, fastPath, ignoreGuards); 1222 return hasFallthrough(groupChildren.get(groupChildren.size() - 1), forType, currentValues, fastPath, ignoreGuards);
1302 } 1223 }
1303 1224
1304 return false; 1225 return false;
1226 }
1227
1228 private static Element createGetNext(CodeTypeElement type) {
1229 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), type.asType(), "getNext");
1230 CodeTreeBuilder builder = method.createBuilder();
1231 builder.startReturn().cast(type.asType(), CodeTreeBuilder.singleString("this.next")).end();
1232 return method;
1305 } 1233 }
1306 1234
1307 private Element createGetSuppliedChildrenMethod() { 1235 private Element createGetSuppliedChildrenMethod() {
1308 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); 1236 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class));
1309 1237
1505 currentValues.addReferencesTo(builder); 1433 currentValues.addReferencesTo(builder);
1506 builder.end().end(); 1434 builder.end().end();
1507 return builder.build(); 1435 return builder.build();
1508 } 1436 }
1509 1437
1510 private CodeTree createCallNext(TypeMirror forType, LocalContext currentValues) { 1438 private CodeTree createCallNext(CodeTreeBuilder parent, ExecutableTypeData currentType, ExecutableTypeData callType, LocalContext currentValues) {
1511 if (singleSpecializable) { 1439 if (singleSpecializable) {
1512 return createThrowUnsupported(currentValues); 1440 return createThrowUnsupported(currentValues);
1513 } 1441 }
1514 CodeTreeBuilder callBuilder = CodeTreeBuilder.createBuilder(); 1442 CodeTreeBuilder callBuilder = parent.create();
1515 callBuilder.startCall("next", TypeSystemNodeFactory.executeName(null)); 1443 callBuilder.tree(createCallDelegateExecute(callBuilder, CodeTreeBuilder.singleString("getNext()"), currentValues, currentType, callType));
1516 currentValues.addReferencesTo(callBuilder, FRAME_VALUE); 1444 nextUsed = true;
1517 callBuilder.end(); 1445 return callBuilder.build();
1518 return CodeTreeBuilder.createBuilder().startReturn().tree(expect(genericType, forType, callBuilder.build())).end().build(); 1446 }
1519 } 1447
1520 1448 private CodeTree createCallRemove(String reason, ExecutableTypeData forType, LocalContext currentValues) {
1521 private CodeTree createCallRemove(String reason, TypeMirror forType, LocalContext currentValues) {
1522 if (singleSpecializable) { 1449 if (singleSpecializable) {
1523 return createThrowUnsupported(currentValues); 1450 return createThrowUnsupported(currentValues);
1524 } 1451 }
1525 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 1452 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1526 builder.startCall("remove"); 1453 builder.startCall("remove");
1529 builder.end(); 1456 builder.end();
1530 CodeTree call = builder.build(); 1457 CodeTree call = builder.build();
1531 1458
1532 builder = builder.create(); 1459 builder = builder.create();
1533 builder.startReturn(); 1460 builder.startReturn();
1534 builder.tree(expect(genericType, forType, call)); 1461 builder.tree(expectOrCast(genericType, forType, call));
1535 builder.end(); 1462 builder.end();
1536 return builder.build(); 1463 return builder.build();
1537 } 1464 }
1538 1465
1539 private CodeTree createCallDelegate(String methodName, String reason, TypeMirror forType, LocalContext currentValues) { 1466 private CodeTree createCallDelegate(String methodName, String reason, ExecutableTypeData forType, LocalContext currentValues) {
1540 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 1467 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
1541 builder.startCall(methodName); 1468 builder.startCall(methodName);
1542 if (reason != null) { 1469 if (reason != null) {
1543 builder.doubleQuote(reason); 1470 builder.doubleQuote(reason);
1544 } 1471 }
1545 currentValues.addReferencesTo(builder, FRAME_VALUE); 1472 currentValues.addReferencesTo(builder, FRAME_VALUE);
1546 builder.end(); 1473 builder.end();
1547 1474
1548 return expect(genericType, forType, builder.build()); 1475 CodeTree expectOrCast = expectOrCast(genericType, forType, builder.build());
1476 return expectOrCast;
1477 }
1478
1479 private CodeTree expectOrCast(TypeMirror sourceType, ExecutableTypeData targetType, CodeTree content) {
1480 if (targetType.hasUnexpectedValue(context)) {
1481 return expect(sourceType, targetType.getReturnType(), content);
1482 } else {
1483 return cast(sourceType, targetType.getReturnType(), content);
1484 }
1485 }
1486
1487 private CodeTree cast(TypeMirror sourceType, TypeMirror targetType, CodeTree content) {
1488 if (ElementUtils.needsCastTo(sourceType, targetType) && !isVoid(sourceType)) {
1489 return TypeSystemCodeGenerator.cast(typeSystem, targetType, content);
1490 } else {
1491 return content;
1492 }
1549 } 1493 }
1550 1494
1551 private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) { 1495 private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
1552 expectedTypes.add(forType); 1496 expectedTypes.add(forType);
1553 return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree); 1497 return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree);
1582 } 1526 }
1583 } 1527 }
1584 return false; 1528 return false;
1585 } 1529 }
1586 1530
1587 private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeMirror forType, int evaluatedArguments) { 1531 private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) {
1588 TypeMirror type = forType == null ? genericType : forType; 1532 LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold);
1589 LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); 1533 CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false);
1534 CodeTreeBuilder builder = executable.createBuilder();
1535 if (specialization == null) {
1536 if (executedType.getDelegatedTo() == null) {
1537 executable.getModifiers().add(ABSTRACT);
1538 }
1539 } else {
1540 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
1541 }
1542 builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals));
1543
1544 return executable;
1545 }
1546
1547 private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) {
1548 TypeMirror returnType = executedType.getReturnType();
1549 TypeMirror frame = executedType.getFrameParameter();
1550 List<TypeMirror> evaluatedParameters = executedType.getEvaluatedParameters();
1590 1551
1591 if (specialization != null) { 1552 if (specialization != null) {
1592 currentLocals.loadFastPathState(specialization); 1553 currentLocals.loadFastPathState(specialization);
1593 } 1554 }
1594 1555
1595 CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type, TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); 1556 if (frame == null) {
1596 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); 1557 currentLocals.removeValue(FRAME_VALUE);
1597 1558 } else {
1598 if (!isObject(type)) { 1559 currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame));
1599 executable.getThrownTypes().add(getType(UnexpectedResultException.class)); 1560 }
1600 } 1561
1601 1562 for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) {
1602 CodeTreeBuilder builder = executable.createBuilder(); 1563 NodeExecutionData execution = node.getChildExecutions().get(i);
1603 builder.tree(createFastPath(builder, specialization, type, currentLocals)); 1564 currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i)));
1565 }
1566
1567 String methodName;
1568 if (originalOverride) {
1569 methodName = executedType.getMethod().getSimpleName().toString();
1570 } else {
1571 methodName = executedType.getUniqueName();
1572 }
1573
1574 CodeExecutableElement executable;
1575 if (originalOverride && executedType.getMethod() != null) {
1576 executable = CodeExecutableElement.clone(context.getEnvironment(), executedType.getMethod());
1577 executable.getAnnotationMirrors().clear();
1578 executable.getModifiers().remove(ABSTRACT);
1579 for (VariableElement var : executable.getParameters()) {
1580 ((CodeVariableElement) var).getAnnotationMirrors().clear();
1581 }
1582 if (executedType.getFrameParameter() != null) {
1583 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE);
1584 }
1585
1586 final String varArgsName = "args";
1587 if (executable.isVarArgs()) {
1588 ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName);
1589 }
1590
1591 // rename varargs parameter
1592 int signatureIndex = 0;
1593 for (TypeMirror parameter : executedType.getEvaluatedParameters()) {
1594 LocalVariable var = currentLocals.getValue(signatureIndex);
1595 if (var != null) {
1596 int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex));
1597 if (varArgsIndex >= 0) {
1598 var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
1599 } else {
1600 ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName());
1601 }
1602 if (!isObject(parameter)) {
1603 var = var.newType(parameter);
1604 }
1605 currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var);
1606 }
1607
1608 signatureIndex++;
1609 }
1610 } else {
1611 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE);
1612 if (executedType.hasUnexpectedValue(context)) {
1613 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class));
1614 }
1615 }
1604 1616
1605 return executable; 1617 return executable;
1606 } 1618 }
1607 1619
1608 private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeMirror type, LocalContext currentLocals) { 1620 private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, final ExecutableTypeData executableType, List<ExecutableTypeData> allTypes, LocalContext currentLocals) {
1609 final CodeTreeBuilder builder = parent.create(); 1621 final CodeTreeBuilder builder = parent.create();
1622 TypeMirror returnType = executableType.getReturnType();
1623
1624 ExecutableTypeData delegate = null;
1625 if (specialization == null) {
1626 delegate = executableType.getDelegatedTo();
1627 }
1628
1629 if (delegate == null) {
1630 delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes);
1631 }
1610 1632
1611 for (NodeExecutionData execution : node.getChildExecutions()) { 1633 for (NodeExecutionData execution : node.getChildExecutions()) {
1634 if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) {
1635 // we just evaluate children for the next delegate
1636 continue;
1637 } else if (specialization != null && delegate != null) {
1638 // skip if already delegated
1639 break;
1640 }
1641
1612 LocalVariable var = currentLocals.getValue(execution); 1642 LocalVariable var = currentLocals.getValue(execution);
1613 if (var == null) { 1643 if (var == null) {
1614 TypeMirror targetType; 1644 TypeMirror targetType;
1615 if (specialization == null) { 1645 if (specialization == null) {
1616 targetType = genericType; 1646 List<TypeMirror> genericTypes = node.getGenericTypes(execution);
1647 if (genericTypes.isEmpty()) {
1648 targetType = genericType;
1649 } else {
1650 targetType = genericTypes.get(0);
1651 }
1617 } else { 1652 } else {
1618 targetType = specialization.findParameterOrDie(execution).getType(); 1653 targetType = specialization.findParameterOrDie(execution).getType();
1619 } 1654 }
1620 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals); 1655 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals);
1621 LocalVariable value = currentLocals.createValue(execution, targetType).nextName(); 1656 var = currentLocals.createValue(execution, targetType).nextName();
1622 builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals)); 1657 builder.tree(createAssignExecuteChild(builder, execution, executableType, var, shortCircuit, currentLocals));
1623 currentLocals.setValue(execution, value); 1658 currentLocals.setValue(execution, var);
1659
1624 } 1660 }
1625 } 1661 }
1626 1662
1627 LocalContext originalValues = currentLocals.copy(); 1663 LocalContext originalValues = currentLocals.copy();
1628 if (specialization == null) { 1664 if (delegate != null) {
1629 builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); 1665 builder.tree(createCallDelegateExecute(builder, null, currentLocals, executableType, delegate));
1666 } else if (specialization == null) {
1667 // nothing to do. abstract anyway
1630 } else if (specialization.isPolymorphic()) { 1668 } else if (specialization.isPolymorphic()) {
1631 builder.tree(createCallNext(type, currentLocals)); 1669 builder.tree(createCallNext(builder, executableType, node.getGenericExecutableType(executableType), currentLocals));
1632 } else if (specialization.isUninitialized()) { 1670 } else if (specialization.isUninitialized()) {
1633 builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); 1671 builder.startReturn().tree(createCallDelegate("uninitialized", null, executableType, currentLocals)).end();
1634 } else { 1672 } else {
1635 final TypeMirror finalType = type;
1636 SpecializationGroup group = SpecializationGroup.create(specialization); 1673 SpecializationGroup group = SpecializationGroup.create(specialization);
1637 SpecializationBody executionFactory = new SpecializationBody(true, true) { 1674 SpecializationBody executionFactory = new SpecializationBody(true, true) {
1638 @Override 1675 @Override
1639 public CodeTree createBody(SpecializationData s, LocalContext values) { 1676 public CodeTree createBody(SpecializationData s, LocalContext values) {
1640 return createFastPathExecute(builder, finalType, s, values); 1677 return createFastPathExecute(builder, executableType, s, values);
1641 } 1678 }
1642 }; 1679 };
1643 builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); 1680 builder.tree(createGuardAndCast(group, returnType, currentLocals, executionFactory));
1644 if (hasFallthrough(group, type, originalValues, true, null) || group.getSpecialization().isFallback()) { 1681 if (hasFallthrough(group, returnType, originalValues, true, null) || group.getSpecialization().isFallback()) {
1645 builder.tree(createCallNext(type, originalValues)); 1682 builder.tree(createCallNext(builder, executableType, executableType, originalValues));
1646 } 1683 }
1647 } 1684 }
1648 return builder.build(); 1685 return builder.build();
1686 }
1687
1688 private CodeTree createCallDelegateExecute(final CodeTreeBuilder parent, CodeTree receiver, LocalContext currentLocals, ExecutableTypeData source, ExecutableTypeData delegate) {
1689 CodeTreeBuilder callBuilder = parent.create();
1690
1691 if (singleSpecializable) {
1692 callBuilder.startCall(receiver, delegate.getMethod().getSimpleName().toString());
1693 } else {
1694 callBuilder.startCall(receiver, delegate.getUniqueName());
1695 }
1696 callBuilder.trees(bindExecuteMethodParameters(null, delegate, currentLocals));
1697 callBuilder.end();
1698 CodeTree call = expectOrCast(delegate.getReturnType(), source, callBuilder.build());
1699
1700 CodeTreeBuilder returnBuilder = parent.create();
1701 if (isVoid(source.getReturnType())) {
1702 returnBuilder.statement(call);
1703 returnBuilder.returnStatement();
1704 } else if (isVoid(delegate.getReturnType())) {
1705 returnBuilder.statement(call);
1706 returnBuilder.returnDefault();
1707 } else {
1708 returnBuilder.startReturn().tree(call).end();
1709 }
1710
1711 CodeTreeBuilder builder = parent.create();
1712
1713 if (!source.hasUnexpectedValue(context) && delegate.hasUnexpectedValue(context)) {
1714 builder.startTryBlock();
1715 builder.tree(returnBuilder.build());
1716 builder.end().startCatchBlock(context.getType(UnexpectedResultException.class), "ex");
1717 if (!isVoid(source.getReturnType())) {
1718 builder.startReturn().tree(cast(context.getType(Object.class), source.getReturnType(), CodeTreeBuilder.singleString("ex.getResult()"))).end();
1719 }
1720 builder.end();
1721 } else {
1722 builder.tree(returnBuilder.build());
1723 }
1724 return builder.build();
1725 }
1726
1727 private ExecutableTypeData findFastPathDelegate(TypeMirror targetType, ExecutableTypeData executableType, List<ExecutableTypeData> allTypes) {
1728 if (typeEquals(executableType.getReturnType(), targetType)) {
1729 // type matches look for even better delegates
1730 for (ExecutableTypeData type : allTypes) {
1731 if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) {
1732 if (type != executableType) {
1733 return type;
1734 }
1735 }
1736 }
1737 return null;
1738 } else {
1739 for (ExecutableTypeData type : allTypes) {
1740 if (typeEquals(type.getReturnType(), targetType) && executableType.sameParameters(type)) {
1741 return type;
1742 }
1743 }
1744 int executableIndex = allTypes.indexOf(executableType);
1745 int compareIndex = 0;
1746 for (ExecutableTypeData type : allTypes) {
1747 if (executableIndex != compareIndex && executableType.sameParameters(type)) {
1748 int result = ExecutableTypeData.compareType(context, type.getReturnType(), executableType.getReturnType());
1749 if (result < 0) {
1750 return type;
1751 } else if (result == 0 && executableIndex < compareIndex) {
1752 return type;
1753 }
1754 }
1755 compareIndex++;
1756 }
1757 return null;
1758 }
1649 } 1759 }
1650 1760
1651 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { 1761 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
1652 LocalVariable shortCircuit = null; 1762 LocalVariable shortCircuit = null;
1653 SpecializationData resolvedSpecialization = specialization; 1763 SpecializationData resolvedSpecialization = specialization;
1674 } 1784 }
1675 } 1785 }
1676 return shortCircuitIndex; 1786 return shortCircuitIndex;
1677 } 1787 }
1678 1788
1679 private CodeTree createFastPathExecute(CodeTreeBuilder parent, final TypeMirror forType, SpecializationData specialization, LocalContext currentValues) { 1789 private CodeTree createFastPathExecute(CodeTreeBuilder parent, final ExecutableTypeData forType, SpecializationData specialization, LocalContext currentValues) {
1680 CodeTreeBuilder builder = parent.create(); 1790 CodeTreeBuilder builder = parent.create();
1681 int ifCount = 0; 1791 int ifCount = 0;
1682 if (specialization.isFallback()) { 1792 if (specialization.isFallback()) {
1683 builder.startIf().startCall("guardFallback"); 1793 builder.startIf().startCall("guardFallback");
1684 if (node.isFrameUsedByAnyGuard()) { 1794 if (node.isFrameUsedByAnyGuard()) {
1727 execute.startStatement(); 1837 execute.startStatement();
1728 } 1838 }
1729 execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues)); 1839 execute.tree(callTemplateMethod(accessParent(null), specialization, currentValues));
1730 execute.end(); 1840 execute.end();
1731 if (!doReturn) { 1841 if (!doReturn) {
1732 if (isVoid(forType)) { 1842 if (isVoid(forType.getReturnType())) {
1733 execute.returnStatement(); 1843 execute.returnStatement();
1734 } else { 1844 } else {
1735 execute.startReturn(); 1845 execute.startReturn();
1736 execute.defaultValue(forType); 1846 execute.defaultValue(forType.getReturnType());
1737 execute.end(); 1847 execute.end();
1738 } 1848 }
1739 } 1849 }
1740 } 1850 }
1741 builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build())); 1851 builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build()));
1939 return false; 2049 return false;
1940 } 2050 }
1941 } 2051 }
1942 } 2052 }
1943 2053
1944 private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeMirror returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) { 2054 private CodeTree createAssignExecuteChild(CodeTreeBuilder parent, NodeExecutionData execution, ExecutableTypeData type, LocalVariable targetValue, LocalVariable shortCircuit,
1945 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 2055 LocalContext currentValues) {
2056 CodeTreeBuilder builder = parent.create();
1946 boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getTypeMirror()); 2057 boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getTypeMirror());
1947 2058
1948 CodeTree executeChild; 2059 CodeTree executeChild;
1949 if (isExecuteChildShared(execution, targetValue.getTypeMirror())) { 2060 if (isExecuteChildShared(execution, targetValue.getTypeMirror())) {
1950 executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues); 2061 executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues);
1960 2071
1961 builder.end(); 2072 builder.end();
1962 if (hasUnexpected) { 2073 if (hasUnexpected) {
1963 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); 2074 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex");
1964 LocalContext slowPathValues = currentValues.copy(); 2075 LocalContext slowPathValues = currentValues.copy();
1965
1966 slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); 2076 slowPathValues.setValue(execution, targetValue.makeGeneric(context).accessWith(CodeTreeBuilder.singleString("ex.getResult()")));
2077
2078 ExecutableTypeData delegateType = node.getGenericExecutableType(type);
1967 boolean found = false; 2079 boolean found = false;
1968 for (NodeExecutionData otherExecution : node.getChildExecutions()) { 2080 for (NodeExecutionData otherExecution : node.getChildExecutions()) {
1969 if (found) { 2081 if (found) {
1970 LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType); 2082 LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType);
1971 LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues); 2083 LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues);
1972 builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues)); 2084 builder.tree(createAssignExecuteChild(builder, otherExecution, delegateType, childEvaluatedValue, genericShortCircuit, slowPathValues));
1973 slowPathValues.setValue(otherExecution, childEvaluatedValue); 2085 slowPathValues.setValue(otherExecution, childEvaluatedValue);
1974 } else { 2086 } else {
1975 // skip forward already evaluated 2087 // skip forward already evaluated
1976 found = execution == otherExecution; 2088 found = execution == otherExecution;
1977 } 2089 }
1978 } 2090 }
1979 builder.tree(createCallNext(returnType, slowPathValues)); 2091 builder.tree(createCallNext(builder, type, delegateType, slowPathValues));
1980 builder.end(); 2092 builder.end();
1981 } 2093 }
1982 2094
1983 return createShortCircuit(targetValue, shortCircuit, builder.build()); 2095 return createShortCircuit(targetValue, shortCircuit, builder.build());
1984 } 2096 }
2221 if (!executableTypes.isEmpty()) { 2333 if (!executableTypes.isEmpty()) {
2222 builder.startElseBlock(); 2334 builder.startElseBlock();
2223 } 2335 }
2224 2336
2225 LocalVariable genericValue = target.makeGeneric(context).nextName(); 2337 LocalVariable genericValue = target.makeGeneric(context).nextName();
2226 builder.tree(createAssignExecuteChild(execution, genericValue.getTypeMirror(), genericValue, null, currentValues)); 2338 builder.tree(createAssignExecuteChild(builder, execution, node.getGenericExecutableType(null), genericValue, null, currentValues));
2227 if (executableTypes.size() == sourceTypes.size()) { 2339 if (executableTypes.size() == sourceTypes.size()) {
2228 builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end(); 2340 builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end();
2229 } else { 2341 } else {
2230 builder.startStatement().tree(assignment); 2342 builder.startStatement().tree(assignment);
2231 builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName)); 2343 builder.tree(TypeSystemCodeGenerator.implicitExpect(typeSystem, target.getTypeMirror(), genericValue.createReference(), implicitClassFieldName));
2236 builder.end(); 2348 builder.end();
2237 } 2349 }
2238 return builder.build(); 2350 return builder.build();
2239 } 2351 }
2240 2352
2241 private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeMirror forType, LocalContext currentValues, CodeTree execution) { 2353 private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, ExecutableTypeData forType, LocalContext currentValues, CodeTree execution) {
2242 if (specialization.getExceptions().isEmpty()) { 2354 if (specialization.getExceptions().isEmpty()) {
2243 return execution; 2355 return execution;
2244 } 2356 }
2245 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 2357 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
2246 builder.startTryBlock(); 2358 builder.startTryBlock();