Mercurial > hg > truffle
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 19291:f4792a544170
Truffle-DSL: implement new assumptions semantics.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Wed, 11 Feb 2015 12:13:44 +0100 |
parents | 62c43fcf5be2 |
children | 21b9b9941775 |
comparison
equal
deleted
inserted
replaced
19290:bf166845c7d8 | 19291:f4792a544170 |
---|---|
30 | 30 |
31 import javax.lang.model.element.*; | 31 import javax.lang.model.element.*; |
32 import javax.lang.model.type.*; | 32 import javax.lang.model.type.*; |
33 import javax.lang.model.util.*; | 33 import javax.lang.model.util.*; |
34 | 34 |
35 import com.oracle.truffle.api.*; | |
36 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; | 35 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; |
37 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; | 36 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; |
38 import com.oracle.truffle.api.dsl.*; | 37 import com.oracle.truffle.api.dsl.*; |
39 import com.oracle.truffle.api.dsl.internal.*; | 38 import com.oracle.truffle.api.dsl.internal.*; |
40 import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization; | 39 import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization; |
72 this.node = node; | 71 this.node = node; |
73 this.typeSystem = node.getTypeSystem(); | 72 this.typeSystem = node.getTypeSystem(); |
74 this.genericType = typeSystem.getGenericTypeData(); | 73 this.genericType = typeSystem.getGenericTypeData(); |
75 this.options = typeSystem.getOptions(); | 74 this.options = typeSystem.getOptions(); |
76 this.singleSpecializable = isSingleSpecializableImpl(); | 75 this.singleSpecializable = isSingleSpecializableImpl(); |
77 this.varArgsThreshold = calculateVarArgsThresHold(); | 76 this.varArgsThreshold = calculateVarArgsThreshold(); |
78 | 77 } |
79 } | 78 |
80 | 79 private int calculateVarArgsThreshold() { |
81 private int calculateVarArgsThresHold() { | |
82 TypeMirror specialization = context.getType(SpecializationNode.class); | 80 TypeMirror specialization = context.getType(SpecializationNode.class); |
83 TypeElement specializationType = fromTypeMirror(specialization); | 81 TypeElement specializationType = fromTypeMirror(specialization); |
84 | 82 |
85 int maxParameters = 0; | 83 int maxParameters = 0; |
86 for (ExecutableElement element : ElementFilter.methodsIn(specializationType.getEnclosedElements())) { | 84 for (ExecutableElement element : ElementFilter.methodsIn(specializationType.getEnclosedElements())) { |
91 return maxParameters; | 89 return maxParameters; |
92 } | 90 } |
93 | 91 |
94 public static String nodeTypeName(NodeData node) { | 92 public static String nodeTypeName(NodeData node) { |
95 return resolveNodeId(node) + NODE_SUFFIX; | 93 return resolveNodeId(node) + NODE_SUFFIX; |
94 } | |
95 | |
96 private static String assumptionName(AssumptionExpression assumption) { | |
97 return assumption.getId() + NAME_SUFFIX; | |
96 } | 98 } |
97 | 99 |
98 private static String resolveNodeId(NodeData node) { | 100 private static String resolveNodeId(NodeData node) { |
99 String nodeid = node.getNodeId(); | 101 String nodeid = node.getNodeId(); |
100 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | 102 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { |
155 return CodeTreeBuilder.createBuilder().string("root.").string(name).build(); | 157 return CodeTreeBuilder.createBuilder().string("root.").string(name).build(); |
156 } | 158 } |
157 } | 159 } |
158 } | 160 } |
159 | 161 |
160 private static String assumptionName(String assumption) { | |
161 return assumption + "_"; | |
162 } | |
163 | |
164 public CodeTypeElement create() { | 162 public CodeTypeElement create() { |
165 CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(FINAL), nodeTypeName(node), node.getTemplateType().asType()); | 163 CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(FINAL), nodeTypeName(node), node.getTemplateType().asType()); |
166 ElementUtils.setVisibility(clazz.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); | 164 ElementUtils.setVisibility(clazz.getModifiers(), ElementUtils.getVisibility(node.getTemplateType().getModifiers())); |
167 | |
168 for (String assumption : node.getAssumptions()) { | |
169 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption))); | |
170 } | |
171 | 165 |
172 for (NodeChildData child : node.getChildren()) { | 166 for (NodeChildData child : node.getChildren()) { |
173 clazz.addOptional(createAccessChildMethod(child)); | 167 clazz.addOptional(createAccessChildMethod(child)); |
174 } | 168 } |
175 | 169 |
755 TypeData type = parameter.getTypeSystemType(); | 749 TypeData type = parameter.getTypeSystemType(); |
756 if (type != null && type.hasImplicitSourceTypes()) { | 750 if (type != null && type.hasImplicitSourceTypes()) { |
757 return false; | 751 return false; |
758 } | 752 } |
759 } | 753 } |
754 | |
755 if (!specialization.getAssumptionExpressions().isEmpty()) { | |
756 return false; | |
757 } | |
758 | |
760 if (specialization.getCaches().size() > 0) { | 759 if (specialization.getCaches().size() > 0) { |
761 // TODO chumer: caches do not yet support single specialization. | 760 // TODO chumer: caches do not yet support single specialization. |
762 // it could be worthwhile to explore if this is possible | 761 // it could be worthwhile to explore if this is possible |
763 return false; | 762 return false; |
764 } | 763 } |
828 SpecializationData specialization = getReachableSpecializations().iterator().next(); | 827 SpecializationData specialization = getReachableSpecializations().iterator().next(); |
829 ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType); | 828 ExecutableTypeData wrappedExecutableType = findWrappedExecutable(specialization, implementedExecutables, execType); |
830 if (wrappedExecutableType != null) { | 829 if (wrappedExecutableType != null) { |
831 builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end(); | 830 builder.startReturn().tree(callTemplateMethod(null, wrappedExecutableType, locals)).end(); |
832 } else { | 831 } else { |
833 builder.tree(createFastPathExecute(builder, specialization, execType.getType(), locals)); | 832 builder.tree(createFastPath(builder, specialization, execType.getType(), locals)); |
834 } | 833 } |
835 } else { | 834 } else { |
836 // create acceptAndExecute | 835 // create acceptAndExecute |
837 CodeTreeBuilder executeBuilder = builder.create(); | 836 CodeTreeBuilder executeBuilder = builder.create(); |
838 executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); | 837 executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); |
986 if (tree != null) { | 985 if (tree != null) { |
987 builder.tree(tree); | 986 builder.tree(tree); |
988 continue; | 987 continue; |
989 } | 988 } |
990 } | 989 } |
991 builder.string(parameter.getLocalName()); | 990 |
991 builder.defaultValue(parameter.getType()); | |
992 } | 992 } |
993 builder.end(); | 993 builder.end(); |
994 return builder.build(); | 994 return builder.build(); |
995 } | 995 } |
996 | 996 |
1034 } | 1034 } |
1035 | 1035 |
1036 if (node.isFrameUsedByAnyGuard()) { | 1036 if (node.isFrameUsedByAnyGuard()) { |
1037 builder.tree(createTransferToInterpreterAndInvalidate()); | 1037 builder.tree(createTransferToInterpreterAndInvalidate()); |
1038 } | 1038 } |
1039 | |
1040 boolean hasAssumptions = !specialization.getAssumptionExpressions().isEmpty(); | |
1041 if (hasAssumptions) { | |
1042 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1043 CodeTree assumptions = DSLExpressionGenerator.write(assumption.getExpression(), accessParent(null), | |
1044 castBoundTypes(bindExpressionValues(assumption.getExpression(), specialization, currentValues))); | |
1045 String name = assumptionName(assumption); | |
1046 // needs specialization index for assumption to make unique | |
1047 String varName = name + specialization.getIndex(); | |
1048 TypeMirror type = assumption.getExpression().getResolvedType(); | |
1049 builder.declaration(type, varName, assumptions); | |
1050 currentValues.set(name, new LocalVariable(null, type, varName, null)); | |
1051 } | |
1052 | |
1053 builder.startIf(); | |
1054 String sep = ""; | |
1055 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1056 LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); | |
1057 if (assumptionVar == null) { | |
1058 throw new AssertionError("assumption var not resolved"); | |
1059 } | |
1060 builder.string(sep); | |
1061 builder.startCall("isValid").tree(assumptionVar.createReference()).end(); | |
1062 sep = " && "; | |
1063 } | |
1064 builder.end(); | |
1065 builder.startBlock(); | |
1066 } | |
1067 | |
1039 for (SpecializationData otherSpeciailzation : node.getSpecializations()) { | 1068 for (SpecializationData otherSpeciailzation : node.getSpecializations()) { |
1040 if (otherSpeciailzation == specialization) { | 1069 if (otherSpeciailzation == specialization) { |
1041 continue; | 1070 continue; |
1042 } | 1071 } |
1043 if (otherSpeciailzation.getExcludedBy().contains(specialization)) { | 1072 if (otherSpeciailzation.getExcludedBy().contains(specialization)) { |
1050 | 1079 |
1051 CodeTree create = createCallCreateMethod(specialization, null, currentValues); | 1080 CodeTree create = createCallCreateMethod(specialization, null, currentValues); |
1052 | 1081 |
1053 if (specialization.hasMultipleInstances()) { | 1082 if (specialization.hasMultipleInstances()) { |
1054 builder.declaration(getType(SpecializationNode.class), "s", create); | 1083 builder.declaration(getType(SpecializationNode.class), "s", create); |
1055 | |
1056 DSLExpression limitExpression = specialization.getLimitExpression(); | 1084 DSLExpression limitExpression = specialization.getLimitExpression(); |
1057 CodeTree limitExpressionTree; | 1085 CodeTree limitExpressionTree; |
1058 if (limitExpression == null) { | 1086 if (limitExpression == null) { |
1059 limitExpressionTree = CodeTreeBuilder.singleString("3"); | 1087 limitExpressionTree = CodeTreeBuilder.singleString("3"); |
1060 } else { | 1088 } else { |
1063 } | 1091 } |
1064 | 1092 |
1065 builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock(); | 1093 builder.startIf().string("countSame(s) < ").tree(limitExpressionTree).end().startBlock(); |
1066 builder.statement("return s"); | 1094 builder.statement("return s"); |
1067 builder.end(); | 1095 builder.end(); |
1068 | |
1069 } else { | 1096 } else { |
1070 builder.startReturn().tree(create).end(); | 1097 builder.startReturn().tree(create).end(); |
1098 } | |
1099 | |
1100 if (hasAssumptions) { | |
1101 builder.end(); | |
1071 } | 1102 } |
1072 | 1103 |
1073 if (mayBeExcluded(specialization)) { | 1104 if (mayBeExcluded(specialization)) { |
1074 CodeTreeBuilder checkHasSeenBuilder = builder.create(); | 1105 CodeTreeBuilder checkHasSeenBuilder = builder.create(); |
1075 checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); | 1106 checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); |
1110 | 1141 |
1111 if (!guards.isEmpty()) { | 1142 if (!guards.isEmpty()) { |
1112 return true; | 1143 return true; |
1113 } | 1144 } |
1114 | 1145 |
1115 if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) { | 1146 if (!fastPath && specialization != null && !specialization.getAssumptionExpressions().isEmpty()) { |
1116 return true; | 1147 return true; |
1117 } | 1148 } |
1118 | 1149 |
1119 if (!fastPath && specialization != null && mayBeExcluded(specialization)) { | 1150 if (!fastPath && specialization != null && mayBeExcluded(specialization)) { |
1120 return true; | 1151 return true; |
1191 if (variable == null) { | 1222 if (variable == null) { |
1192 throw new AssertionError("Could not bind cached value " + cache.getParameter().getLocalName() + ": " + currentValues); | 1223 throw new AssertionError("Could not bind cached value " + cache.getParameter().getLocalName() + ": " + currentValues); |
1193 } | 1224 } |
1194 builder.tree(variable.createReference()); | 1225 builder.tree(variable.createReference()); |
1195 } | 1226 } |
1196 | 1227 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { |
1228 LocalVariable variable = currentValues.get(assumptionName(assumption)); | |
1229 if (variable == null) { | |
1230 throw new AssertionError("Could not bind assumption value " + assumption.getId() + ": " + currentValues); | |
1231 } | |
1232 builder.tree(variable.createReference()); | |
1233 } | |
1197 } | 1234 } |
1198 builder.end(); | 1235 builder.end(); |
1199 | 1236 |
1200 return builder.build(); | 1237 return builder.build(); |
1201 } | 1238 } |
1285 } | 1322 } |
1286 constructor.addParameter(new CodeVariableElement(type, name)); | 1323 constructor.addParameter(new CodeVariableElement(type, name)); |
1287 builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); | 1324 builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); |
1288 } | 1325 } |
1289 | 1326 |
1327 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1328 String name = assumptionName(assumption); | |
1329 TypeMirror type = assumption.getExpression().getResolvedType(); | |
1330 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), type, name)); | |
1331 constructor.addParameter(new CodeVariableElement(type, name)); | |
1332 builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); | |
1333 } | |
1290 } | 1334 } |
1291 | 1335 |
1292 if (constructor.getParameters().isEmpty()) { | 1336 if (constructor.getParameters().isEmpty()) { |
1293 // do not generate default constructor | 1337 // do not generate default constructor |
1294 return null; | 1338 return null; |
1344 builder.tree(TypeSystemCodeGenerator.expect(genericType, forType, call)); | 1388 builder.tree(TypeSystemCodeGenerator.expect(genericType, forType, call)); |
1345 builder.end(); | 1389 builder.end(); |
1346 return builder.build(); | 1390 return builder.build(); |
1347 } | 1391 } |
1348 | 1392 |
1349 private static CodeTree createCallDelegate(String methodName, TypeData forType, LocalContext currentValues) { | 1393 private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { |
1350 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | 1394 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); |
1351 builder.startCall(methodName); | 1395 builder.startCall(methodName); |
1396 if (reason != null) { | |
1397 builder.doubleQuote(reason); | |
1398 } | |
1352 currentValues.addReferencesTo(builder, FRAME_VALUE); | 1399 currentValues.addReferencesTo(builder, FRAME_VALUE); |
1353 builder.end(); | 1400 builder.end(); |
1354 | 1401 |
1355 TypeData executedType = forType.getTypeSystem().getGenericTypeData(); | 1402 TypeData executedType = forType.getTypeSystem().getGenericTypeData(); |
1356 return TypeSystemCodeGenerator.expect(executedType, forType, builder.build()); | 1403 return TypeSystemCodeGenerator.expect(executedType, forType, builder.build()); |
1387 private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) { | 1434 private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) { |
1388 TypeData type = forType == null ? genericType : forType; | 1435 TypeData type = forType == null ? genericType : forType; |
1389 LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); | 1436 LocalContext currentLocals = LocalContext.load(this, evaluatedArguments, varArgsThreshold); |
1390 | 1437 |
1391 if (specialization != null) { | 1438 if (specialization != null) { |
1392 currentLocals.loadFastPathCachedValues(specialization); | 1439 currentLocals.loadFastPathState(specialization); |
1393 } | 1440 } |
1394 | 1441 |
1395 CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); | 1442 CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); |
1396 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | 1443 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); |
1397 | 1444 |
1398 if (!type.isGeneric()) { | 1445 if (!type.isGeneric()) { |
1399 executable.getThrownTypes().add(getType(UnexpectedResultException.class)); | 1446 executable.getThrownTypes().add(getType(UnexpectedResultException.class)); |
1400 } | 1447 } |
1401 | 1448 |
1402 CodeTreeBuilder builder = executable.createBuilder(); | 1449 CodeTreeBuilder builder = executable.createBuilder(); |
1403 builder.tree(createFastPathExecute(builder, specialization, type, currentLocals)); | 1450 builder.tree(createFastPath(builder, specialization, type, currentLocals)); |
1404 | 1451 |
1405 return executable; | 1452 return executable; |
1406 } | 1453 } |
1407 | 1454 |
1408 private CodeTree createFastPathExecute(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) { | 1455 private CodeTree createFastPath(CodeTreeBuilder parent, SpecializationData specialization, TypeData type, LocalContext currentLocals) { |
1409 final CodeTreeBuilder builder = parent.create(); | 1456 final CodeTreeBuilder builder = parent.create(); |
1410 | 1457 |
1411 for (NodeExecutionData execution : node.getChildExecutions()) { | 1458 for (NodeExecutionData execution : node.getChildExecutions()) { |
1412 LocalVariable var = currentLocals.getValue(execution); | 1459 LocalVariable var = currentLocals.getValue(execution); |
1413 if (var == null) { | 1460 if (var == null) { |
1424 } | 1471 } |
1425 } | 1472 } |
1426 | 1473 |
1427 LocalContext originalValues = currentLocals.copy(); | 1474 LocalContext originalValues = currentLocals.copy(); |
1428 if (specialization == null) { | 1475 if (specialization == null) { |
1429 builder.startReturn().tree(createCallDelegate("acceptAndExecute", type, currentLocals)).end(); | 1476 builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); |
1430 } else if (specialization.isPolymorphic()) { | 1477 } else if (specialization.isPolymorphic()) { |
1431 builder.tree(createCallNext(type, currentLocals)); | 1478 builder.tree(createCallNext(type, currentLocals)); |
1432 } else if (specialization.isUninitialized()) { | 1479 } else if (specialization.isUninitialized()) { |
1433 builder.startReturn().tree(createCallDelegate("uninitialized", type, currentLocals)).end(); | 1480 builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); |
1434 } else { | 1481 } else { |
1435 final TypeData finalType = type; | 1482 final TypeData finalType = type; |
1436 SpecializationGroup group = SpecializationGroup.create(specialization); | 1483 SpecializationGroup group = SpecializationGroup.create(specialization); |
1437 SpecializationExecution executionFactory = new SpecializationExecution() { | 1484 SpecializationExecution executionFactory = new SpecializationExecution() { |
1438 public CodeTree createExecute(SpecializationData s, LocalContext values) { | 1485 public CodeTree createExecute(SpecializationData s, LocalContext values) { |
1493 builder.end(); | 1540 builder.end(); |
1494 builder.startBlock(); | 1541 builder.startBlock(); |
1495 ifCount++; | 1542 ifCount++; |
1496 } | 1543 } |
1497 CodeTreeBuilder execute = builder.create(); | 1544 CodeTreeBuilder execute = builder.create(); |
1545 | |
1546 if (!specialization.getAssumptionExpressions().isEmpty()) { | |
1547 builder.startTryBlock(); | |
1548 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1549 LocalVariable assumptionVar = currentValues.get(assumptionName(assumption)); | |
1550 if (assumptionVar == null) { | |
1551 throw new AssertionError("Could not resolve assumption var " + currentValues); | |
1552 } | |
1553 builder.startStatement().startCall("check").tree(assumptionVar.createReference()).end().end(); | |
1554 } | |
1555 builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); | |
1556 builder.startReturn(); | |
1557 List<String> assumptionIds = new ArrayList<>(); | |
1558 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
1559 assumptionIds.add(assumption.getId()); | |
1560 } | |
1561 builder.tree(createCallDelegate("removeThis", String.format("Assumption %s invalidated", assumptionIds), forType, currentValues)); | |
1562 builder.end(); | |
1563 builder.end(); | |
1564 } | |
1565 | |
1498 execute.startReturn(); | 1566 execute.startReturn(); |
1499 if (specialization.getMethod() == null) { | 1567 if (specialization.getMethod() == null) { |
1500 execute.startCall("unsupported"); | 1568 execute.startCall("unsupported"); |
1501 currentValues.addReferencesTo(execute, FRAME_VALUE); | 1569 currentValues.addReferencesTo(execute, FRAME_VALUE); |
1502 execute.end(); | 1570 execute.end(); |
1523 } | 1591 } |
1524 } | 1592 } |
1525 } | 1593 } |
1526 | 1594 |
1527 SpecializationData specialization = group.getSpecialization(); | 1595 SpecializationData specialization = group.getSpecialization(); |
1528 CodeTree[] checkAndCast = createTypeCheckCastAndCaches(specialization, group.getTypeGuards(), castGuards, currentValues, execution); | 1596 CodeTree[] checkAndCast = createTypeCheckAndLocals(specialization, group.getTypeGuards(), castGuards, currentValues, execution); |
1529 | 1597 |
1530 CodeTree check = checkAndCast[0]; | 1598 CodeTree check = checkAndCast[0]; |
1531 CodeTree cast = checkAndCast[1]; | 1599 CodeTree cast = checkAndCast[1]; |
1532 | 1600 |
1533 List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards(); | 1601 List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards(); |
1534 List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards()); | 1602 List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards()); |
1535 guardExpressions.removeAll(elseGuardExpressions); | 1603 guardExpressions.removeAll(elseGuardExpressions); |
1536 CodeTree[] methodGuardAndAssertions = createMethodGuardCheck(guardExpressions, specialization, currentValues, execution.isFastPath()); | 1604 CodeTree[] methodGuardAndAssertions = createMethodGuardCheck(guardExpressions, specialization, currentValues, execution.isFastPath()); |
1537 CodeTree methodGuards = methodGuardAndAssertions[0]; | 1605 CodeTree methodGuards = methodGuardAndAssertions[0]; |
1538 CodeTree guardAssertions = methodGuardAndAssertions[1]; | 1606 CodeTree guardAssertions = methodGuardAndAssertions[1]; |
1539 | |
1540 if (!group.getAssumptions().isEmpty()) { | |
1541 if (execution.isFastPath() && !forType.isGeneric()) { | |
1542 cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues); | |
1543 } else { | |
1544 methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions()); | |
1545 } | |
1546 } | |
1547 | 1607 |
1548 int ifCount = 0; | 1608 int ifCount = 0; |
1549 if (!check.isEmpty()) { | 1609 if (!check.isEmpty()) { |
1550 builder.startIf(); | 1610 builder.startIf(); |
1551 builder.tree(check).end(); | 1611 builder.tree(check).end(); |
1581 builder.end(ifCount); | 1641 builder.end(ifCount); |
1582 | 1642 |
1583 return builder.build(); | 1643 return builder.build(); |
1584 } | 1644 } |
1585 | 1645 |
1586 private CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List<String> assumptions) { | |
1587 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1588 | |
1589 builder.tree(methodGuards); | |
1590 String connect = methodGuards.isEmpty() ? "" : " && "; | |
1591 for (String assumption : assumptions) { | |
1592 builder.string(connect); | |
1593 builder.startCall(accessParent(assumptionName(assumption)), "isValid").end(); | |
1594 connect = " && "; | |
1595 } | |
1596 | |
1597 return builder.build(); | |
1598 } | |
1599 | |
1600 private CodeTree appendAssumptionFastPath(CodeTree casts, List<String> assumptions, TypeData forType, LocalContext currentValues) { | |
1601 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1602 builder.tree(casts); | |
1603 builder.startTryBlock(); | |
1604 for (String assumption : assumptions) { | |
1605 builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end(); | |
1606 } | |
1607 builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); | |
1608 builder.tree(createCallNext(forType, currentValues)); | |
1609 builder.end(); | |
1610 return builder.build(); | |
1611 } | |
1612 | |
1613 private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { | 1646 private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { |
1614 if (ifCount != 0) { | 1647 if (ifCount != 0) { |
1615 return true; | 1648 return true; |
1616 } | 1649 } |
1617 SpecializationGroup previous = group.getPreviousGroup(); | 1650 SpecializationGroup previous = group.getPreviousGroup(); |
1621 | 1654 |
1622 /* | 1655 /* |
1623 * Hacky else case. In this case the specialization is not reachable due to previous else | 1656 * Hacky else case. In this case the specialization is not reachable due to previous else |
1624 * branch. This is only true if the minimum state is not checked. | 1657 * branch. This is only true if the minimum state is not checked. |
1625 */ | 1658 */ |
1626 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && | 1659 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && |
1627 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { | 1660 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { |
1628 return false; | 1661 return false; |
1629 } | 1662 } |
1630 | 1663 |
1631 return true; | 1664 return true; |
2122 } | 2155 } |
2123 } | 2156 } |
2124 return bindings; | 2157 return bindings; |
2125 } | 2158 } |
2126 | 2159 |
2127 private CodeTree[] createTypeCheckCastAndCaches(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, | 2160 private CodeTree[] createTypeCheckAndLocals(SpecializationData specialization, List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, |
2128 SpecializationExecution specializationExecution) { | 2161 SpecializationExecution specializationExecution) { |
2129 CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); | 2162 CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); |
2130 CodeTreeBuilder castsAndCaches = CodeTreeBuilder.createBuilder(); | 2163 CodeTreeBuilder localsBuilder = CodeTreeBuilder.createBuilder(); |
2131 for (TypeGuard typeGuard : typeGuards) { | 2164 for (TypeGuard typeGuard : typeGuards) { |
2132 int signatureIndex = typeGuard.getSignatureIndex(); | 2165 int signatureIndex = typeGuard.getSignatureIndex(); |
2133 LocalVariable value = currentValues.getValue(signatureIndex); | 2166 LocalVariable value = currentValues.getValue(signatureIndex); |
2134 TypeData targetType = typeGuard.getType(); | 2167 TypeData targetType = typeGuard.getType(); |
2135 if (!value.getType().needsCastTo(targetType)) { | 2168 if (!value.getType().needsCastTo(targetType)) { |
2186 } | 2219 } |
2187 | 2220 |
2188 if (castGuards == null || castGuards.contains(typeGuard)) { | 2221 if (castGuards == null || castGuards.contains(typeGuard)) { |
2189 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); | 2222 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); |
2190 currentValues.setValue(execution, castVariable); | 2223 currentValues.setValue(execution, castVariable); |
2191 castsAndCaches.tree(castVariable.createDeclaration(castBuilder.build())); | 2224 localsBuilder.tree(castVariable.createDeclaration(castBuilder.build())); |
2192 } | 2225 } |
2193 | 2226 |
2194 checksBuilder.tree(checkBuilder.build()); | 2227 checksBuilder.tree(checkBuilder.build()); |
2195 } | 2228 } |
2196 | 2229 |
2200 castBoundTypes(bindExpressionValues(cache.getExpression(), specialization, currentValues))); | 2233 castBoundTypes(bindExpressionValues(cache.getExpression(), specialization, currentValues))); |
2201 String name = cache.getParameter().getLocalName(); | 2234 String name = cache.getParameter().getLocalName(); |
2202 // multiple specializations might use the same name | 2235 // multiple specializations might use the same name |
2203 String varName = name + specialization.getIndex(); | 2236 String varName = name + specialization.getIndex(); |
2204 TypeMirror type = cache.getParameter().getType(); | 2237 TypeMirror type = cache.getParameter().getType(); |
2205 castsAndCaches.declaration(type, varName, initializer); | 2238 localsBuilder.declaration(type, varName, initializer); |
2206 currentValues.set(name, new LocalVariable(null, type, varName, null)); | 2239 currentValues.set(name, new LocalVariable(null, type, varName, null)); |
2207 } | 2240 } |
2208 } | 2241 } |
2209 | 2242 |
2210 return new CodeTree[]{checksBuilder.build(), castsAndCaches.build()}; | 2243 return new CodeTree[]{checksBuilder.build(), localsBuilder.build()}; |
2211 } | 2244 } |
2212 | 2245 |
2213 public static final class LocalContext { | 2246 public static final class LocalContext { |
2214 | 2247 |
2215 private final NodeGenFactory factory; | 2248 private final NodeGenFactory factory; |
2217 | 2250 |
2218 private LocalContext(NodeGenFactory factory) { | 2251 private LocalContext(NodeGenFactory factory) { |
2219 this.factory = factory; | 2252 this.factory = factory; |
2220 } | 2253 } |
2221 | 2254 |
2222 public void loadFastPathCachedValues(SpecializationData specialization) { | 2255 public void loadFastPathState(SpecializationData specialization) { |
2223 for (CacheExpression cache : specialization.getCaches()) { | 2256 for (CacheExpression cache : specialization.getCaches()) { |
2224 Parameter cacheParameter = cache.getParameter(); | 2257 Parameter cacheParameter = cache.getParameter(); |
2225 String name = cacheParameter.getVariableElement().getSimpleName().toString(); | 2258 String name = cacheParameter.getVariableElement().getSimpleName().toString(); |
2226 set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name))); | 2259 set(cacheParameter.getLocalName(), new LocalVariable(cacheParameter.getTypeSystemType(), cacheParameter.getType(), name, CodeTreeBuilder.singleString("this." + name))); |
2260 } | |
2261 | |
2262 for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) { | |
2263 String name = assumptionName(assumption); | |
2264 TypeMirror type = assumption.getExpression().getResolvedType(); | |
2265 set(name, new LocalVariable(null, type, name, CodeTreeBuilder.singleString("this." + name))); | |
2227 } | 2266 } |
2228 } | 2267 } |
2229 | 2268 |
2230 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) { | 2269 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) { |
2231 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); | 2270 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); |
2423 | 2462 |
2424 private LocalVariable getShortCircuit(NodeExecutionData execution) { | 2463 private LocalVariable getShortCircuit(NodeExecutionData execution) { |
2425 return values.get(shortCircuitName(execution)); | 2464 return values.get(shortCircuitName(execution)); |
2426 } | 2465 } |
2427 | 2466 |
2467 @Override | |
2468 public String toString() { | |
2469 return "LocalContext [values=" + values + "]"; | |
2470 } | |
2471 | |
2428 } | 2472 } |
2429 | 2473 |
2430 public static final class LocalVariable { | 2474 public static final class LocalVariable { |
2431 | 2475 |
2432 private final TypeData type; | 2476 private final TypeData type; |