Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java @ 7502:6343a09b2ec1
Codegen operation generation is inferred from the node type hierarchy.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Fri, 18 Jan 2013 13:28:12 +0100 |
parents | |
children | 5e3d1a68664e |
comparison
equal
deleted
inserted
replaced
7497:0f8c6dbf68be | 7502:6343a09b2ec1 |
---|---|
1 /* | |
2 * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. | |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
4 * | |
5 * This code is free software; you can redistribute it and/or modify it | |
6 * under the terms of the GNU General Public License version 2 only, as | |
7 * published by the Free Software Foundation. | |
8 * | |
9 * This code is distributed in the hope that it will be useful, but WITHOUT | |
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
12 * version 2 for more details (a copy is included in the LICENSE file that | |
13 * accompanied this code). | |
14 * | |
15 * You should have received a copy of the GNU General Public License version | |
16 * 2 along with this work; if not, write to the Free Software Foundation, | |
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
18 * | |
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
20 * or visit www.oracle.com if you need additional information or have any | |
21 * questions. | |
22 */ | |
23 package com.oracle.truffle.codegen.processor.node; | |
24 | |
25 import static com.oracle.truffle.codegen.processor.Utils.*; | |
26 import static javax.lang.model.element.Modifier.*; | |
27 | |
28 import java.util.*; | |
29 | |
30 import javax.lang.model.element.*; | |
31 import javax.lang.model.type.*; | |
32 import javax.lang.model.util.*; | |
33 | |
34 import com.oracle.truffle.codegen.processor.*; | |
35 import com.oracle.truffle.codegen.processor.ast.*; | |
36 import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; | |
37 import com.oracle.truffle.codegen.processor.template.*; | |
38 import com.oracle.truffle.codegen.processor.typesystem.*; | |
39 | |
40 | |
41 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> { | |
42 | |
43 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; | |
44 | |
45 public NodeCodeGenerator(ProcessorContext context) { | |
46 super(context); | |
47 } | |
48 | |
49 private TypeMirror getUnexpectedValueException() { | |
50 return getContext().getTruffleTypes().getUnexpectedValueException(); | |
51 } | |
52 | |
53 private static String factoryClassName(NodeData node) { | |
54 return nodeClassName(node) + "Factory"; | |
55 } | |
56 | |
57 private static String nodeClassName(NodeData node) { | |
58 return Utils.getSimpleName(node.getTemplateType().asType()); | |
59 } | |
60 | |
61 private static String nodeClassName(SpecializationData specialization) { | |
62 String name = ""; | |
63 if (specialization.getNode().getSpecializations().length > 1) { | |
64 name = specialization.getMethodName(); | |
65 if (name.startsWith("do")) { | |
66 name = name.substring(2); | |
67 } | |
68 } | |
69 name += nodeClassName(specialization.getNode()); | |
70 if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) | |
71 || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) { | |
72 name = name + "Impl"; | |
73 } | |
74 | |
75 return name; | |
76 } | |
77 | |
78 private static String valueName(NodeFieldData field) { | |
79 return field.getName() + "Value"; | |
80 } | |
81 | |
82 private static String valueName(TemplateMethod method, ActualParameter param) { | |
83 NodeData node = (NodeData) method.getTemplate(); | |
84 NodeFieldData field = node.findField(param.getSpecification().getName()); | |
85 if (field != null) { | |
86 return valueName(field); | |
87 } else { | |
88 return param.getSpecification().getName(); | |
89 } | |
90 } | |
91 | |
92 private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { | |
93 if (forceFrame) { | |
94 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frame")); | |
95 } | |
96 for (ActualParameter parameter : specialization.getParameters()) { | |
97 ParameterSpec spec = parameter.getSpecification(); | |
98 if (forceFrame && spec.getName().equals("frame")) { | |
99 continue; | |
100 } | |
101 method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(specialization, parameter))); | |
102 } | |
103 } | |
104 | |
105 private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) { | |
106 if (forceFrame) { | |
107 builder.string("frame"); | |
108 } | |
109 for (ActualParameter parameter : specialization.getParameters()) { | |
110 ParameterSpec spec = parameter.getSpecification(); | |
111 if (forceFrame && spec.getName().equals("frame")) { | |
112 continue; | |
113 } | |
114 | |
115 if (unexpectedValueName != null && spec.getName().equals(unexpectedValueName)) { | |
116 builder.string("ex.getResult()"); | |
117 } else { | |
118 builder.string(valueName(specialization, parameter)); | |
119 } | |
120 } | |
121 } | |
122 | |
123 private static void addValueParameterNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization) { | |
124 for (ActualParameter param : specialization.getParameters()) { | |
125 TypeData typeData = param.getActualTypeData(specialization.getNode().getTypeSystem()); | |
126 if (typeData == null || typeData.isGeneric()) { | |
127 body.string(valueName(specialization, param)); | |
128 } else { | |
129 String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); | |
130 startCallTypeSystemMethod(context, body, specialization.getNode(), methodName); | |
131 body.string(valueName(specialization, param)); | |
132 body.end().end(); | |
133 } | |
134 } | |
135 } | |
136 | |
137 private static String genClassName(Template operation) { | |
138 return getSimpleName(operation.getTemplateType()) + "Gen"; | |
139 } | |
140 | |
141 private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) { | |
142 body.startGroup(); | |
143 if (body.findMethod().getModifiers().contains(STATIC)) { | |
144 body.string(THIS_NODE_LOCAL_VAR_NAME); | |
145 } else { | |
146 body.string("super"); | |
147 } | |
148 body.string("."); | |
149 body.startCall(method.getMethodName()); | |
150 } | |
151 | |
152 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { | |
153 VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); | |
154 assert singleton != null; | |
155 | |
156 body.startGroup(); | |
157 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); | |
158 body.string(".").startCall(methodName); | |
159 } | |
160 | |
161 private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { | |
162 TypeSystemData typeSystem = specialization.getNode().getTypeSystem(); | |
163 // Implict guards based on method signature | |
164 String andOperator = prefix; | |
165 for (NodeFieldData field : specialization.getNode().getFields()) { | |
166 ActualParameter param = specialization.findParameter(field.getName()); | |
167 TypeData type = param.getActualTypeData(typeSystem); | |
168 if (type == null || type.isGeneric()) { | |
169 continue; | |
170 } | |
171 | |
172 body.string(andOperator); | |
173 startCallTypeSystemMethod(context, body, specialization.getNode(), | |
174 TypeSystemCodeGenerator.isTypeMethodName(type)); | |
175 body.string(valueName(specialization, param)); | |
176 body.end().end(); // call | |
177 andOperator = " && "; | |
178 } | |
179 | |
180 if (specialization.getGuards().length > 0) { | |
181 // Explicitly specified guards | |
182 for (SpecializationGuardData guard : specialization.getGuards()) { | |
183 if ((guard.isOnSpecialization() && onSpecialization) | |
184 || (guard.isOnExecution() && !onSpecialization)) { | |
185 body.string(andOperator); | |
186 | |
187 startCallOperationMethod(body, guard.getGuardDeclaration()); | |
188 | |
189 if (needsCast) { | |
190 addValueParameterNamesWithCasts(context, body, specialization); | |
191 } else { | |
192 addValueParameterNames(body, specialization, null, false); | |
193 } | |
194 body.end().end(); // call | |
195 andOperator = " && "; | |
196 } | |
197 } | |
198 } | |
199 } | |
200 | |
201 @Override | |
202 protected void createChildren(NodeData node) { | |
203 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); | |
204 if (node.getDeclaredChildren() != null && !node.getDeclaredChildren().isEmpty()) { | |
205 for (NodeData nodeChild : node.getDeclaredChildren()) { | |
206 NodeCodeGenerator generator = new NodeCodeGenerator(getContext()); | |
207 childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements()); | |
208 } | |
209 } | |
210 | |
211 if (node.getExtensionElements() != null && !node.getExtensionElements().isEmpty()) { | |
212 NodeGenFactory factory = new NodeGenFactory(context); | |
213 add(factory, node); | |
214 } | |
215 | |
216 if (node.getSpecializations() == null) { | |
217 return; | |
218 } | |
219 | |
220 if (node.needsFactory() || childTypes.size() > 0) { | |
221 add(new NodeFactoryFactory(context, childTypes), node); | |
222 } | |
223 } | |
224 | |
225 private class NodeGenFactory extends ClassElementFactory<NodeData> { | |
226 | |
227 public NodeGenFactory(ProcessorContext context) { | |
228 super(context); | |
229 } | |
230 | |
231 @Override | |
232 protected CodeTypeElement create(NodeData node) { | |
233 CodeTypeElement clazz = createClass(node, modifiers(PUBLIC, ABSTRACT), genClassName(node), node.getTemplateType().asType(), false); | |
234 | |
235 for (ExecutableElement executable : ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements())) { | |
236 CodeExecutableElement superConstructor = createSuperConstructor(clazz, executable); | |
237 | |
238 if (superConstructor != null) { | |
239 if (superConstructor.getParameters().size() == 1 | |
240 && Utils.typeEquals(superConstructor.getParameters().get(0).asType(), node.getTemplateType().asType())) { | |
241 String originalName = superConstructor.getParameters().get(0).getSimpleName().toString(); | |
242 superConstructor.getParameters().clear(); | |
243 superConstructor.getParameters().add(new CodeVariableElement(clazz.asType(), originalName)); | |
244 } | |
245 clazz.add(superConstructor); | |
246 } | |
247 } | |
248 | |
249 if (node.getExtensionElements() != null) { | |
250 clazz.getEnclosedElements().addAll(node.getExtensionElements()); | |
251 } | |
252 | |
253 node.setNodeType(clazz.asType()); | |
254 | |
255 return clazz; | |
256 } | |
257 | |
258 } | |
259 | |
260 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { | |
261 | |
262 private final Map<NodeData, List<TypeElement>> childTypes; | |
263 | |
264 public NodeFactoryFactory(ProcessorContext context, Map<NodeData, List<TypeElement>> childElements) { | |
265 super(context); | |
266 this.childTypes = childElements; | |
267 } | |
268 | |
269 @Override | |
270 protected CodeTypeElement create(NodeData node) { | |
271 Modifier visibility = Utils.getVisibility(node.getTemplateType().getModifiers()); | |
272 CodeTypeElement clazz = createClass(node, modifiers(), factoryClassName(node), null, false); | |
273 if (visibility != null) { | |
274 clazz.getModifiers().add(visibility); | |
275 } | |
276 clazz.getModifiers().add(Modifier.FINAL); | |
277 clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); | |
278 return clazz; | |
279 } | |
280 | |
281 @Override | |
282 protected void createChildren(NodeData node) { | |
283 CodeTypeElement clazz = getElement(); | |
284 | |
285 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); | |
286 | |
287 if (node.needsFactory()) { | |
288 createFactoryMethods(node, clazz, createVisibility); | |
289 | |
290 if (node.getSpecializations().length > 1) { | |
291 clazz.add(createCreateSpecializedMethod(node, createVisibility)); | |
292 } | |
293 | |
294 if (node.needsRewrites(getContext())) { | |
295 clazz.add(createSpecializeMethod(node)); | |
296 clazz.add(createGeneratedGenericMethod(node)); | |
297 } | |
298 | |
299 for (SpecializationData specialization : node.getSpecializations()) { | |
300 add(new SpecializedNodeFactory(context), specialization); | |
301 } | |
302 } | |
303 | |
304 for (NodeData childNode : childTypes.keySet()) { | |
305 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { | |
306 continue; | |
307 } | |
308 | |
309 for (TypeElement type : childTypes.get(childNode)) { | |
310 Set<Modifier> typeModifiers = ((CodeTypeElement) type).getModifiers(); | |
311 Modifier visibility = Utils.getVisibility(type.getModifiers()); | |
312 typeModifiers.clear(); | |
313 if (visibility != null) { | |
314 typeModifiers.add(visibility); | |
315 } | |
316 | |
317 typeModifiers.add(Modifier.STATIC); | |
318 typeModifiers.add(Modifier.FINAL); | |
319 clazz.add(type); | |
320 } | |
321 } | |
322 } | |
323 | |
324 private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { | |
325 for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(node.getNodeType()).getEnclosedElements())) { | |
326 if (constructor.getModifiers().contains(PRIVATE)) { | |
327 continue; | |
328 } | |
329 | |
330 // skip node rewrite constructor | |
331 if (constructor.getParameters().size() == 1 | |
332 && typeEquals(constructor.getParameters().get(0).asType(), node.getNodeType())) { | |
333 continue; | |
334 } | |
335 | |
336 clazz.add(createCreateMethod(node, createVisibility, constructor)); | |
337 } | |
338 } | |
339 | |
340 private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { | |
341 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor); | |
342 method.setSimpleName(CodeNames.of("create")); | |
343 method.getModifiers().clear(); | |
344 if (visibility != null) { | |
345 method.getModifiers().add(visibility); | |
346 } | |
347 method.getModifiers().add(Modifier.STATIC); | |
348 method.setReturnType(node.getNodeType()); | |
349 | |
350 CodeTreeBuilder body = method.createBuilder(); | |
351 body.startReturn(); | |
352 if (node.getSpecializations().length == 0) { | |
353 body.null_(); | |
354 } else { | |
355 body.startNew(nodeClassName(node.getSpecializations()[0])); | |
356 for (VariableElement var : method.getParameters()) { | |
357 body.string(var.getSimpleName().toString()); | |
358 } | |
359 body.end(); | |
360 } | |
361 body.end(); | |
362 return method; | |
363 } | |
364 | |
365 private CodeExecutableElement createCreateSpecializedMethod(NodeData node, Modifier visibility) { | |
366 CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createSpecialized"); | |
367 if (visibility != null) { | |
368 method.getModifiers().add(visibility); | |
369 } | |
370 method.getModifiers().add(Modifier.STATIC); | |
371 | |
372 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); | |
373 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); | |
374 | |
375 CodeTreeBuilder body = method.createBuilder(); | |
376 boolean first = true; | |
377 for (TypeData type : node.getTypeSystem().getTypes()) { | |
378 SpecializationData specialization = node.findUniqueSpecialization(type); | |
379 if (specialization != null && !type.isGeneric()) { | |
380 if (first) { | |
381 body.startIf(); | |
382 first = false; | |
383 } else { | |
384 body.startElseIf(); | |
385 } | |
386 body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); | |
387 body.startReturn().startNew(nodeClassName(specialization)); | |
388 body.string(THIS_NODE_LOCAL_VAR_NAME); | |
389 body.end().end(); // new, return | |
390 | |
391 body.end(); // if | |
392 } | |
393 } | |
394 body.startReturn().startNew(nodeClassName(node.getGenericSpecialization())); | |
395 body.string(THIS_NODE_LOCAL_VAR_NAME); | |
396 body.end().end(); | |
397 return method; | |
398 } | |
399 | |
400 private CodeExecutableElement createSpecializeMethod(NodeData node) { | |
401 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); | |
402 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); | |
403 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); | |
404 addValueParameters(method, node.getGenericSpecialization(), false); | |
405 | |
406 CodeTreeBuilder body = method.createBuilder(); | |
407 body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations()[0])).string(".class)").end(); | |
408 | |
409 for (int i = 1; i < node.getSpecializations().length; i++) { | |
410 SpecializationData specialization = node.getSpecializations()[i]; | |
411 body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); | |
412 | |
413 if (specialization.isGeneric()) { | |
414 body.startIf().string("allowed").end().startBlock(); | |
415 } else { | |
416 body.startIf().string("allowed"); | |
417 emitGuards(getContext(), body, " && ", specialization, true, true); | |
418 body.end().startBlock(); | |
419 } | |
420 body.startReturn().startNew(nodeClassName(specialization)); | |
421 body.string(THIS_NODE_LOCAL_VAR_NAME); | |
422 body.end().end(); | |
423 body.end(); // block | |
424 } | |
425 body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); | |
426 | |
427 return method; | |
428 } | |
429 | |
430 | |
431 private CodeExecutableElement createGeneratedGenericMethod(NodeData node) { | |
432 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getGenericSpecialization().getReturnType().getActualType(), "generatedGeneric"); | |
433 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); | |
434 addValueParameters(method, node.getGenericSpecialization(), true); | |
435 | |
436 CodeTreeBuilder builder = method.createBuilder(); | |
437 boolean ifStarted = false; | |
438 for (int i = 0; i < node.getSpecializations().length; i++) { | |
439 SpecializationData specialization = node.getSpecializations()[i]; | |
440 if (specialization.isUninitialized()) { | |
441 continue; | |
442 } | |
443 if (!specialization.isGeneric()) { | |
444 if (!ifStarted) { | |
445 builder.startIf(); | |
446 ifStarted = true; | |
447 } else { | |
448 builder.startElseIf(); | |
449 } | |
450 emitGuards(getContext(), builder, "", specialization, false, true); | |
451 builder.end().startBlock(); | |
452 } else { | |
453 builder.startElseBlock(); | |
454 } | |
455 | |
456 emitInvokeDoMethod(builder, specialization, 0); | |
457 builder.end(); | |
458 } | |
459 return method; | |
460 } | |
461 | |
462 private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization, int level) { | |
463 if (specialization.getExceptions().length > 0) { | |
464 builder.startTryBlock(); | |
465 } | |
466 | |
467 builder.startReturn(); | |
468 startCallOperationMethod(builder, specialization); | |
469 addValueParameterNamesWithCasts(context, builder, specialization); | |
470 builder.end().end(); // start call operation | |
471 builder.end(); // return | |
472 | |
473 if (specialization.getExceptions().length > 0) { | |
474 for (SpecializationThrowsData exception : specialization.getExceptions()) { | |
475 builder.end().startCatchBlock(exception.getJavaClass(), "ex" + level); | |
476 emitInvokeDoMethod(builder, exception.getTransitionTo(), level + 1); | |
477 } | |
478 builder.end(); | |
479 } | |
480 } | |
481 } | |
482 | |
483 private class SpecializedNodeFactory extends ClassElementFactory<SpecializationData> { | |
484 | |
485 | |
486 public SpecializedNodeFactory(ProcessorContext context) { | |
487 super(context); | |
488 } | |
489 | |
490 @Override | |
491 public CodeTypeElement create(SpecializationData specialization) { | |
492 NodeData node = specialization.getNode(); | |
493 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false); | |
494 return clazz; | |
495 } | |
496 | |
497 @Override | |
498 protected void createChildren(SpecializationData specialization) { | |
499 CodeTypeElement clazz = getElement(); | |
500 NodeData node = specialization.getNode(); | |
501 | |
502 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); | |
503 for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { | |
504 ExecutableElement superConstructor = createSuperConstructor(clazz, constructor); | |
505 if (superConstructor != null) { | |
506 clazz.add(superConstructor); | |
507 } | |
508 } | |
509 | |
510 for (ExecutableTypeData execType : node.getExecutableTypes()) { | |
511 if (execType.isFinal()) { | |
512 continue; | |
513 } | |
514 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); | |
515 if (method.getParameters().size() == 1) { | |
516 CodeVariableElement var = CodeVariableElement.clone(method.getParameters().get(0)); | |
517 var.setName("frame"); | |
518 method.getParameters().set(0, var); | |
519 } | |
520 method.getModifiers().remove(Modifier.ABSTRACT); | |
521 clazz.add(method); | |
522 | |
523 TypeData primaryType = specialization.getReturnType().getActualTypeData(node.getTypeSystem()); | |
524 if (primaryType == execType.getType()) { | |
525 buildFunctionalExecuteMethod(method.createBuilder(), specialization); | |
526 } else { | |
527 buildCastingExecuteMethod(method.createBuilder(), specialization, execType.getType()); | |
528 } | |
529 } | |
530 | |
531 if (node.needsRewrites(getContext()) && !specialization.isGeneric() && !specialization.isUninitialized()) { | |
532 buildSpecializeStateMethod(clazz, specialization); | |
533 } | |
534 } | |
535 | |
536 private void buildCastingExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization, TypeData type) { | |
537 NodeData node = specialization.getNode(); | |
538 TypeSystemData typeSystem = node.getTypeSystem(); | |
539 | |
540 if (!type.isVoid()) { | |
541 builder.startStatement().type(specialization.getReturnType().getActualType()).string(" result").end(); | |
542 } | |
543 | |
544 TypeData primaryType = specialization.getReturnType().getActualTypeData(typeSystem); | |
545 ExecutableTypeData execType = specialization.getNode().findExecutableType(primaryType); | |
546 | |
547 boolean needsTry = !specialization.getReturnType().getActualTypeData(typeSystem).isGeneric(); | |
548 if (needsTry) { | |
549 builder.startTryBlock(); | |
550 } | |
551 | |
552 builder.startStatement(); | |
553 if (!type.isVoid()) { | |
554 builder.string("result = "); | |
555 } | |
556 buildExecute(builder, null, execType); | |
557 builder.end(); // statement | |
558 | |
559 if (needsTry) { | |
560 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); | |
561 | |
562 if (!type.isVoid()) { | |
563 builder.startReturn(); | |
564 if (!type.isGeneric()) { | |
565 startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(type)); | |
566 } | |
567 | |
568 builder.string("ex.getResult()"); | |
569 | |
570 if (!type.isGeneric()) { | |
571 builder.end().end(); | |
572 } | |
573 builder.end(); // return | |
574 } else { | |
575 builder.string("// ignore").newLine(); | |
576 } | |
577 } | |
578 builder.end(); // try/catch | |
579 | |
580 if (!type.isVoid()) { | |
581 builder.startReturn(); | |
582 if (!type.isGeneric()) { | |
583 startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.expectTypeMethodName(type)); | |
584 } | |
585 builder.string("result"); | |
586 if (!type.isGeneric()) { | |
587 builder.end().end(); | |
588 } | |
589 builder.end(); // return | |
590 } | |
591 } | |
592 | |
593 private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, SpecializationData specialization) { | |
594 NodeData node = specialization.getNode(); | |
595 TypeSystemData typeSystem = node.getTypeSystem(); | |
596 | |
597 for (NodeFieldData field : node.getFields()) { | |
598 if (field.getExecutionKind() == ExecutionKind.IGNORE) { | |
599 continue; | |
600 } | |
601 | |
602 ActualParameter parameterType = specialization.findParameter(field.getName()); | |
603 | |
604 if (parameterType.getActualTypeData(typeSystem).isGeneric()) { | |
605 buildGenericValueExecute(builder, specialization, field, null); | |
606 } else { | |
607 buildSpecializedValueExecute(builder, specialization, field); | |
608 } | |
609 } | |
610 | |
611 if (specialization.hasDynamicGuards()) { | |
612 builder.startIf(); | |
613 emitGuards(getContext(), builder, "", specialization, false, false); | |
614 builder.end().startBlock(); | |
615 } | |
616 if (specialization.getExceptions().length > 0) { | |
617 builder.startTryBlock(); | |
618 } | |
619 | |
620 if (specialization.isUninitialized()) { | |
621 for (TemplateMethod listener : node.getSpecializationListeners()) { | |
622 builder.startStatement(); | |
623 startCallOperationMethod(builder, listener); | |
624 addValueParameterNames(builder, listener, null, false); | |
625 builder.end().end(); | |
626 builder.end(); // statement | |
627 } | |
628 | |
629 builder.startStatement(); | |
630 builder.startCall("replace"); | |
631 if (node.needsRewrites(getContext())) { | |
632 builder.startCall(factoryClassName(node), "specialize"); | |
633 builder.string("this"); | |
634 builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); | |
635 addValueParameterNames(builder, specialization, null, false); | |
636 builder.end(); // call replace, call specialize | |
637 } else { | |
638 builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); | |
639 } | |
640 builder.end().end(); | |
641 } | |
642 | |
643 if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { | |
644 builder.startReturn().startCall(factoryClassName(node), "generatedGeneric"); | |
645 builder.string("this"); | |
646 addValueParameterNames(builder, specialization, null, true); | |
647 builder.end().end(); | |
648 } else { | |
649 builder.startReturn(); | |
650 | |
651 if (specialization.isUninitialized()) { | |
652 startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization()); | |
653 } else { | |
654 startCallOperationMethod(builder, specialization); | |
655 } | |
656 addValueParameterNames(builder, specialization, null, false); | |
657 builder.end().end(); // operation call | |
658 builder.end(); // return | |
659 } | |
660 | |
661 if (specialization.getExceptions().length > 0) { | |
662 for (SpecializationThrowsData exception : specialization.getExceptions()) { | |
663 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); | |
664 buildThrowSpecialize(builder, exception.getTransitionTo(), null); | |
665 } | |
666 builder.end(); | |
667 } | |
668 if (specialization.hasDynamicGuards()) { | |
669 builder.end().startElseBlock(); | |
670 buildThrowSpecialize(builder, specialization.findNextSpecialization(), null); | |
671 builder.end(); | |
672 } | |
673 } | |
674 | |
675 private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field, NodeFieldData exceptionSpec) { | |
676 ActualParameter specParameter = specialization.findParameter(field.getName()); | |
677 | |
678 boolean shortCircuit = startShortCircuit(builder, specialization, | |
679 field, exceptionSpec); | |
680 | |
681 builder.startStatement(); | |
682 if (!shortCircuit) { | |
683 builder.type(specialization.getNode().getTypeSystem().getGenericType()); | |
684 builder.string(" "); | |
685 } | |
686 | |
687 builder.string(valueName(specialization, specParameter)); | |
688 builder.string(" = "); | |
689 ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext()); | |
690 if (genericExecutableType == null) { | |
691 throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + Arrays.toString(field.getNodeData().getExecutableTypes())); | |
692 } | |
693 buildExecute(builder, field, genericExecutableType); | |
694 builder.end(); | |
695 | |
696 endShortCircuit(builder, shortCircuit); | |
697 } | |
698 | |
699 private void buildExecute(CodeTreeBuilder builder, NodeFieldData field, ExecutableTypeData execType) { | |
700 if (field != null) { | |
701 Element accessElement = field.getAccessElement(); | |
702 if (accessElement.getKind() == ElementKind.METHOD) { | |
703 builder.startCall(accessElement.getSimpleName().toString()).end(); | |
704 } else if (accessElement.getKind() == ElementKind.FIELD) { | |
705 builder.string("this.").string(accessElement.getSimpleName().toString()); | |
706 } else { | |
707 throw new AssertionError(); | |
708 } | |
709 builder.string("."); | |
710 } | |
711 builder.startCall(execType.getMethodName()); | |
712 if (execType.getParameters().length == 1) { | |
713 builder.string("frame"); | |
714 } | |
715 builder.end(); | |
716 } | |
717 | |
718 | |
719 private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, NodeFieldData field) { | |
720 ActualParameter param = specialization.findParameter(field.getName()); | |
721 boolean shortCircuit = startShortCircuit(builder, specialization, field, null); | |
722 | |
723 if (!shortCircuit) { | |
724 builder.startStatement().type(param.getActualType()).string(" ").string(valueName(specialization, param)).end(); | |
725 } | |
726 | |
727 ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); | |
728 | |
729 if (execType.hasUnexpectedValue(getContext())) { | |
730 builder.startTryBlock(); | |
731 } | |
732 | |
733 builder.startStatement().string(valueName(field)).string(" = "); | |
734 buildExecute(builder, field, execType); | |
735 builder.end(); | |
736 | |
737 | |
738 if (execType.hasUnexpectedValue(getContext())) { | |
739 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); | |
740 boolean execute = false; | |
741 for (NodeFieldData exField : specialization.getNode().getFields()) { | |
742 if (exField.getExecutionKind() == ExecutionKind.IGNORE) { | |
743 continue; | |
744 } | |
745 if (execute) { | |
746 buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exField, field); | |
747 } else if (exField == field) { | |
748 execute = true; | |
749 } | |
750 } | |
751 buildThrowSpecialize(builder, specialization.findNextSpecialization(), param.getSpecification()); | |
752 builder.end(); // catch block | |
753 } | |
754 | |
755 endShortCircuit(builder, shortCircuit); | |
756 builder.newLine(); | |
757 } | |
758 | |
759 | |
760 private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, | |
761 NodeFieldData forField, NodeFieldData exceptionField) { | |
762 if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { | |
763 return false; | |
764 } | |
765 | |
766 ActualParameter parameter = specialization.findParameter(forField.getName()); | |
767 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); | |
768 | |
769 int shortCircuitIndex = 0; | |
770 for (NodeFieldData field : specialization.getNode().getFields()) { | |
771 if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { | |
772 if (field == forField) { | |
773 break; | |
774 } | |
775 shortCircuitIndex++; | |
776 } | |
777 } | |
778 | |
779 builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(specialization, shortCircuitParam)).string(" = "); | |
780 ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; | |
781 | |
782 startCallOperationMethod(builder, shortCircuitData); | |
783 addValueParameterNames(builder, shortCircuitData, exceptionField != null ? exceptionField.getName() : null, false); | |
784 builder.end().end(); // call operation | |
785 | |
786 builder.end(); // statement | |
787 | |
788 builder.declaration(parameter.getActualType(), valueName(specialization, parameter), | |
789 CodeTreeBuilder.createBuilder().defaultValue(parameter.getActualType())); | |
790 builder.startIf().string(shortCircuitParam.getSpecification().getName()).end(); | |
791 builder.startBlock(); | |
792 | |
793 return true; | |
794 } | |
795 | |
796 | |
797 private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { | |
798 if (shortCircuit) { | |
799 builder.end(); | |
800 } | |
801 } | |
802 | |
803 private void buildThrowSpecialize(CodeTreeBuilder builder, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { | |
804 boolean canThrowUnexpected = Utils.canThrowType(builder.findMethod().getThrownTypes(), getContext().getTruffleTypes().getUnexpectedValueException()); | |
805 | |
806 CodeTreeBuilder specializeCall = CodeTreeBuilder.createBuilder(); | |
807 specializeCall.startCall("specialize"); | |
808 specializeCall.string(nodeClassName(nextSpecialization) + ".class"); | |
809 addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionSpec != null ? exceptionSpec.getName() : null, true); | |
810 specializeCall.end().end(); | |
811 | |
812 if (canThrowUnexpected) { | |
813 builder.startThrow(); | |
814 builder.startNew(getContext().getTruffleTypes().getUnexpectedValueException()); | |
815 builder.tree(specializeCall.getRoot()); | |
816 builder.end().end(); | |
817 } else { | |
818 builder.startReturn(); | |
819 builder.tree(specializeCall.getRoot()); | |
820 builder.end(); | |
821 } | |
822 | |
823 } | |
824 | |
825 private void buildSpecializeStateMethod(CodeTypeElement clazz, SpecializationData specialization) { | |
826 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), specialization.getNode().getTypeSystem().getGenericType(), "specialize"); | |
827 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); | |
828 addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); | |
829 clazz.add(method); | |
830 | |
831 CodeTreeBuilder builder = method.createBuilder(); | |
832 for (TemplateMethod listener : specialization.getNode().getSpecializationListeners()) { | |
833 builder.startStatement(); | |
834 startCallOperationMethod(builder, listener); | |
835 addValueParameterNames(builder, listener, null, false); | |
836 builder.end().end(); // call operation | |
837 builder.end(); // statement | |
838 } | |
839 | |
840 builder.startStatement(); | |
841 builder.startCall("replace"); | |
842 builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); | |
843 addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false); | |
844 builder.end(); | |
845 builder.end(); // call replace | |
846 builder.end(); // statement | |
847 | |
848 ExecutableElement generatedGeneric = clazz.getEnclosingClass().getMethod("generatedGeneric"); | |
849 | |
850 CodeTreeBuilder genericBuilder = CodeTreeBuilder.createBuilder(); | |
851 genericBuilder.startCall(factoryClassName(specialization.getNode()), "generatedGeneric"); | |
852 genericBuilder.string("this"); | |
853 addValueParameterNames(genericBuilder, specialization.getNode().getGenericSpecialization(), null, true); | |
854 genericBuilder.end(); // call generated generic | |
855 | |
856 if (Utils.isVoid(generatedGeneric.getReturnType())) { | |
857 builder.declaration(generatedGeneric.getReturnType(), "genericResult", genericBuilder.getRoot()); | |
858 builder.startReturn().string("null").end(); | |
859 } else { | |
860 builder.startReturn().tree(genericBuilder.getRoot()).end(); | |
861 } | |
862 } | |
863 | |
864 } | |
865 | |
866 } |