Mercurial > hg > graal-jvmci-8
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(); |