comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 20984:6361fa2e3321

Truffle-DSL: further fixes for polymorphic execute signatures.
author Christian Humer <christian.humer@oracle.com>
date Wed, 15 Apr 2015 21:13:43 +0200
parents 05a2b72c071f
children ef2825da2e43
comparison
equal deleted inserted replaced
20983:b99da6d86cfe 20984:6361fa2e3321
64 private final TypeMirror genericType; 64 private final TypeMirror genericType;
65 private final DSLOptions options; 65 private final DSLOptions options;
66 private final boolean singleSpecializable; 66 private final boolean singleSpecializable;
67 private final int varArgsThreshold; 67 private final int varArgsThreshold;
68 private final Set<TypeMirror> expectedTypes = new HashSet<>(); 68 private final Set<TypeMirror> expectedTypes = new HashSet<>();
69 private final Set<NodeExecutionData> usedExecuteChildMethods = new HashSet<>();
69 private boolean nextUsed; 70 private boolean nextUsed;
71
70 private List<ExecutableTypeData> usedTypes; 72 private List<ExecutableTypeData> usedTypes;
71 private List<SpecializationData> reachableSpecializations; 73 private List<SpecializationData> reachableSpecializations;
72 74
73 public NodeGenFactory(ProcessorContext context, NodeData node) { 75 public NodeGenFactory(ProcessorContext context, NodeData node) {
74 this.context = context; 76 this.context = context;
208 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); 210 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class));
209 } 211 }
210 } 212 }
211 213
212 for (ExecutableTypeData execType : usedTypes) { 214 for (ExecutableTypeData execType : usedTypes) {
213 if (execType.getMethod() == null) { 215 if (!singleSpecializable && execType.getMethod() == null) {
214 continue; 216 continue;
215 } 217 }
216 clazz.add(createExecutableTypeOverride(usedTypes, execType)); 218 clazz.add(createExecutableTypeOverride(usedTypes, execType));
217 } 219 }
218 220
271 } 273 }
272 } 274 }
273 275
274 private Element createUnsupportedMethod() { 276 private Element createUnsupportedMethod() {
275 LocalContext locals = LocalContext.load(this); 277 LocalContext locals = LocalContext.load(this);
276 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported"); 278 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED), getType(UnsupportedSpecializationException.class), "unsupported", varArgsThreshold);
277 279
278 CodeTreeBuilder builder = method.createBuilder(); 280 CodeTreeBuilder builder = method.createBuilder();
279 builder.startReturn(); 281 builder.startReturn();
280 builder.startNew(getType(UnsupportedSpecializationException.class)); 282 builder.startNew(getType(UnsupportedSpecializationException.class));
281 builder.string("this"); 283 builder.string("this");
378 baseSpecialization.addOptional(createCreateNext(generated)); 380 baseSpecialization.addOptional(createCreateNext(generated));
379 baseSpecialization.addOptional(createCreateFallback(generated)); 381 baseSpecialization.addOptional(createCreateFallback(generated));
380 baseSpecialization.addOptional(createCreatePolymorphic(generated)); 382 baseSpecialization.addOptional(createCreatePolymorphic(generated));
381 baseSpecialization.addOptional(createGetNext(baseSpecialization)); 383 baseSpecialization.addOptional(createGetNext(baseSpecialization));
382 384
385 for (NodeExecutionData execution : node.getChildExecutions()) {
386 Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
387 specializedTypes.add(genericType);
388 for (TypeMirror specializedType : specializedTypes) {
389 if (isExecuteChildShared(execution, specializedType)) {
390 baseSpecialization.addOptional(createExecuteChildMethod(execution, specializedType));
391 }
392 }
393 }
394
383 return node.getUninitializedSpecialization(); 395 return node.getUninitializedSpecialization();
384 } 396 }
385 397
386 private boolean needsPolymorphic() { 398 private boolean needsPolymorphic() {
387 if (reachableSpecializations.size() != 1) { 399 if (reachableSpecializations.size() != 1) {
416 428
417 for (ExecutableTypeData type : usedTypes) { 429 for (ExecutableTypeData type : usedTypes) {
418 clazz.add(createFastPathExecuteMethod(null, type, usedTypes)); 430 clazz.add(createFastPathExecuteMethod(null, type, usedTypes));
419 } 431 }
420 432
421 for (NodeExecutionData execution : node.getChildExecutions()) {
422 Collection<TypeMirror> specializedTypes = node.findSpecializedTypes(execution);
423 specializedTypes.add(genericType);
424 for (TypeMirror specializedType : specializedTypes) {
425 if (isExecuteChildShared(execution, specializedType)) {
426 clazz.add(createExecuteChildMethod(execution, specializedType));
427 }
428 }
429 }
430
431 return clazz; 433 return clazz;
432 } 434 }
433 435
434 private Element createAcceptAndExecute() { 436 private Element createAcceptAndExecute() {
435 437 ExecutableTypeData executableElement = createSpecializationNodeSignature(node.getSignatureSize());
436 TypeMirror[] parameters = new TypeMirror[node.getSignatureSize()]; 438 LocalContext currentLocals = LocalContext.load(this, executableElement, varArgsThreshold);
437 Arrays.fill(parameters, genericType); 439 CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false, varArgsThreshold);
438
439 ExecutableTypeData executableElement = new ExecutableTypeData(genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
440
441 LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold);
442 CodeExecutableElement executable = createExecuteMethod(null, executableElement, currentLocals, false);
443 440
444 executable.getModifiers().add(FINAL); 441 executable.getModifiers().add(FINAL);
445 CodeTreeBuilder builder = executable.createBuilder(); 442 CodeTreeBuilder builder = executable.createBuilder();
446 443
447 CodeTree receiver = CodeTreeBuilder.singleString("this"); 444 CodeTree receiver = CodeTreeBuilder.singleString("this");
448 445
449 builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null))); 446 builder.tree(createCallDelegateExecute(builder, receiver, currentLocals, executableElement, node.getGenericExecutableType(null)));
450 447
451 return executable; 448 return executable;
449 }
450
451 private ExecutableTypeData createSpecializationNodeSignature(int argumentCount) {
452 TypeMirror[] parameters = new TypeMirror[argumentCount];
453 Arrays.fill(parameters, genericType);
454 return new ExecutableTypeData(node, genericType, "acceptAndExecute", context.getType(Frame.class), Arrays.asList(parameters));
452 } 455 }
453 456
454 private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) { 457 private boolean shouldImplementExecutableType(SpecializationData specialization, ExecutableTypeData executableType) {
455 // always implement the root execute method. they are declared abstract in the base node. 458 // always implement the root execute method. they are declared abstract in the base node.
456 if (executableType.getDelegatedTo() == null) { 459 if (executableType.getDelegatedTo() == null) {
457 return true; 460 return true;
458 } 461 }
459 462
460 // specializations with more parameters are just ignored 463 // specializations with more parameters are just ignored
461 if (executableType.getEvaluatedCount() > node.getSignatureSize()) { 464 if (executableType.getEvaluatedCount() > node.getExecutionCount()) {
462 return false; 465 return false;
463 } 466 }
464 467
465 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) { 468 if (!isSubtypeBoxed(context, specialization.getReturnType().getType(), executableType.getReturnType())) {
466 return false; 469 return false;
467 } 470 }
468 471
469 // the evaluated signature might be compatible to the specialization 472 // the evaluated signature might be compatible to the specialization
470 boolean specializationCompatible = true; 473 boolean specializationCompatible = true;
471 for (int i = 0; i < executableType.getEvaluatedCount(); i++) { 474 List<TypeMirror> signatureParameters = executableType.getSignatureParameters();
472 TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); 475 for (int i = 0; i < signatureParameters.size(); i++) {
476 TypeMirror evaluatedType = signatureParameters.get(i);
473 TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType(); 477 TypeMirror specializedType = specialization.findParameterOrDie(node.getChildExecutions().get(i)).getType();
474 478
475 if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) { 479 if (!isSubtypeBoxed(context, evaluatedType, specializedType) && !isSubtypeBoxed(context, specializedType, evaluatedType)) {
476 specializationCompatible = false; 480 specializationCompatible = false;
477 break; 481 break;
487 return true; 491 return true;
488 } 492 }
489 } 493 }
490 494
491 // trigger type boxing elimination for unevaluated arguments 495 // trigger type boxing elimination for unevaluated arguments
492 for (int i = executableType.getEvaluatedCount(); i < node.getSignatureSize(); i++) { 496 for (int i = executableType.getEvaluatedCount(); i < node.getExecutionCount(); i++) {
493 NodeExecutionData execution = node.getChildExecutions().get(i); 497 NodeExecutionData execution = node.getChildExecutions().get(i);
494 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); 498 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
495 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) { 499 if (isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), specializedType)) {
496 // it does not make sense to do type boxing elimination for children with 500 // it does not make sense to do type boxing elimination for children with
497 // no type specialized execute method 501 // no type specialized execute method
510 return true; 514 return true;
511 } 515 }
512 } 516 }
513 517
514 // trigger generation for evaluated assignable type matches other than generic 518 // trigger generation for evaluated assignable type matches other than generic
515 for (int i = 0; i < executableType.getEvaluatedCount(); i++) { 519 for (int i = 0; i < signatureParameters.size(); i++) {
516 TypeMirror evaluatedType = executableType.getEvaluatedParameters().get(i); 520 TypeMirror evaluatedType = signatureParameters.get(i);
517 NodeExecutionData execution = node.getChildExecutions().get(i); 521 NodeExecutionData execution = node.getChildExecutions().get(i);
518 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType(); 522 TypeMirror specializedType = specialization.findParameterOrDie(execution).getType();
519 523
520 if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) { 524 if (isSubtypeBoxed(context, evaluatedType, specializedType) && !isObject(specializedType)) {
521 return true; 525 return true;
662 boolean cacheBoundGuard = specialization.hasMultipleInstances(); 666 boolean cacheBoundGuard = specialization.hasMultipleInstances();
663 if (!cacheBoundGuard) { 667 if (!cacheBoundGuard) {
664 return null; 668 return null;
665 } 669 }
666 670
667 LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); 671 LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
668 currentLocals.loadFastPathState(specialization); 672 currentLocals.loadFastPathState(specialization);
669 673
670 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical"); 674 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isIdentical");
671 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); 675 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other"));
672 currentLocals.addParametersTo(method, FRAME_VALUE); 676 currentLocals.addParametersTo(method, varArgsThreshold, FRAME_VALUE);
673 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); 677 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
674 final CodeTreeBuilder builder = method.createBuilder(); 678 final CodeTreeBuilder builder = method.createBuilder();
675 679
676 SpecializationGroup group = SpecializationGroup.create(specialization); 680 SpecializationGroup group = SpecializationGroup.create(specialization);
677 SpecializationBody executionFactory = new SpecializationBody(true, false) { 681 SpecializationBody executionFactory = new SpecializationBody(true, false) {
727 private Element createMergeMethod(SpecializationData specialization) { 731 private Element createMergeMethod(SpecializationData specialization) {
728 if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { 732 if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) {
729 return null; 733 return null;
730 } 734 }
731 TypeMirror specializationNodeType = getType(SpecializationNode.class); 735 TypeMirror specializationNodeType = getType(SpecializationNode.class);
732 LocalContext currentLocals = LocalContext.load(this, node.getSignatureSize(), varArgsThreshold); 736 LocalContext currentLocals = LocalContext.load(this, createSpecializationNodeSignature(node.getSignatureSize()), varArgsThreshold);
733 737
734 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); 738 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge");
735 executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); 739 executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode"));
736 currentLocals.addParametersTo(executable, FRAME_VALUE); 740 currentLocals.addParametersTo(executable, varArgsThreshold, FRAME_VALUE);
737 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); 741 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
738 CodeTreeBuilder builder = executable.createBuilder(); 742 CodeTreeBuilder builder = executable.createBuilder();
739 743
740 if (specialization.isPolymorphic()) { 744 if (specialization.isPolymorphic()) {
741 builder.startReturn(); 745 builder.startReturn();
800 } 804 }
801 805
802 private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) { 806 private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) {
803 final LocalContext locals = LocalContext.load(this); 807 final LocalContext locals = LocalContext.load(this);
804 808
805 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE); 809 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", varArgsThreshold, FRAME_VALUE);
806 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); 810 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
807 811
808 CodeTreeBuilder builder = method.createBuilder(); 812 CodeTreeBuilder builder = method.createBuilder();
809 SpecializationGroup group = createSpecializationGroups(); 813 SpecializationGroup group = createSpecializationGroups();
810 CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) { 814 CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationBody(false, false) {
832 836
833 if (!frameUsed) { 837 if (!frameUsed) {
834 locals.removeValue(FRAME_VALUE); 838 locals.removeValue(FRAME_VALUE);
835 } 839 }
836 840
837 CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE); 841 CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", varArgsThreshold, FRAME_VALUE);
838 if (!frameUsed) { 842 if (!frameUsed) {
839 boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class))); 843 boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class)));
840 } 844 }
841 845
842 CodeTreeBuilder builder = boundaryMethod.createBuilder(); 846 CodeTreeBuilder builder = boundaryMethod.createBuilder();
885 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { 889 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) {
886 return null; 890 return null;
887 } 891 }
888 LocalContext locals = LocalContext.load(this); 892 LocalContext locals = LocalContext.load(this);
889 893
890 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", FRAME_VALUE); 894 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType, "unsupported", varArgsThreshold, FRAME_VALUE);
891 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); 895 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class)));
892 896
893 CodeTreeBuilder builder = method.createBuilder(); 897 CodeTreeBuilder builder = method.createBuilder();
894 builder.startReturn(); 898 builder.startReturn();
895 builder.tree(callTemplateMethod(accessParent(null), fallback, locals)); 899 builder.tree(callTemplateMethod(accessParent(null), fallback, locals));
948 throw new AssertionError(); 952 throw new AssertionError();
949 } 953 }
950 } 954 }
951 955
952 private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) { 956 private CodeExecutableElement createExecutableTypeOverride(List<ExecutableTypeData> usedExecutables, ExecutableTypeData execType) {
953 LocalContext locals = LocalContext.load(this, execType.getEvaluatedCount(), Integer.MAX_VALUE); 957 LocalContext locals = LocalContext.load(this, execType, Integer.MAX_VALUE);
954 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true); 958 CodeExecutableElement method = createExecuteMethod(null, execType, locals, true, Integer.MAX_VALUE);
955 959
956 CodeTreeBuilder builder = method.createBuilder(); 960 CodeTreeBuilder builder = method.createBuilder();
957 if (singleSpecializable) { 961 if (singleSpecializable) {
958 SpecializationData specialization = reachableSpecializations.iterator().next(); 962 SpecializationData specialization = reachableSpecializations.iterator().next();
959 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals)); 963 builder.tree(createFastPath(builder, specialization, execType, usedExecutables, locals));
1041 values.add(CodeTreeBuilder.singleString("null")); 1045 values.add(CodeTreeBuilder.singleString("null"));
1042 } else { 1046 } else {
1043 values.add(createTypeSafeReference(frameLocal, method.getFrameParameter())); 1047 values.add(createTypeSafeReference(frameLocal, method.getFrameParameter()));
1044 } 1048 }
1045 } 1049 }
1046 for (int parameterIndex = 0; parameterIndex < method.getEvaluatedCount(); parameterIndex++) { 1050
1047 TypeMirror targetParameter = method.getEvaluatedParameters().get(parameterIndex); 1051 int evaluatedIndex = 0;
1048 LocalVariable variable; 1052 for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
1049 if (executeWith != null && parameterIndex < executeWith.size()) { 1053 NodeExecutionData parameterExecution;
1050 variable = currentValues.getValue(executeWith.get(parameterIndex)); 1054 if (executeWith != null && executionIndex < executeWith.size()) {
1055 parameterExecution = executeWith.get(executionIndex);
1051 } else { 1056 } else {
1052 variable = currentValues.getValue(parameterIndex); 1057 parameterExecution = node.getChildExecutions().get(executionIndex);
1053 } 1058 }
1054 values.add(createTypeSafeReference(variable, targetParameter)); 1059 if (parameterExecution.isShortCircuit()) {
1055 } 1060 if (evaluatedIndex < method.getEvaluatedCount()) {
1056 1061 TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
1062 LocalVariable shortCircuit = currentValues.getShortCircuit(parameterExecution);
1063 if (shortCircuit != null) {
1064 values.add(createTypeSafeReference(shortCircuit, targetType));
1065 } else {
1066 values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
1067 }
1068 evaluatedIndex++;
1069 }
1070 }
1071 if (evaluatedIndex < method.getEvaluatedCount()) {
1072 TypeMirror targetType = method.getEvaluatedParameters().get(evaluatedIndex);
1073 LocalVariable value = currentValues.getValue(parameterExecution);
1074 if (value != null) {
1075 values.add(createTypeSafeReference(value, targetType));
1076 } else {
1077 values.add(CodeTreeBuilder.createBuilder().defaultValue(targetType).build());
1078 }
1079 evaluatedIndex++;
1080 }
1081 }
1057 return values.toArray(new CodeTree[values.size()]); 1082 return values.toArray(new CodeTree[values.size()]);
1058 } 1083 }
1059 1084
1060 private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) { 1085 private CodeTree callExecuteMethod(NodeExecutionData execution, ExecutableTypeData method, LocalContext currentValues) {
1061 CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null; 1086 CodeTree receiver = execution != null ? accessParent(nodeFieldName(execution)) : null;
1516 return content; 1541 return content;
1517 } 1542 }
1518 } 1543 }
1519 1544
1520 private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) { 1545 private CodeTree expect(TypeMirror sourceType, TypeMirror forType, CodeTree tree) {
1521 expectedTypes.add(forType); 1546 if (sourceType == null || ElementUtils.needsCastTo(sourceType, forType)) {
1522 return TypeSystemCodeGenerator.expect(typeSystem, sourceType, forType, tree); 1547 expectedTypes.add(forType);
1548 return TypeSystemCodeGenerator.expect(typeSystem, forType, tree);
1549 }
1550 return tree;
1523 } 1551 }
1524 1552
1525 private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) { 1553 private Set<ExecutableTypeData> findSpecializedExecutableTypes(NodeExecutionData execution, TypeMirror type) {
1526 if (execution.getChild() == null) { 1554 if (execution.getChild() == null) {
1527 return Collections.emptySet(); 1555 return Collections.emptySet();
1552 } 1580 }
1553 return false; 1581 return false;
1554 } 1582 }
1555 1583
1556 private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) { 1584 private Element createFastPathExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, List<ExecutableTypeData> allTypes) {
1557 LocalContext currentLocals = LocalContext.load(this, executedType.getEvaluatedCount(), varArgsThreshold); 1585 LocalContext currentLocals = LocalContext.load(this, executedType, Integer.MAX_VALUE);
1558 CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false); 1586 CodeExecutableElement executable = createExecuteMethod(specialization, executedType, currentLocals, false, Integer.MAX_VALUE);
1559 CodeTreeBuilder builder = executable.createBuilder(); 1587 CodeTreeBuilder builder = executable.createBuilder();
1560 if (specialization == null) { 1588 if (specialization == null) {
1561 if (executedType.getDelegatedTo() == null) { 1589 if (executedType.getDelegatedTo() == null) {
1562 executable.getModifiers().add(ABSTRACT); 1590 executable.getModifiers().add(ABSTRACT);
1563 } 1591 }
1567 builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals)); 1595 builder.tree(createFastPath(builder, specialization, executedType, allTypes, currentLocals));
1568 1596
1569 return executable; 1597 return executable;
1570 } 1598 }
1571 1599
1572 private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride) { 1600 private static final String VARARGS_NAME = "args";
1601
1602 private CodeExecutableElement createExecuteMethod(SpecializationData specialization, ExecutableTypeData executedType, LocalContext currentLocals, boolean originalOverride, int varArgs) {
1573 TypeMirror returnType = executedType.getReturnType(); 1603 TypeMirror returnType = executedType.getReturnType();
1574 TypeMirror frame = executedType.getFrameParameter();
1575 List<TypeMirror> evaluatedParameters = executedType.getEvaluatedParameters();
1576 1604
1577 if (specialization != null) { 1605 if (specialization != null) {
1578 currentLocals.loadFastPathState(specialization); 1606 currentLocals.loadFastPathState(specialization);
1579 } 1607 }
1580 1608
1581 if (frame == null) {
1582 currentLocals.removeValue(FRAME_VALUE);
1583 } else {
1584 currentLocals.set(FRAME_VALUE, currentLocals.get(FRAME_VALUE).newType(frame));
1585 }
1586
1587 for (int i = 0; i < Math.min(node.getChildExecutions().size(), evaluatedParameters.size()); i++) {
1588 NodeExecutionData execution = node.getChildExecutions().get(i);
1589 currentLocals.setValue(execution, currentLocals.getValue(execution).newType(evaluatedParameters.get(i)));
1590 }
1591
1592 String methodName; 1609 String methodName;
1593 if (originalOverride) { 1610 if (originalOverride && executedType.getMethod() != null) {
1594 methodName = executedType.getMethod().getSimpleName().toString(); 1611 methodName = executedType.getMethod().getSimpleName().toString();
1595 } else { 1612 } else {
1596 methodName = executedType.getUniqueName(); 1613 methodName = executedType.getUniqueName();
1597 } 1614 }
1598 1615
1606 } 1623 }
1607 if (executedType.getFrameParameter() != null) { 1624 if (executedType.getFrameParameter() != null) {
1608 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE); 1625 ((CodeVariableElement) executable.getParameters().get(0)).setName(FRAME_VALUE);
1609 } 1626 }
1610 1627
1611 final String varArgsName = "args";
1612 if (executable.isVarArgs()) { 1628 if (executable.isVarArgs()) {
1613 ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(varArgsName); 1629 ((CodeVariableElement) executable.getParameters().get(executable.getParameters().size() - 1)).setName(VARARGS_NAME);
1614 } 1630 }
1615 1631
1616 // rename varargs parameter 1632 renameOriginalParameters(executedType, executable, currentLocals);
1617 int signatureIndex = 0; 1633 } else {
1618 for (TypeMirror parameter : executedType.getEvaluatedParameters()) { 1634 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, varArgs, FRAME_VALUE);
1619 LocalVariable var = currentLocals.getValue(signatureIndex);
1620 if (var != null) {
1621 int varArgsIndex = executedType.getVarArgsIndex(executedType.getParameterIndex(signatureIndex));
1622 if (varArgsIndex >= 0) {
1623 var = var.accessWith(CodeTreeBuilder.singleString(varArgsName + "[" + varArgsIndex + "]"));
1624 } else {
1625 ((CodeVariableElement) executable.getParameters().get(executedType.getParameterIndex(signatureIndex))).setName(var.getName());
1626 }
1627 if (!isObject(parameter)) {
1628 var = var.newType(parameter);
1629 }
1630 currentLocals.setValue(node.getChildExecutions().get(signatureIndex), var);
1631 }
1632
1633 signatureIndex++;
1634 }
1635 } else {
1636 executable = currentLocals.createMethod(modifiers(PUBLIC), returnType, methodName, FRAME_VALUE);
1637 } 1635 }
1638 executable.getThrownTypes().clear(); 1636 executable.getThrownTypes().clear();
1639 1637
1640 if (needsUnexpectedResultException(executedType)) { 1638 if (needsUnexpectedResultException(executedType)) {
1641 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class)); 1639 executable.getThrownTypes().add(context.getDeclaredType(UnexpectedResultException.class));
1642 } 1640 }
1643 1641
1644 return executable; 1642 return executable;
1643 }
1644
1645 private void renameOriginalParameters(ExecutableTypeData executedType, CodeExecutableElement executable, LocalContext currentLocals) {
1646 // rename varargs parameter
1647 int evaluatedIndex = 0;
1648 for (int executionIndex = 0; executionIndex < node.getExecutionCount(); executionIndex++) {
1649 NodeExecutionData execution = node.getChildExecutions().get(executionIndex);
1650 if (execution.isShortCircuit()) {
1651 if (evaluatedIndex < executedType.getEvaluatedCount()) {
1652 TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
1653 LocalVariable shortCircuit = currentLocals.getShortCircuit(execution);
1654 if (shortCircuit != null) {
1655 currentLocals.setShortCircuitValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, shortCircuit));
1656 }
1657 evaluatedIndex++;
1658 }
1659 }
1660 if (evaluatedIndex < executedType.getEvaluatedCount()) {
1661 TypeMirror evaluatedType = executedType.getEvaluatedParameters().get(evaluatedIndex);
1662 LocalVariable value = currentLocals.getValue(execution);
1663 if (value != null) {
1664 currentLocals.setValue(execution, renameExecutableTypeParameter(executable, executedType, evaluatedIndex, evaluatedType, value));
1665 }
1666 evaluatedIndex++;
1667 }
1668 }
1669 }
1670
1671 private static LocalVariable renameExecutableTypeParameter(CodeExecutableElement method, ExecutableTypeData executedType, int evaluatedIndex, TypeMirror targetType, LocalVariable var) {
1672 int parameterIndex = executedType.getParameterIndex(evaluatedIndex);
1673 int varArgsIndex = executedType.getVarArgsIndex(parameterIndex);
1674 LocalVariable returnVar = var;
1675 if (varArgsIndex >= 0) {
1676 returnVar = returnVar.accessWith(CodeTreeBuilder.singleString(VARARGS_NAME + "[" + varArgsIndex + "]"));
1677 } else {
1678 ((CodeVariableElement) method.getParameters().get(parameterIndex)).setName(returnVar.getName());
1679 }
1680 if (!isObject(targetType)) {
1681 returnVar = returnVar.newType(targetType);
1682 }
1683 return returnVar;
1645 } 1684 }
1646 1685
1647 private boolean needsUnexpectedResultException(ExecutableTypeData executedType) { 1686 private boolean needsUnexpectedResultException(ExecutableTypeData executedType) {
1648 if (!executedType.hasUnexpectedValue(context)) { 1687 if (!executedType.hasUnexpectedValue(context)) {
1649 return false; 1688 return false;
1668 1707
1669 if (delegate == null) { 1708 if (delegate == null) {
1670 delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes); 1709 delegate = findFastPathDelegate((specialization != null ? specialization.getReturnType().getType() : genericType), executableType, allTypes);
1671 } 1710 }
1672 1711
1712 int delegateSignatureCount = delegate != null ? delegate.getSignatureParameters().size() : 0;
1673 for (NodeExecutionData execution : node.getChildExecutions()) { 1713 for (NodeExecutionData execution : node.getChildExecutions()) {
1674 if (specialization == null && delegate != null && execution.getIndex() >= delegate.getEvaluatedCount()) { 1714 if (specialization == null && delegate != null && execution.getIndex() >= delegateSignatureCount) {
1675 // we just evaluate children for the next delegate 1715 // we just evaluate children for the next delegate
1676 continue; 1716 continue;
1677 } else if (specialization != null && delegate != null) { 1717 } else if (specialization != null && delegate != null) {
1678 // skip if already delegated 1718 // skip if already delegated
1679 break; 1719 break;
1792 } 1832 }
1793 } 1833 }
1794 1834
1795 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { 1835 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) {
1796 LocalVariable shortCircuit = null; 1836 LocalVariable shortCircuit = null;
1797 SpecializationData resolvedSpecialization = specialization;
1798 if (specialization == null) {
1799 resolvedSpecialization = node.getGenericSpecialization();
1800 }
1801
1802 if (execution.isShortCircuit()) { 1837 if (execution.isShortCircuit()) {
1803 ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); 1838 shortCircuit = currentLocals.getShortCircuit(execution);
1804 CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals); 1839
1805 shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); 1840 if (shortCircuit == null) {
1841 SpecializationData resolvedSpecialization = specialization;
1842 if (specialization == null) {
1843 resolvedSpecialization = node.getGenericSpecialization();
1844 }
1845 ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution));
1846 CodeTree access = callTemplateMethod(accessParent(null), shortCircuitData, currentLocals);
1847 shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access);
1848 } else {
1849 CodeTree access = shortCircuit.createReference();
1850 shortCircuit = shortCircuit.nextName().accessWith(access);
1851 }
1806 } 1852 }
1807 return shortCircuit; 1853 return shortCircuit;
1808 } 1854 }
1809 1855
1810 private int calculateShortCircuitIndex(NodeExecutionData execution) { 1856 private int calculateShortCircuitIndex(NodeExecutionData execution) {
2014 } 2060 }
2015 return false; 2061 return false;
2016 } 2062 }
2017 2063
2018 private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) { 2064 private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeMirror targetType) {
2019 LocalContext locals = LocalContext.load(this, 0, varArgsThreshold); 2065 if (!usedExecuteChildMethods.contains(execution)) {
2020 2066 return null;
2021 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), FRAME_VALUE); 2067 }
2068
2069 LocalContext locals = LocalContext.load(this, createSpecializationNodeSignature(0), Integer.MAX_VALUE);
2070
2071 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType, executeChildMethodName(execution, targetType), Integer.MAX_VALUE, FRAME_VALUE);
2022 if (hasChildUnexpectedResult(execution, targetType)) { 2072 if (hasChildUnexpectedResult(execution, targetType)) {
2023 method.getThrownTypes().add(getType(UnexpectedResultException.class)); 2073 method.getThrownTypes().add(getType(UnexpectedResultException.class));
2024 } 2074 }
2025 2075
2026 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType); 2076 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType);
2045 return method; 2095 return method;
2046 } 2096 }
2047 2097
2048 private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) { 2098 private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeMirror targetType) {
2049 if (typeSystem.hasImplicitSourceTypes(targetType)) { 2099 if (typeSystem.hasImplicitSourceTypes(targetType)) {
2100 if (typeEquals(node.getGenericType(execution), targetType)) {
2101 return null;
2102 }
2103
2050 switch (options.implicitCastOptimization()) { 2104 switch (options.implicitCastOptimization()) {
2051 case NONE: 2105 case NONE:
2052 return null; 2106 return null;
2053 case DUPLICATE_TAIL: 2107 case DUPLICATE_TAIL:
2054 return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution)); 2108 return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution));
2183 2237
2184 private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) { 2238 private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) {
2185 if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) { 2239 if (!isExecuteChildShared(execution, targetValue.getTypeMirror())) {
2186 throw new AssertionError("Execute child not shared with method but called."); 2240 throw new AssertionError("Execute child not shared with method but called.");
2187 } 2241 }
2242 usedExecuteChildMethods.add(execution);
2188 2243
2189 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); 2244 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder();
2190 builder.tree(targetValue.createReference()).string(" = "); 2245 builder.tree(targetValue.createReference()).string(" = ");
2191 builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror())); 2246 builder.startCall(executeChildMethodName(execution, targetValue.getTypeMirror()));
2192 if (currentValues.get(FRAME_VALUE) == null) { 2247 if (currentValues.get(FRAME_VALUE) == null) {
2592 TypeMirror type = assumption.getExpression().getResolvedType(); 2647 TypeMirror type = assumption.getExpression().getResolvedType();
2593 set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null)); 2648 set(name, new LocalVariable(type, name, CodeTreeBuilder.singleString("this." + name), null));
2594 } 2649 }
2595 } 2650 }
2596 2651
2597 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) { 2652 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, int varArgsThreshold, String... optionalArguments) {
2598 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); 2653 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name);
2599 addParametersTo(method, optionalArguments); 2654 addParametersTo(method, varArgsThreshold, optionalArguments);
2600 return method; 2655 return method;
2601 } 2656 }
2602 2657
2603 public static LocalContext load(NodeGenFactory factory, int signatureSize, int varargsThreshold) { 2658 public static LocalContext load(NodeGenFactory factory, ExecutableTypeData type, int varargsThreshold) {
2604 LocalContext context = new LocalContext(factory); 2659 LocalContext context = new LocalContext(factory);
2605 context.loadValues(signatureSize, varargsThreshold); 2660 context.loadEvaluatedValues(type, varargsThreshold);
2606 return context; 2661 return context;
2607 } 2662 }
2608 2663
2664 private void loadEvaluatedValues(ExecutableTypeData executedType, int varargsThreshold) {
2665 TypeMirror frame = executedType.getFrameParameter();
2666 if (frame == null) {
2667 removeValue(FRAME_VALUE);
2668 } else {
2669 set(FRAME_VALUE, new LocalVariable(frame, FRAME_VALUE, null, null));
2670 }
2671 for (NodeFieldData field : factory.node.getFields()) {
2672 String fieldName = fieldValueName(field);
2673 values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
2674 }
2675 boolean varargs = needsVarargs(false, varargsThreshold);
2676 List<TypeMirror> evaluatedParameter = executedType.getEvaluatedParameters();
2677 int evaluatedIndex = 0;
2678 for (int executionIndex = 0; executionIndex < factory.node.getExecutionCount(); executionIndex++) {
2679 NodeExecutionData execution = factory.node.getChildExecutions().get(executionIndex);
2680 if (execution.isShortCircuit()) {
2681 if (evaluatedIndex < executedType.getEvaluatedCount()) {
2682 TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
2683 LocalVariable shortCircuit = createShortCircuitValue(execution).newType(evaluatedType);
2684 if (varargs) {
2685 shortCircuit = shortCircuit.accessWith(createReadVarargs(evaluatedIndex));
2686 }
2687 values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
2688 evaluatedIndex++;
2689 }
2690 }
2691 if (evaluatedIndex < executedType.getEvaluatedCount()) {
2692 TypeMirror evaluatedType = evaluatedParameter.get(evaluatedIndex);
2693 LocalVariable value = createValue(execution, evaluatedType);
2694 if (varargs) {
2695 value = value.accessWith(createReadVarargs(evaluatedIndex));
2696 }
2697 values.put(value.getName(), value.makeOriginal());
2698 evaluatedIndex++;
2699 }
2700 }
2701 }
2702
2609 public static LocalContext load(NodeGenFactory factory) { 2703 public static LocalContext load(NodeGenFactory factory) {
2610 return load(factory, factory.node.getSignatureSize(), factory.varArgsThreshold); 2704 return load(factory, factory.createSpecializationNodeSignature(factory.node.getSignatureSize()), factory.varArgsThreshold);
2611 } 2705 }
2612 2706
2613 public LocalContext copy() { 2707 public LocalContext copy() {
2614 LocalContext copy = new LocalContext(factory); 2708 LocalContext copy = new LocalContext(factory);
2615 copy.values.putAll(values); 2709 copy.values.putAll(values);
2697 } else { 2791 } else {
2698 size++; 2792 size++;
2699 } 2793 }
2700 } 2794 }
2701 return size >= varArgsThreshold; 2795 return size >= varArgsThreshold;
2702 }
2703
2704 private void loadValues(int evaluatedArguments, int varargsThreshold) {
2705 values.put(FRAME_VALUE, new LocalVariable(factory.getType(Frame.class), FRAME_VALUE, null, null));
2706
2707 for (NodeFieldData field : factory.node.getFields()) {
2708 String fieldName = fieldValueName(field);
2709 values.put(fieldName, new LocalVariable(field.getType(), fieldName, factory.accessParent(field.getName()), null));
2710 }
2711
2712 boolean varargs = needsVarargs(false, varargsThreshold);
2713 for (int i = 0; i < evaluatedArguments; i++) {
2714 List<NodeExecutionData> childExecutions = factory.node.getChildExecutions();
2715 if (i >= childExecutions.size()) {
2716 break;
2717 }
2718 NodeExecutionData execution = childExecutions.get(i);
2719 if (execution.isShortCircuit()) {
2720 LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(factory.context);
2721 if (varargs) {
2722 shortCircuit = shortCircuit.accessWith(createReadVarargs(i));
2723 }
2724 values.put(shortCircuit.getName(), shortCircuit.makeOriginal());
2725 }
2726 LocalVariable value = createValue(execution, factory.genericType);
2727 if (varargs) {
2728 value = value.accessWith(createReadVarargs(i));
2729 }
2730 values.put(value.getName(), value.makeOriginal());
2731 }
2732 } 2796 }
2733 2797
2734 private static CodeTree createReadVarargs(int i) { 2798 private static CodeTree createReadVarargs(int i) {
2735 return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build(); 2799 return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build();
2736 } 2800 }
2764 builder.end(); 2828 builder.end();
2765 } 2829 }
2766 } 2830 }
2767 } 2831 }
2768 2832
2769 public void addParametersTo(CodeExecutableElement method, String... optionalNames) { 2833 public void addParametersTo(CodeExecutableElement method, int varArgsThreshold, String... optionalNames) {
2770 for (String var : optionalNames) { 2834 for (String var : optionalNames) {
2771 LocalVariable local = values.get(var); 2835 LocalVariable local = values.get(var);
2772 if (local != null) { 2836 if (local != null) {
2773 method.addParameter(local.createParameter()); 2837 method.addParameter(local.createParameter());
2774 } 2838 }
2775 } 2839 }
2776 if (needsVarargs(true, factory.varArgsThreshold)) { 2840 if (needsVarargs(true, varArgsThreshold)) {
2777 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_")); 2841 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_"));
2778 method.setVarArgs(true); 2842 method.setVarArgs(true);
2779 } else { 2843 } else {
2780 for (NodeExecutionData execution : factory.node.getChildExecutions()) { 2844 for (NodeExecutionData execution : factory.node.getChildExecutions()) {
2781 if (execution.isShortCircuit()) { 2845 if (execution.isShortCircuit()) {