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 }