comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 9217:61ba6fc21ba4

Sourcegen can now generate execute methods of signature execute(frame, evaluatedValue).
author Christian Humer <christian.humer@gmail.com>
date Mon, 15 Apr 2013 18:50:19 +0200
parents bd067a48a9c2
children 797bb88bf004
comparison
equal deleted inserted replaced
9216:8b9ea2f5c36e 9217:61ba6fc21ba4
86 } 86 }
87 if (spec.isLocal()) { 87 if (spec.isLocal()) {
88 continue; 88 continue;
89 } 89 }
90 90
91 method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter))); 91 method.addParameter(new CodeVariableElement(parameter.getType(), valueName(parameter)));
92 } 92 }
93 } 93 }
94 94
95 private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { 95 private static void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame,
96 boolean includeImplicit) {
96 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { 97 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) {
97 builder.string("frameValue"); 98 builder.string("frameValue");
98 } 99 }
99 for (ActualParameter parameter : specialization.getParameters()) { 100 for (ActualParameter parameter : specialization.getParameters()) {
100 ParameterSpec spec = parameter.getSpecification(); 101 ParameterSpec spec = parameter.getSpecification();
107 } 108 }
108 if (parameter.getSpecification().isLocal()) { 109 if (parameter.getSpecification().isLocal()) {
109 continue; 110 continue;
110 } 111 }
111 112
113 ActualParameter sourceParameter = source.findParameter(parameter.getLocalName());
114
112 if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { 115 if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) {
113 builder.cast(parameter.getActualType(), CodeTreeBuilder.singleString("ex.getResult()")); 116 builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()"));
117 } else if (sourceParameter != null) {
118 builder.string(valueName(sourceParameter, parameter));
114 } else { 119 } else {
115 builder.string(valueName(parameter)); 120 builder.string(valueName(parameter));
116 } 121 }
122 }
123 }
124
125 private static String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) {
126 if (sourceParameter != null) {
127 if (!sourceParameter.getSpecification().isSignature()) {
128 return valueName(targetParameter);
129 } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) {
130 if (sourceParameter.getTypeSystemType().needsCastTo(targetParameter.getTypeSystemType())) {
131 return castValueName(targetParameter);
132 }
133 }
134 return valueName(targetParameter);
135 } else {
136 return valueName(targetParameter);
117 } 137 }
118 } 138 }
119 139
120 private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) { 140 private static CodeTree createTemplateMethodCall(CodeTreeBuilder parent, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName) {
121 CodeTreeBuilder builder = parent.create(); 141 CodeTreeBuilder builder = parent.create();
127 if (method == null) { 147 if (method == null) {
128 throw new IllegalStateException("Cannot call synthetic operation methods."); 148 throw new IllegalStateException("Cannot call synthetic operation methods.");
129 } 149 }
130 TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); 150 TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement());
131 NodeData node = (NodeData) targetMethod.getTemplate(); 151 NodeData node = (NodeData) targetMethod.getTemplate();
132 TypeSystemData typeSystem = node.getTypeSystem();
133 152
134 boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType()); 153 boolean accessible = targetMethod.canBeAccessedByInstanceOf(node.getNodeType());
135 if (accessible) { 154 if (accessible) {
136 if (builder.findMethod().getModifiers().contains(STATIC)) { 155 if (builder.findMethod().getModifiers().contains(STATIC)) {
137 if (method.getModifiers().contains(STATIC)) { 156 if (method.getModifiers().contains(STATIC)) {
138 builder.type(targetClass.asType()); 157 builder.type(targetClass.asType());
139 } else { 158 } else {
140 builder.string(THIS_NODE_LOCAL_VAR_NAME); 159 builder.string(THIS_NODE_LOCAL_VAR_NAME);
141 } 160 }
142 } else { 161 } else {
143 builder.string("super"); 162 if (targetMethod instanceof ExecutableTypeData) {
163 builder.string("this");
164 } else {
165 builder.string("super");
166 }
144 } 167 }
145 } else { 168 } else {
146 if (method.getModifiers().contains(STATIC)) { 169 if (method.getModifiers().contains(STATIC)) {
147 builder.type(targetClass.asType()); 170 builder.type(targetClass.asType());
148 } else { 171 } else {
154 } 177 }
155 } 178 }
156 ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); 179 ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName());
157 assert parameter != null; 180 assert parameter != null;
158 181
159 if (castedValues) { 182 if (castedValues && sourceParameter != null) {
160 NodeFieldData field = node.findField(parameter.getSpecification().getName()); 183 builder.string(valueName(sourceParameter, parameter));
161 if (field == null) {
162 builder.string(valueName(parameter));
163 } else {
164 if (Utils.typeEquals(sourceParameter.getActualType(), parameter.getActualType())) {
165 builder.string(valueName(parameter));
166 } else {
167 builder.string(castValueName(parameter));
168 }
169 }
170 } else { 184 } else {
171 builder.string(valueName(parameter)); 185 builder.string(valueName(parameter));
172 } 186 }
173 } 187 }
174 } 188 }
178 for (ActualParameter targetParameter : targetMethod.getParameters()) { 192 for (ActualParameter targetParameter : targetMethod.getParameters()) {
179 ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); 193 ActualParameter valueParameter = sourceMethod.findParameter(targetParameter.getLocalName());
180 if (valueParameter == null) { 194 if (valueParameter == null) {
181 valueParameter = targetParameter; 195 valueParameter = targetParameter;
182 } 196 }
183 TypeData targetType = targetParameter.getActualTypeData(typeSystem); 197 TypeData targetType = targetParameter.getTypeSystemType();
184 198
185 if (targetParameter.isImplicit() || valueParameter.isImplicit()) { 199 if (targetParameter.isImplicit() || valueParameter.isImplicit()) {
186 continue; 200 continue;
187 } 201 }
188 202
189 TypeData valueType = null; 203 TypeData valueType = null;
190 if (valueParameter != null) { 204 if (valueParameter != null) {
191 valueType = valueParameter.getActualTypeData(typeSystem); 205 valueType = valueParameter.getTypeSystemType();
192 } 206 }
193 207
194 if (targetParameter.getSpecification().isLocal()) { 208 if (targetParameter.getSpecification().isLocal()) {
195 builder.startGroup(); 209 builder.startGroup();
196 if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { 210 if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) {
201 builder.string(targetParameter.getSpecification().getName()); 215 builder.string(targetParameter.getSpecification().getName());
202 builder.end(); 216 builder.end();
203 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { 217 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) {
204 builder.string("ex.getResult()"); 218 builder.string("ex.getResult()");
205 } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) { 219 } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) {
220 builder.startGroup();
221
222 if (valueType != null && sourceMethod.getMethodName().equals(targetMethod.getMethodName()) && !valueType.isGeneric() && targetType.isGeneric()) {
223 builder.string("(");
224 builder.type(targetType.getPrimitiveType());
225 builder.string(") ");
226 }
206 builder.string(valueName(targetParameter)); 227 builder.string(valueName(targetParameter));
228 builder.end();
207 } else { 229 } else {
208 builder.string(castValueName(targetParameter)); 230 builder.string(castValueName(targetParameter));
209 } 231 }
210 } 232 }
211 233
241 prev = current; 263 prev = current;
242 } 264 }
243 return prefix; 265 return prefix;
244 } 266 }
245 267
246 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, String value) { 268 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) {
247 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 269 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
248 startCallTypeSystemMethod(context, builder, node, methodName); 270 startCallTypeSystemMethod(context, builder, node, methodName);
249 builder.string(value); 271 builder.tree(value);
250 builder.end().end(); 272 builder.end().end();
251 return builder.getRoot(); 273 return builder.getRoot();
252 } 274 }
253 275
254 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { 276 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) {
279 for (ActualParameter parameter : guard.getParameters()) { 301 for (ActualParameter parameter : guard.getParameters()) {
280 NodeFieldData field = node.findField(parameter.getSpecification().getName()); 302 NodeFieldData field = node.findField(parameter.getSpecification().getName());
281 if (field == null) { 303 if (field == null) {
282 continue; 304 continue;
283 } 305 }
284 TypeData typeData = parameter.getActualTypeData(node.getTypeSystem()); 306 TypeData typeData = parameter.getTypeSystemType();
285 if (typeData != null && !typeData.isGeneric()) { 307 if (typeData != null && !typeData.isGeneric()) {
286 valuesNeedsCast.add(parameter.getLocalName()); 308 valuesNeedsCast.add(parameter.getLocalName());
287 } 309 }
288 } 310 }
289 } 311 }
343 private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) { 365 private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, SpecializationData valueSpecialization, SpecializationData guardedSpecialization) {
344 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 366 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
345 // Implict guards based on method signature 367 // Implict guards based on method signature
346 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { 368 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
347 NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); 369 NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
348 if (field == null || field.getKind() == FieldKind.FIELD) { 370 if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
349 continue; 371 continue;
350 } 372 }
351 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); 373 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
352 374
353 if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) { 375 if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) {
368 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 390 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
369 // Implict guards based on method signature 391 // Implict guards based on method signature
370 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; 392 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : "";
371 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { 393 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) {
372 NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName()); 394 NodeFieldData field = guardedSpecialization.getNode().findField(guardedParam.getSpecification().getName());
373 if (field == null || field.getKind() == FieldKind.FIELD) { 395 if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
374 continue; 396 continue;
375 } 397 }
376 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); 398 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName());
377 399
378 CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); 400 CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam);
390 412
391 private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { 413 private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
392 NodeData node = field.getNodeData(); 414 NodeData node = field.getNodeData();
393 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 415 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
394 416
395 TypeData targetType = target.getActualTypeData(node.getTypeSystem()); 417 TypeData targetType = target.getTypeSystemType();
396 TypeData sourceType = source.getActualTypeData(node.getTypeSystem()); 418 TypeData sourceType = source.getTypeSystemType();
397 419
398 if (targetType.equalsType(sourceType) || targetType.isGeneric()) { 420 if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
399 return null; 421 return null;
400 } 422 }
401 423
407 builder.string("("); 429 builder.string("(");
408 builder.string("!").string(valueName(shortCircuit)); 430 builder.string("!").string(valueName(shortCircuit));
409 builder.string(" || "); 431 builder.string(" || ");
410 } 432 }
411 433
412 startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getActualTypeData(node.getTypeSystem()))); 434 startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType()));
413 builder.string(valueName(source)); 435 builder.string(valueName(source));
414 builder.end().end(); // call 436 builder.end().end(); // call
415 437
416 if (field.isShortCircuit()) { 438 if (field.isShortCircuit()) {
417 builder.string(")"); 439 builder.string(")");
422 return builder.getRoot(); 444 return builder.getRoot();
423 } 445 }
424 446
425 private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) { 447 private CodeTree createCast(CodeTreeBuilder parent, NodeFieldData field, ActualParameter source, ActualParameter target) {
426 NodeData node = field.getNodeData(); 448 NodeData node = field.getNodeData();
427 TypeSystemData typeSystem = node.getTypeSystem(); 449 TypeData sourceType = source.getTypeSystemType();
428 450 TypeData targetType = target.getTypeSystemType();
429 TypeData sourceType = source.getActualTypeData(typeSystem); 451
430 TypeData targetType = target.getActualTypeData(typeSystem); 452 if (!sourceType.needsCastTo(targetType)) {
431
432 if (targetType.equalsType(sourceType) || targetType.isGeneric()) {
433 return null; 453 return null;
434 } 454 }
435 455
436 CodeTree condition = null; 456 CodeTree condition = null;
437 if (field.isShortCircuit()) { 457 if (field.isShortCircuit()) {
438 ActualParameter shortCircuit = target.getPreviousParameter(); 458 ActualParameter shortCircuit = target.getPreviousParameter();
439 assert shortCircuit != null; 459 assert shortCircuit != null;
440 condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); 460 condition = CodeTreeBuilder.singleString(valueName(shortCircuit));
441 } 461 }
442 462
443 CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), valueName(target)); 463 CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target)));
444 464
445 return createLazyAssignment(parent, castValueName(target), target.getActualType(), condition, value); 465 return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value);
446 } 466 }
447 467
448 /** 468 /**
449 * <pre> 469 * <pre>
450 * variant1 $condition != null 470 * variant1 $condition != null
666 assert !node.getSpecializations().isEmpty(); 686 assert !node.getSpecializations().isEmpty();
667 SpecializationData data = node.getSpecializations().get(0); 687 SpecializationData data = node.getSpecializations().get(0);
668 for (ActualParameter parameter : data.getParameters()) { 688 for (ActualParameter parameter : data.getParameters()) {
669 ParameterSpec spec = parameter.getSpecification(); 689 ParameterSpec spec = parameter.getSpecification();
670 NodeFieldData field = node.findField(spec.getName()); 690 NodeFieldData field = node.findField(spec.getName());
671 if (field == null || field.getKind() == FieldKind.FIELD) { 691 if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
672 continue; 692 continue;
673 } 693 }
674 694
675 TypeMirror type; 695 TypeMirror type;
676 if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) { 696 if (field.getKind() == FieldKind.CHILDREN && field.getType().getKind() == TypeKind.ARRAY) {
990 1010
991 return method; 1011 return method;
992 } 1012 }
993 1013
994 private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) { 1014 private List<CodeExecutableElement> createGeneratedGenericMethod(NodeData node) {
995 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getActualType(); 1015 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType();
996 if (node.needsRewrites(context)) { 1016 if (node.needsRewrites(context)) {
997 List<CodeExecutableElement> methods = new ArrayList<>(); 1017 List<CodeExecutableElement> methods = new ArrayList<>();
998 1018
999 List<SpecializationData> specializations = node.getSpecializations(); 1019 List<SpecializationData> specializations = node.getSpecializations();
1000 SpecializationData prev = null; 1020 SpecializationData prev = null;
1035 if (next != null) { 1055 if (next != null) {
1036 CodeTreeBuilder nextBuilder = builder.create(); 1056 CodeTreeBuilder nextBuilder = builder.create();
1037 1057
1038 nextBuilder.startReturn().startCall(generatedGenericMethodName(next)); 1058 nextBuilder.startReturn().startCall(generatedGenericMethodName(next));
1039 nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME); 1059 nextBuilder.string(THIS_NODE_LOCAL_VAR_NAME);
1040 addInternalValueParameterNames(nextBuilder, next, null, true, true); 1060 addInternalValueParameterNames(nextBuilder, next, next, null, true, true);
1041 nextBuilder.end().end(); 1061 nextBuilder.end().end();
1042 1062
1043 invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot()); 1063 invokeMethod = createGuardAndCast(builder, null, current.getNode().getGenericSpecialization(), current, true, invokeMethod, nextBuilder.getRoot());
1044 } 1064 }
1045 1065
1067 for (SpecializationThrowsData exception : specialization.getExceptions()) { 1087 for (SpecializationThrowsData exception : specialization.getExceptions()) {
1068 builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); 1088 builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level);
1069 1089
1070 builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); 1090 builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo()));
1071 builder.string(THIS_NODE_LOCAL_VAR_NAME); 1091 builder.string(THIS_NODE_LOCAL_VAR_NAME);
1072 addInternalValueParameterNames(builder, exception.getTransitionTo(), null, true, true); 1092 addInternalValueParameterNames(builder, exception.getTransitionTo(), exception.getTransitionTo(), null, true, true);
1073 builder.end().end(); 1093 builder.end().end();
1074 } 1094 }
1075 builder.end(); 1095 builder.end();
1076 } 1096 }
1077 } 1097 }
1102 if (superConstructor != null) { 1122 if (superConstructor != null) {
1103 clazz.add(superConstructor); 1123 clazz.add(superConstructor);
1104 } 1124 }
1105 } 1125 }
1106 1126
1107 TypeData primaryType = specialization.getReturnType().getActualTypeData(node.getTypeSystem());
1108
1109 for (ExecutableTypeData execType : node.getExecutableTypes()) { 1127 for (ExecutableTypeData execType : node.getExecutableTypes()) {
1110 if (execType.isFinal()) { 1128 if (execType.isFinal()) {
1111 continue; 1129 continue;
1112 } 1130 }
1113 1131 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType);
1114 if (primaryType == execType.getType()) { 1132 clazz.add(executeMethod);
1115 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType); 1133 CodeTreeBuilder builder = executeMethod.createBuilder();
1116 clazz.add(executeMethod); 1134 CodeTree result = createExecuteBody(builder, specialization, execType);
1117 executeMethod.setBodyTree(createFunctionalExecute(executeMethod.createBuilder(), specialization)); 1135 if (result != null) {
1118 } else if (needsCastingExecuteMethod(execType, primaryType)) { 1136 builder.tree(result);
1119 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType); 1137 } else {
1120 clazz.add(executeMethod); 1138 clazz.remove(executeMethod);
1121 executeMethod.setBodyTree(createCastingExecute(executeMethod.createBuilder(), specialization, execType.getType())); 1139 }
1122 }
1123
1124 } 1140 }
1125 1141
1126 if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { 1142 if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) {
1127 buildSpecializeAndExecute(clazz, specialization); 1143 buildSpecializeAndExecute(clazz, specialization);
1128 } 1144 }
1129 } 1145 }
1130 1146
1147 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) {
1148 TypeData primaryType = specialization.getReturnType().getTypeSystemType();
1149
1150 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1151
1152 ExecutableTypeData foundEvaluatedPrimaryType = findFunctionalExecutableType(specialization, execType.getEvaluatedCount());
1153
1154 if (execType == foundEvaluatedPrimaryType || foundEvaluatedPrimaryType == null) {
1155 builder.tree(createFunctionalExecute(builder, specialization, execType));
1156 } else if (needsCastingExecuteMethod(execType, primaryType)) {
1157 builder.tree(createCastingExecute(builder, specialization, execType, foundEvaluatedPrimaryType));
1158 } else {
1159 return null;
1160 }
1161
1162 return builder.getRoot();
1163 }
1164
1131 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) { 1165 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) {
1132 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); 1166 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod());
1133 if (method.getParameters().size() == 1) { 1167
1134 CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0)); 1168 int i = 0;
1135 var.setName("frameValue"); 1169 for (VariableElement param : method.getParameters()) {
1136 method.getParameters().set(0, var); 1170 CodeVariableElement var = CodeVariableElement.clone(param);
1137 } 1171 var.setName(valueName(execType.getParameters().get(i)));
1172 method.getParameters().set(i, var);
1173 i++;
1174 }
1175
1176 method.getAnnotationMirrors().clear();
1138 method.getModifiers().remove(Modifier.ABSTRACT); 1177 method.getModifiers().remove(Modifier.ABSTRACT);
1139 return method; 1178 return method;
1140 } 1179 }
1141 1180
1142 private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) { 1181 private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) {
1150 return true; 1189 return true;
1151 } 1190 }
1152 return false; 1191 return false;
1153 } 1192 }
1154 1193
1155 private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, TypeData type) { 1194 private ExecutableTypeData findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) {
1195 TypeData primaryType = specialization.getReturnType().getTypeSystemType();
1196 List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount);
1197
1198 List<ExecutableTypeData> filteredTypes = new ArrayList<>();
1199 for (ExecutableTypeData compareType : otherTypes) {
1200 if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) {
1201 continue;
1202 }
1203 filteredTypes.add(compareType);
1204 }
1205
1206 for (ExecutableTypeData compareType : filteredTypes) {
1207 if (compareType.startsWithSignature(specialization)) {
1208 return compareType;
1209 }
1210 }
1211
1212 for (ExecutableTypeData compareType : otherTypes) {
1213 if (compareType.startsWithSignature(specialization)) {
1214 return compareType;
1215 }
1216 }
1217
1218 return null;
1219 }
1220
1221 private CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) {
1222 TypeData type = executable.getType();
1156 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1223 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1157 NodeData node = specialization.getNode(); 1224 NodeData node = specialization.getNode();
1158 TypeSystemData typeSystem = node.getTypeSystem();
1159 1225
1160 ExecutableTypeData castedType = node.findExecutableType(type); 1226 ExecutableTypeData castedType = node.findExecutableType(type);
1161 TypeData primaryType = specialization.getReturnType().getActualTypeData(typeSystem); 1227 TypeData primaryType = castExecutable.getType();
1162 ExecutableTypeData execType = specialization.getNode().findExecutableType(primaryType); 1228
1163 1229 boolean needsTry = castExecutable.hasUnexpectedValue(getContext());
1164 boolean needsTry = execType.hasUnexpectedValue(getContext());
1165 boolean returnVoid = type.isVoid(); 1230 boolean returnVoid = type.isVoid();
1166 1231
1167 CodeTree primaryExecuteCall = null; 1232 List<ActualParameter> executeParameters = new ArrayList<>();
1168 1233 for (ActualParameter sourceParameter : executable.getParameters()) {
1169 CodeTreeBuilder executeBuilder = new CodeTreeBuilder(builder); 1234 NodeFieldData field = specialization.getNode().findField(sourceParameter.getSpecification().getName());
1170 buildExecute(executeBuilder, null, null, execType); 1235 if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
1171 primaryExecuteCall = executeBuilder.getRoot(); 1236 continue;
1172 1237 }
1238
1239 ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName());
1240 if (targetParameter != null) {
1241 TypeData sourceType = sourceParameter.getTypeSystemType();
1242 TypeData targetType = targetParameter.getTypeSystemType();
1243 if (sourceType.needsCastTo(targetType)) {
1244 executeParameters.add(targetParameter);
1245 }
1246 }
1247 }
1248
1249 builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true));
1250
1251 CodeTree primaryExecuteCall = createTemplateMethodCall(builder, executable, castExecutable, null);
1173 if (needsTry) { 1252 if (needsTry) {
1174 if (!returnVoid) { 1253 if (!returnVoid) {
1175 builder.declaration(primaryType.getPrimitiveType(), "value"); 1254 builder.declaration(primaryType.getPrimitiveType(), "value");
1176 } 1255 }
1177 builder.startTryBlock(); 1256 builder.startTryBlock();
1234 builder.tree(value); 1313 builder.tree(value);
1235 builder.end().end(); 1314 builder.end().end();
1236 return builder.getRoot(); 1315 return builder.getRoot();
1237 } 1316 }
1238 1317
1239 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization) { 1318 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) {
1240 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1319 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1241 if (specialization.isUninitialized()) { 1320 if (specialization.isUninitialized()) {
1242 builder.tree(createDeoptimize(builder)); 1321 builder.tree(createDeoptimize(builder));
1243 } 1322 }
1244 1323
1245 builder.tree(createExecuteChildren(builder, specialization)); 1324 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false));
1246 1325
1247 CodeTree executeNode; 1326 CodeTree executeNode;
1248 if (specialization.isUninitialized()) { 1327 if (specialization.isUninitialized()) {
1249 builder.tree(createSpecializeCall(builder, specialization)); 1328 builder.tree(createSpecializeCall(builder, executable, specialization));
1250 } 1329 }
1251 executeNode = createExecute(builder, specialization); 1330 executeNode = createExecute(builder, executable, specialization);
1252 1331
1253 SpecializationData next = specialization.findNextSpecialization(); 1332 SpecializationData next = specialization.findNextSpecialization();
1254 CodeTree returnSpecialized = null; 1333 CodeTree returnSpecialized = null;
1255 if (next != null) { 1334 if (next != null) {
1256 returnSpecialized = createReturnSpecializeAndExecute(builder, next, null); 1335 returnSpecialized = createReturnSpecializeAndExecute(builder, executable, next, null);
1257 } 1336 }
1258 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized)); 1337 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized));
1259 1338
1260 return builder.getRoot(); 1339 return builder.getRoot();
1261 } 1340 }
1266 builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end(); 1345 builder.startStaticCall(getContext().getTruffleTypes().getTruffleIntrinsics(), "deoptimize").end();
1267 builder.end(); 1346 builder.end();
1268 return builder.getRoot(); 1347 return builder.getRoot();
1269 } 1348 }
1270 1349
1271 private CodeTree createSpecializeCall(CodeTreeBuilder parent, SpecializationData specialization) { 1350 private CodeTree createSpecializeCall(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
1272 NodeData node = specialization.getNode(); 1351 NodeData node = specialization.getNode();
1273 1352
1274 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1353 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1275 emitSpecializationListeners(builder, node); 1354 emitSpecializationListeners(builder, node);
1276 1355
1278 builder.startCall("replace"); 1357 builder.startCall("replace");
1279 if (node.needsRewrites(getContext())) { 1358 if (node.needsRewrites(getContext())) {
1280 builder.startCall(factoryClassName(node), "specialize"); 1359 builder.startCall(factoryClassName(node), "specialize");
1281 builder.string("this"); 1360 builder.string("this");
1282 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); 1361 builder.typeLiteral(builder.findMethod().getEnclosingElement().asType());
1283 addInternalValueParameterNames(builder, specialization, null, true, true); 1362 addInternalValueParameterNames(builder, executable, specialization, null, true, true);
1284 builder.end(); // call replace, call specialize 1363 builder.end(); // call replace, call specialize
1285 } else { 1364 } else {
1286 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); 1365 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end();
1287 } 1366 }
1288 builder.end().end(); 1367 builder.end().end();
1289 return builder.getRoot(); 1368 return builder.getRoot();
1290 } 1369 }
1291 1370
1292 private CodeTree createExecute(CodeTreeBuilder parent, SpecializationData specialization) { 1371 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) {
1293 NodeData node = specialization.getNode(); 1372 NodeData node = specialization.getNode();
1294 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1373 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1295 if (!specialization.getExceptions().isEmpty()) { 1374 if (!specialization.getExceptions().isEmpty()) {
1296 builder.startTryBlock(); 1375 builder.startTryBlock();
1297 } 1376 }
1298 1377
1378 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent);
1299 if (specialization.isUninitialized()) { 1379 if (specialization.isUninitialized()) {
1300 String genericMethodName = generatedGenericMethodName(null); 1380 String genericMethodName = generatedGenericMethodName(null);
1301 builder.startReturn().startCall(factoryClassName(node), genericMethodName); 1381 returnBuilder.startCall(factoryClassName(node), genericMethodName);
1302 builder.string("this"); 1382 returnBuilder.string("this");
1303 addInternalValueParameterNames(builder, specialization, null, true, true); 1383 addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
1304 builder.end().end(); 1384 returnBuilder.end();
1305 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { 1385 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) {
1306 emitEncounteredSynthetic(builder); 1386 emitEncounteredSynthetic(builder);
1307 } else if (specialization.isGeneric()) { 1387 } else if (specialization.isGeneric()) {
1308 String genericMethodName; 1388 String genericMethodName;
1309 if (!specialization.isUseSpecializationsForGeneric()) { 1389 if (!specialization.isUseSpecializationsForGeneric()) {
1310 genericMethodName = generatedGenericMethodName(specialization); 1390 genericMethodName = generatedGenericMethodName(specialization);
1311 } else { 1391 } else {
1312 genericMethodName = generatedGenericMethodName(null); 1392 genericMethodName = generatedGenericMethodName(null);
1313 } 1393 }
1314 1394
1315 builder.startReturn().startCall(factoryClassName(node), genericMethodName); 1395 returnBuilder.startCall(factoryClassName(node), genericMethodName);
1316 builder.string("this"); 1396 returnBuilder.string("this");
1317 addInternalValueParameterNames(builder, specialization, null, true, true); 1397 addInternalValueParameterNames(returnBuilder, executable, specialization, null, true, true);
1318 builder.end().end(); 1398 returnBuilder.end();
1319 } else { 1399 } else {
1400 returnBuilder.tree(createTemplateMethodCall(returnBuilder, executable, specialization, null));
1401 }
1402
1403 if (!returnBuilder.isEmpty()) {
1320 builder.startReturn(); 1404 builder.startReturn();
1321 builder.tree(createTemplateMethodCall(builder, specialization, specialization, null)); 1405
1322 builder.end(); // return 1406 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType());
1407 TypeData sourceType = specialization.getReturnType().getTypeSystemType();
1408
1409 if (targetType == null || sourceType == null) {
1410 builder.tree(returnBuilder.getRoot());
1411 } else if (sourceType.needsCastTo(targetType)) {
1412 builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot()));
1413 } else {
1414 builder.tree(returnBuilder.getRoot());
1415 }
1416 builder.end();
1323 } 1417 }
1324 1418
1325 if (!specialization.getExceptions().isEmpty()) { 1419 if (!specialization.getExceptions().isEmpty()) {
1326 for (SpecializationThrowsData exception : specialization.getExceptions()) { 1420 for (SpecializationThrowsData exception : specialization.getExceptions()) {
1327 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); 1421 builder.end().startCatchBlock(exception.getJavaClass(), "ex");
1328 builder.tree(createReturnSpecializeAndExecute(parent, exception.getTransitionTo(), null)); 1422 builder.tree(createReturnSpecializeAndExecute(parent, executable, exception.getTransitionTo(), null));
1329 } 1423 }
1330 builder.end(); 1424 builder.end();
1331 } 1425 }
1332 return builder.getRoot(); 1426 return builder.getRoot();
1333 } 1427 }
1334 1428
1335 private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { 1429 private CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters,
1430 ActualParameter unexpectedParameter, boolean cast) {
1431 NodeData sourceNode = specialization.getNode();
1432
1336 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1433 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1337 1434
1338 for (ActualParameter parameter : specialization.getParameters()) { 1435 for (ActualParameter targetParameter : targetParameters) {
1339 NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName()); 1436 NodeFieldData field = sourceNode.findField(targetParameter.getSpecification().getName());
1340 if (field == null || field.getKind() == FieldKind.FIELD) { 1437 if (field == null || field.getKind() == FieldKind.FINAL_FIELD) {
1341 continue; 1438 continue;
1342 } 1439 }
1343 1440 TypeData targetType = targetParameter.getTypeSystemType();
1344 buildFieldExecute(builder, specialization, parameter, field, null); 1441
1442 ExecutableTypeData targetExecutable = field.getNodeData().findExecutableType(targetType);
1443
1444 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName());
1445
1446 String targetVariableName;
1447 CodeTree executionExpression;
1448 if (cast || sourceParameter != null) {
1449 TypeData sourceType = sourceParameter.getTypeSystemType();
1450 if (!sourceType.needsCastTo(targetType)) {
1451 continue;
1452 }
1453 executionExpression = createExpectType(sourceNode, targetExecutable, CodeTreeBuilder.singleString(valueName(targetParameter)));
1454 targetVariableName = castValueName(targetParameter);
1455 } else {
1456 if (sourceExecutable.findParameter(targetParameter.getLocalName()) == null) {
1457 executionExpression = createExecuteChildExpression(builder, field, targetParameter);
1458 targetVariableName = valueName(targetParameter);
1459 } else {
1460 continue;
1461 }
1462 }
1463
1464 CodeTreeVariable executionVar = new CodeTreeVariable();
1465 CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, sourceExecutable, specialization, targetParameter, unexpectedParameter);
1466 CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter,
1467 shortCircuitTree != executionVar);
1468
1469 executionVar.set(unexpectedTree);
1470 builder.tree(shortCircuitTree);
1345 } 1471 }
1346 return builder.getRoot(); 1472 return builder.getRoot();
1347 } 1473 }
1348 1474
1349 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { 1475 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) {
1352 builder.tree(createTemplateMethodCall(builder, listener, listener, null)); 1478 builder.tree(createTemplateMethodCall(builder, listener, listener, null));
1353 builder.end(); // statement 1479 builder.end(); // statement
1354 } 1480 }
1355 } 1481 }
1356 1482
1357 private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) { 1483 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable,
1358 boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam); 1484 ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) {
1359 ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); 1485 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1360 boolean unexpected = execType.hasUnexpectedValue(getContext()); 1486 boolean unexpected = targetExecutable.hasUnexpectedValue(getContext());
1361 1487 builder.startStatement();
1362 if (!shortCircuit && unexpected) { 1488
1363 builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); 1489 if (!shortCircuit) {
1490 builder.type(param.getType()).string(" ").string(targetVariableName);
1364 } 1491 }
1365 1492
1366 if (unexpected) { 1493 if (unexpected) {
1494 if (!shortCircuit) {
1495 builder.end();
1496 }
1367 builder.startTryBlock(); 1497 builder.startTryBlock();
1368 } 1498 builder.startStatement();
1369 1499 builder.string(targetVariableName);
1370 if (!shortCircuit && !unexpected) { 1500 } else if (shortCircuit) {
1371 builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = "); 1501 builder.startStatement();
1372 } else { 1502 builder.string(targetVariableName);
1373 builder.startStatement().string(valueName(param)).string(" = "); 1503 }
1374 } 1504 builder.string(" = ");
1375 buildExecute(builder, param, field, execType); 1505 builder.tree(body);
1376 builder.end(); 1506 builder.end();
1377 1507
1378 if (unexpected) { 1508 if (unexpected) {
1379 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); 1509 builder.end().startCatchBlock(getUnexpectedValueException(), "ex");
1380 SpecializationData generic = specialization.getNode().getGenericSpecialization(); 1510 SpecializationData generic = specialization.getNode().getGenericSpecialization();
1381 boolean execute = false; 1511 ActualParameter genericParameter = generic.findParameter(param.getLocalName());
1382 for (ActualParameter exParam : generic.getParameters()) { 1512
1383 NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName()); 1513 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter);
1384 if (exField == null || field.getKind() == FieldKind.FIELD) { 1514 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false));
1385 continue; 1515 builder.tree(createReturnSpecializeAndExecute(builder, currentExecutable, specialization.findNextSpecialization(), param));
1386 }
1387 if (execute) {
1388 buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param);
1389 } else if (exParam.getLocalName().equals(param.getLocalName())) {
1390 execute = true;
1391 }
1392 }
1393 builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param));
1394 builder.end(); // catch block 1516 builder.end(); // catch block
1395 } 1517 }
1396 1518
1397 endShortCircuit(builder, shortCircuit); 1519 return builder.getRoot();
1398 builder.newLine(); 1520 }
1399 } 1521
1400 1522 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeFieldData targetField, ActualParameter sourceParameter) {
1401 private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) { 1523 TypeData type = sourceParameter.getTypeSystemType();
1402 if (field != null) { 1524 ExecutableTypeData execType = targetField.getNodeData().findExecutableType(type);
1403 Element accessElement = field.getAccessElement(); 1525
1526 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1527 if (targetField != null) {
1528 Element accessElement = targetField.getAccessElement();
1404 if (accessElement.getKind() == ElementKind.METHOD) { 1529 if (accessElement.getKind() == ElementKind.METHOD) {
1405 builder.startCall(accessElement.getSimpleName().toString()).end(); 1530 builder.startCall(accessElement.getSimpleName().toString()).end();
1406 } else if (accessElement.getKind() == ElementKind.FIELD) { 1531 } else if (accessElement.getKind() == ElementKind.FIELD) {
1407 builder.string("this.").string(accessElement.getSimpleName().toString()); 1532 builder.string("this.").string(accessElement.getSimpleName().toString());
1408 } else { 1533 } else {
1409 throw new AssertionError(); 1534 throw new AssertionError();
1410 } 1535 }
1411 if (parameter.getSpecification().isIndexed()) { 1536 if (sourceParameter.getSpecification().isIndexed()) {
1412 builder.string("[" + parameter.getIndex() + "]"); 1537 builder.string("[" + sourceParameter.getIndex() + "]");
1413 } 1538 }
1414 builder.string("."); 1539 builder.string(".");
1415 } 1540 }
1416 builder.startCall(execType.getMethodName()); 1541 builder.startCall(execType.getMethodName());
1417 if (execType.getParameters().size() == 1) { 1542 if (execType.getParameters().size() == 1) {
1418 builder.string("frameValue"); 1543 builder.string("frameValue");
1419 } 1544 }
1420 builder.end(); 1545 builder.end();
1421 } 1546 return builder.getRoot();
1422 1547 }
1423 private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { 1548
1549 private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, ExecutableTypeData currentExecutable, SpecializationData specialization,
1550 ActualParameter parameter, ActualParameter exceptionParam) {
1551 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1552
1424 NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName()); 1553 NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName());
1425 if (forField == null) { 1554 if (forField == null) {
1426 return false; 1555 return body;
1427 } 1556 }
1428 1557
1429 if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { 1558 if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) {
1430 return false; 1559 return body;
1431 } 1560 }
1432 1561
1433 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); 1562 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter);
1434 1563
1435 int shortCircuitIndex = 0; 1564 int shortCircuitIndex = 0;
1440 } 1569 }
1441 shortCircuitIndex++; 1570 shortCircuitIndex++;
1442 } 1571 }
1443 } 1572 }
1444 1573
1445 builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); 1574 builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = ");
1446 ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); 1575 ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex);
1447 1576
1448 builder.tree(createTemplateMethodCall(builder, shortCircuitData, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); 1577 builder.tree(createTemplateMethodCall(builder, currentExecutable, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null));
1449 1578
1450 builder.end(); // statement 1579 builder.end(); // statement
1451 1580
1452 builder.declaration(parameter.getActualType(), valueName(parameter), CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); 1581 builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType()));
1453 builder.startIf().string(shortCircuitParam.getLocalName()).end(); 1582 builder.startIf().string(shortCircuitParam.getLocalName()).end();
1454 builder.startBlock(); 1583 builder.startBlock();
1455 1584 builder.tree(body);
1456 return true; 1585 builder.end();
1457 } 1586
1458 1587 return builder.getRoot();
1459 private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { 1588 }
1460 if (shortCircuit) { 1589
1461 builder.end(); 1590 private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
1462 }
1463 }
1464
1465 private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) {
1466 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); 1591 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent);
1467 specializeCall.startCall("specializeAndExecute"); 1592 specializeCall.startCall("specializeAndExecute");
1468 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); 1593 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class");
1469 addInternalValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); 1594 addInternalValueParameterNames(specializeCall, executable, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true,
1595 true);
1470 specializeCall.end().end(); 1596 specializeCall.end().end();
1471 1597
1472 CodeTreeBuilder builder = new CodeTreeBuilder(parent); 1598 CodeTreeBuilder builder = new CodeTreeBuilder(parent);
1473 builder.startReturn(); 1599 builder.startReturn();
1474 builder.tree(specializeCall.getRoot()); 1600 builder.tree(createExpectType(nextSpecialization.getNode(), executable, specializeCall.getRoot()));
1475 builder.end(); 1601 builder.end();
1602
1476 return builder.getRoot(); 1603 return builder.getRoot();
1477 } 1604 }
1478 1605
1479 private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) { 1606 private void buildSpecializeAndExecute(CodeTypeElement clazz, SpecializationData specialization) {
1480 NodeData node = specialization.getNode(); 1607 NodeData node = specialization.getNode();
1481 TypeData returnType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); 1608 TypeData returnType = node.getGenericSpecialization().getReturnType().getTypeSystemType();
1482 ExecutableTypeData returnExecutableType = node.findExecutableType(returnType);
1483 boolean canThrowUnexpected = returnExecutableType == null ? true : returnExecutableType.hasUnexpectedValue(getContext());
1484 1609
1485 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute"); 1610 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), returnType.getPrimitiveType(), "specializeAndExecute");
1486 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); 1611 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState"));
1487 if (canThrowUnexpected) {
1488 method.addThrownType(getUnexpectedValueException());
1489 }
1490 addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true); 1612 addInternalValueParameters(method, specialization.getNode().getGenericSpecialization(), true);
1491 clazz.add(method); 1613 clazz.add(method);
1492 1614
1493 CodeTreeBuilder builder = method.createBuilder(); 1615 CodeTreeBuilder builder = method.createBuilder();
1494 1616
1496 emitSpecializationListeners(builder, specialization.getNode()); 1618 emitSpecializationListeners(builder, specialization.getNode());
1497 1619
1498 builder.startStatement(); 1620 builder.startStatement();
1499 builder.startCall("replace"); 1621 builder.startCall("replace");
1500 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); 1622 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState");
1501 addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, true, true); 1623 addInternalValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
1502 builder.end(); 1624 builder.end();
1503 builder.end(); // call replace 1625 builder.end(); // call replace
1504 builder.end(); // statement 1626 builder.end(); // statement
1505 1627
1506 String generatedMethodName; 1628 String generatedMethodName;
1512 ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName); 1634 ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod(generatedMethodName);
1513 1635
1514 CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); 1636 CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder();
1515 genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); 1637 genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName);
1516 genericExecute.string("this"); 1638 genericExecute.string("this");
1517 addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true); 1639 addInternalValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), specialization.getNode().getGenericSpecialization(), null, true, true);
1518 genericExecute.end(); // call generated generic 1640 genericExecute.end(); // call generated generic
1519 1641
1520 CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot()); 1642 CodeTree genericInvocation = genericExecute.getRoot();
1521 1643
1522 if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) { 1644 if (generatedGeneric != null && Utils.isVoid(generatedGeneric.getReturnType())) {
1523 builder.statement(genericInvocation); 1645 builder.statement(genericInvocation);
1524 1646
1525 if (!Utils.isVoid(builder.findMethod().asType())) { 1647 if (!Utils.isVoid(builder.findMethod().asType())) {