Mercurial > hg > truffle
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java @ 10597:79041ab43660
Truffle-DSL: API-change: Renamed truffle.api.codegen to truffle.api.dsl for all projects and packages.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 01 Jul 2013 20:58:32 +0200 |
parents | |
children | e93efe3ba5f4 |
comparison
equal
deleted
inserted
replaced
10596:f43eb2f1bbbc | 10597:79041ab43660 |
---|---|
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.dsl.processor.node; | |
24 | |
25 import static com.oracle.truffle.dsl.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.api.dsl.*; | |
35 import com.oracle.truffle.api.nodes.NodeInfo.Kind; | |
36 import com.oracle.truffle.dsl.processor.*; | |
37 import com.oracle.truffle.dsl.processor.ast.*; | |
38 import com.oracle.truffle.dsl.processor.node.NodeChildData.*; | |
39 import com.oracle.truffle.dsl.processor.template.*; | |
40 import com.oracle.truffle.dsl.processor.typesystem.*; | |
41 | |
42 public class NodeCodeGenerator extends CompilationUnitFactory<NodeData> { | |
43 | |
44 private static final String THIS_NODE_LOCAL_VAR_NAME = "thisNode"; | |
45 | |
46 private static final String EXECUTE_GENERIC_NAME = "executeGeneric0"; | |
47 private static final String EXECUTE_SPECIALIZE_NAME = "executeAndSpecialize0"; | |
48 | |
49 public NodeCodeGenerator(ProcessorContext context) { | |
50 super(context); | |
51 } | |
52 | |
53 private TypeMirror getUnexpectedValueException() { | |
54 return getContext().getTruffleTypes().getUnexpectedValueException(); | |
55 } | |
56 | |
57 private static String factoryClassName(NodeData node) { | |
58 return node.getNodeId() + "Factory"; | |
59 } | |
60 | |
61 private static String nodeSpecializationClassName(SpecializationData specialization) { | |
62 String nodeid = specialization.getNode().getNodeId(); | |
63 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
64 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
65 } | |
66 | |
67 String name = Utils.firstLetterUpperCase(nodeid); | |
68 name += Utils.firstLetterUpperCase(specialization.getId()); | |
69 name += "Node"; | |
70 return name; | |
71 } | |
72 | |
73 private static String nodePolymorphicClassName(NodeData node, SpecializationData specialization) { | |
74 String nodeid = node.getNodeId(); | |
75 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
76 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
77 } | |
78 | |
79 String name = Utils.firstLetterUpperCase(nodeid); | |
80 int index = specialization == null ? 0 : node.getPolymorphicSpecializations().indexOf(specialization); | |
81 if (index == 0) { | |
82 name += "PolymorphicNode"; | |
83 } else { | |
84 name += "Polymorphic" + index + "Node"; | |
85 } | |
86 return name; | |
87 } | |
88 | |
89 private static String valueNameEvaluated(ActualParameter targetParameter) { | |
90 return valueName(targetParameter) + "Evaluated"; | |
91 } | |
92 | |
93 private static String valueName(ActualParameter param) { | |
94 return param.getLocalName(); | |
95 } | |
96 | |
97 private static String castValueName(ActualParameter parameter) { | |
98 return valueName(parameter) + "Cast"; | |
99 } | |
100 | |
101 private void addInternalValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean evaluated) { | |
102 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { | |
103 method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); | |
104 } | |
105 for (ActualParameter parameter : specialization.getParameters()) { | |
106 ParameterSpec spec = parameter.getSpecification(); | |
107 if (forceFrame && spec.getName().equals("frame")) { | |
108 continue; | |
109 } | |
110 if (spec.isLocal()) { | |
111 continue; | |
112 } | |
113 | |
114 String name = valueName(parameter); | |
115 if (evaluated && spec.isSignature()) { | |
116 name = valueNameEvaluated(parameter); | |
117 } | |
118 | |
119 method.addParameter(new CodeVariableElement(parameter.getType(), name)); | |
120 } | |
121 } | |
122 | |
123 private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { | |
124 if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { | |
125 builder.string("frameValue"); | |
126 } | |
127 for (ActualParameter parameter : specialization.getParameters()) { | |
128 ParameterSpec spec = parameter.getSpecification(); | |
129 if (forceFrame && spec.getName().equals("frame")) { | |
130 continue; | |
131 } | |
132 | |
133 if (!includeImplicit && (parameter.isImplicit())) { | |
134 continue; | |
135 } | |
136 if (parameter.getSpecification().isLocal()) { | |
137 continue; | |
138 } | |
139 | |
140 ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); | |
141 | |
142 if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { | |
143 builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); | |
144 } else if (sourceParameter != null) { | |
145 builder.string(valueName(sourceParameter, parameter)); | |
146 } else { | |
147 builder.string(valueName(parameter)); | |
148 } | |
149 } | |
150 } | |
151 | |
152 private String valueName(ActualParameter sourceParameter, ActualParameter targetParameter) { | |
153 if (sourceParameter != null) { | |
154 if (!sourceParameter.getSpecification().isSignature()) { | |
155 return valueName(targetParameter); | |
156 } else if (sourceParameter.getTypeSystemType() != null && targetParameter.getTypeSystemType() != null) { | |
157 if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), targetParameter.getTypeSystemType())) { | |
158 return castValueName(targetParameter); | |
159 } | |
160 } | |
161 return valueName(targetParameter); | |
162 } else { | |
163 return valueName(targetParameter); | |
164 } | |
165 } | |
166 | |
167 private CodeTree createTemplateMethodCall(CodeTreeBuilder parent, CodeTree target, TemplateMethod sourceMethod, TemplateMethod targetMethod, String unexpectedValueName, | |
168 String... customSignatureValueNames) { | |
169 CodeTreeBuilder builder = parent.create(); | |
170 | |
171 boolean castedValues = sourceMethod != targetMethod; | |
172 | |
173 builder.startGroup(); | |
174 ExecutableElement method = targetMethod.getMethod(); | |
175 if (method == null) { | |
176 throw new UnsupportedOperationException(); | |
177 } | |
178 TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); | |
179 NodeData node = (NodeData) targetMethod.getTemplate(); | |
180 | |
181 if (target == null) { | |
182 boolean accessible = targetMethod.canBeAccessedByInstanceOf(getContext(), node.getNodeType()); | |
183 if (accessible) { | |
184 if (builder.findMethod().getModifiers().contains(STATIC)) { | |
185 if (method.getModifiers().contains(STATIC)) { | |
186 builder.type(targetClass.asType()); | |
187 } else { | |
188 builder.string(THIS_NODE_LOCAL_VAR_NAME); | |
189 } | |
190 } else { | |
191 if (targetMethod instanceof ExecutableTypeData) { | |
192 builder.string("this"); | |
193 } else { | |
194 builder.string("super"); | |
195 } | |
196 } | |
197 } else { | |
198 if (method.getModifiers().contains(STATIC)) { | |
199 builder.type(targetClass.asType()); | |
200 } else { | |
201 ActualParameter parameter = null; | |
202 for (ActualParameter searchParameter : targetMethod.getParameters()) { | |
203 if (searchParameter.getSpecification().isSignature()) { | |
204 parameter = searchParameter; | |
205 break; | |
206 } | |
207 } | |
208 ActualParameter sourceParameter = sourceMethod.findParameter(parameter.getLocalName()); | |
209 assert parameter != null; | |
210 | |
211 if (castedValues && sourceParameter != null) { | |
212 builder.string(valueName(sourceParameter, parameter)); | |
213 } else { | |
214 builder.string(valueName(parameter)); | |
215 } | |
216 } | |
217 } | |
218 builder.string("."); | |
219 } else { | |
220 builder.tree(target); | |
221 } | |
222 builder.startCall(method.getSimpleName().toString()); | |
223 | |
224 int signatureIndex = 0; | |
225 | |
226 for (ActualParameter targetParameter : targetMethod.getParameters()) { | |
227 ActualParameter valueParameter = null; | |
228 if (sourceMethod != null) { | |
229 valueParameter = sourceMethod.findParameter(targetParameter.getLocalName()); | |
230 } | |
231 if (valueParameter == null) { | |
232 valueParameter = targetParameter; | |
233 } | |
234 TypeData targetType = targetParameter.getTypeSystemType(); | |
235 | |
236 if (targetParameter.isImplicit() || valueParameter.isImplicit()) { | |
237 continue; | |
238 } | |
239 | |
240 TypeData valueType = null; | |
241 if (valueParameter != null) { | |
242 valueType = valueParameter.getTypeSystemType(); | |
243 } | |
244 | |
245 if (signatureIndex < customSignatureValueNames.length && targetParameter.getSpecification().isSignature()) { | |
246 builder.string(customSignatureValueNames[signatureIndex]); | |
247 signatureIndex++; | |
248 } else if (targetParameter.getSpecification().isLocal()) { | |
249 builder.startGroup(); | |
250 if (builder.findMethod().getModifiers().contains(Modifier.STATIC)) { | |
251 builder.string(THIS_NODE_LOCAL_VAR_NAME).string("."); | |
252 } else { | |
253 builder.string("this."); | |
254 } | |
255 builder.string(targetParameter.getSpecification().getName()); | |
256 builder.end(); | |
257 } else if (unexpectedValueName != null && targetParameter.getLocalName().equals(unexpectedValueName)) { | |
258 builder.string("ex.getResult()"); | |
259 } else if (targetType == null || targetType.isGeneric() || (valueType != null && valueType.equalsType(targetType))) { | |
260 builder.startGroup(); | |
261 | |
262 if (valueType != null && sourceMethod.getMethodName().equals(targetMethod.getMethodName()) && !valueType.isGeneric() && targetType.isGeneric()) { | |
263 builder.string("("); | |
264 builder.type(targetType.getPrimitiveType()); | |
265 builder.string(") "); | |
266 } | |
267 builder.string(valueName(targetParameter)); | |
268 builder.end(); | |
269 } else { | |
270 builder.string(castValueName(targetParameter)); | |
271 } | |
272 } | |
273 | |
274 builder.end().end(); | |
275 | |
276 return builder.getRoot(); | |
277 } | |
278 | |
279 private static String baseClassName(NodeData node) { | |
280 String nodeid = node.getNodeId(); | |
281 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
282 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
283 } | |
284 String name = Utils.firstLetterUpperCase(nodeid); | |
285 name += "BaseNode"; | |
286 return name; | |
287 } | |
288 | |
289 private static CodeTree createCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder parent, NodeData node, String methodName, CodeTree value) { | |
290 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
291 startCallTypeSystemMethod(context, builder, node, methodName); | |
292 builder.tree(value); | |
293 builder.end().end(); | |
294 return builder.getRoot(); | |
295 } | |
296 | |
297 private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, NodeData node, String methodName) { | |
298 VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, node.getTypeSystem()); | |
299 assert singleton != null; | |
300 | |
301 body.startGroup(); | |
302 body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); | |
303 body.string(".").startCall(methodName); | |
304 } | |
305 | |
306 private CodeTree createGuardAndCast(CodeTreeBuilder parent, String conditionPrefix, SpecializationData sourceSpecialization, SpecializationData targetSpecialization, boolean castValues, | |
307 CodeTree guardedStatements, CodeTree elseStatements, boolean emitAssumptions, boolean forceElse) { | |
308 | |
309 NodeData node = targetSpecialization.getNode(); | |
310 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
311 CodeTree implicitGuards = createImplicitGuards(parent, conditionPrefix, sourceSpecialization, targetSpecialization, emitAssumptions); | |
312 CodeTree explicitGuards = createExplicitGuards(parent, implicitGuards == null ? conditionPrefix : null, sourceSpecialization, targetSpecialization); | |
313 | |
314 Set<String> valuesNeedsCast; | |
315 if (castValues) { | |
316 // cast all | |
317 valuesNeedsCast = null; | |
318 } else { | |
319 // find out which values needs a cast | |
320 valuesNeedsCast = new HashSet<>(); | |
321 for (GuardData guard : targetSpecialization.getGuards()) { | |
322 for (ActualParameter targetParameter : guard.getParameters()) { | |
323 NodeChildData field = node.findChild(targetParameter.getSpecification().getName()); | |
324 if (field == null) { | |
325 continue; | |
326 } | |
327 TypeData targetType = targetParameter.getTypeSystemType(); | |
328 ActualParameter sourceParameter = sourceSpecialization.findParameter(targetParameter.getLocalName()); | |
329 if (sourceParameter == null) { | |
330 sourceParameter = targetParameter; | |
331 } | |
332 TypeData sourceType = sourceParameter.getTypeSystemType(); | |
333 | |
334 if (sourceType.needsCastTo(getContext(), targetType)) { | |
335 valuesNeedsCast.add(targetParameter.getLocalName()); | |
336 } | |
337 } | |
338 } | |
339 } | |
340 | |
341 int ifCount = 0; | |
342 | |
343 if (implicitGuards != null) { | |
344 builder.startIf(); | |
345 builder.tree(implicitGuards); | |
346 builder.end(); | |
347 builder.startBlock(); | |
348 ifCount++; | |
349 } | |
350 | |
351 builder.tree(createCasts(parent, valuesNeedsCast, sourceSpecialization, targetSpecialization)); | |
352 | |
353 if (explicitGuards != null) { | |
354 builder.startIf(); | |
355 builder.tree(explicitGuards); | |
356 builder.end(); | |
357 builder.startBlock(); | |
358 ifCount++; | |
359 } | |
360 | |
361 if (implicitGuards == null && explicitGuards == null && conditionPrefix != null && !conditionPrefix.isEmpty()) { | |
362 builder.startIf(); | |
363 builder.string(conditionPrefix); | |
364 builder.end().startBlock(); | |
365 ifCount++; | |
366 } | |
367 | |
368 builder.tree(guardedStatements); | |
369 | |
370 builder.end(ifCount); | |
371 if (elseStatements != null && (forceElse || ifCount > 0)) { | |
372 builder.tree(elseStatements); | |
373 } | |
374 return builder.getRoot(); | |
375 } | |
376 | |
377 private CodeTree createExplicitGuards(CodeTreeBuilder parent, String conditionPrefix, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { | |
378 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
379 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; | |
380 if (guardedSpecialization.getGuards().size() > 0) { | |
381 // Explicitly specified guards | |
382 for (GuardData guard : guardedSpecialization.getGuards()) { | |
383 builder.string(andOperator); | |
384 builder.tree(createTemplateMethodCall(parent, null, valueSpecialization, guard, null)); | |
385 andOperator = " && "; | |
386 } | |
387 } | |
388 | |
389 return builder.isEmpty() ? null : builder.getRoot(); | |
390 } | |
391 | |
392 private CodeTree createCasts(CodeTreeBuilder parent, Set<String> castWhiteList, TemplateMethod valueSpecialization, SpecializationData guardedSpecialization) { | |
393 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
394 // Implict guards based on method signature | |
395 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { | |
396 NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName()); | |
397 if (field == null) { | |
398 continue; | |
399 } | |
400 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); | |
401 | |
402 if (valueParam == null) { | |
403 /* | |
404 * If used inside a function execute method. The value param may not exist. In that | |
405 * case it assumes that the value is already converted. | |
406 */ | |
407 valueParam = guardedParam; | |
408 } | |
409 | |
410 if (castWhiteList != null && !castWhiteList.contains(guardedParam.getLocalName())) { | |
411 continue; | |
412 } | |
413 | |
414 CodeTree cast = createCast(parent, field, valueParam, guardedParam); | |
415 if (cast == null) { | |
416 continue; | |
417 } | |
418 builder.tree(cast); | |
419 } | |
420 | |
421 return builder.getRoot(); | |
422 } | |
423 | |
424 private CodeTree createImplicitGuards(CodeTreeBuilder parent, String conditionPrefix, SpecializationData valueSpecialization, SpecializationData guardedSpecialization, boolean emitAssumptions) { | |
425 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
426 // Implict guards based on method signature | |
427 String andOperator = conditionPrefix != null ? conditionPrefix + " && " : ""; | |
428 | |
429 if (emitAssumptions) { | |
430 for (String assumption : guardedSpecialization.getAssumptions()) { | |
431 builder.string(andOperator); | |
432 builder.string("this"); | |
433 builder.string(".").string(assumption).string(".isValid()"); | |
434 andOperator = " && "; | |
435 } | |
436 } | |
437 | |
438 for (ActualParameter guardedParam : guardedSpecialization.getParameters()) { | |
439 NodeChildData field = guardedSpecialization.getNode().findChild(guardedParam.getSpecification().getName()); | |
440 if (field == null) { | |
441 continue; | |
442 } | |
443 ActualParameter valueParam = valueSpecialization.findParameter(guardedParam.getLocalName()); | |
444 | |
445 if (valueParam == null) { | |
446 /* | |
447 * If used inside a function execute method. The value param may not exist. In that | |
448 * case it assumes that the value is already converted. | |
449 */ | |
450 valueParam = guardedParam; | |
451 } | |
452 | |
453 CodeTree implicitGuard = createImplicitGuard(builder, field, valueParam, guardedParam); | |
454 if (implicitGuard == null) { | |
455 continue; | |
456 } | |
457 | |
458 builder.string(andOperator); | |
459 builder.tree(implicitGuard); | |
460 andOperator = " && "; | |
461 } | |
462 | |
463 return builder.isEmpty() ? null : builder.getRoot(); | |
464 } | |
465 | |
466 private CodeTree createImplicitGuard(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { | |
467 NodeData node = field.getNodeData(); | |
468 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
469 | |
470 TypeData targetType = target.getTypeSystemType(); | |
471 TypeData sourceType = source.getTypeSystemType(); | |
472 | |
473 if (!sourceType.needsCastTo(getContext(), targetType)) { | |
474 return null; | |
475 } | |
476 | |
477 builder.startGroup(); | |
478 | |
479 if (field.isShortCircuit()) { | |
480 ActualParameter shortCircuit = target.getPreviousParameter(); | |
481 assert shortCircuit != null; | |
482 builder.string("("); | |
483 builder.string("!").string(valueName(shortCircuit)); | |
484 builder.string(" || "); | |
485 } | |
486 | |
487 startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(target.getTypeSystemType())); | |
488 builder.string(valueName(source)); | |
489 builder.end().end(); // call | |
490 | |
491 if (field.isShortCircuit()) { | |
492 builder.string(")"); | |
493 } | |
494 | |
495 builder.end(); // group | |
496 | |
497 return builder.getRoot(); | |
498 } | |
499 | |
500 private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, ActualParameter target) { | |
501 NodeData node = field.getNodeData(); | |
502 TypeData sourceType = source.getTypeSystemType(); | |
503 TypeData targetType = target.getTypeSystemType(); | |
504 | |
505 if (!sourceType.needsCastTo(getContext(), targetType)) { | |
506 return null; | |
507 } | |
508 | |
509 CodeTree condition = null; | |
510 if (field.isShortCircuit()) { | |
511 ActualParameter shortCircuit = target.getPreviousParameter(); | |
512 assert shortCircuit != null; | |
513 condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); | |
514 } | |
515 | |
516 CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(target))); | |
517 | |
518 return createLazyAssignment(parent, castValueName(target), target.getType(), condition, value); | |
519 } | |
520 | |
521 /** | |
522 * <pre> | |
523 * variant1 $condition != null | |
524 * | |
525 * $type $name = defaultValue($type); | |
526 * if ($condition) { | |
527 * $name = $value; | |
528 * } | |
529 * | |
530 * variant2 $condition != null | |
531 * $type $name = $value; | |
532 * </pre> | |
533 * | |
534 * . | |
535 */ | |
536 private static CodeTree createLazyAssignment(CodeTreeBuilder parent, String name, TypeMirror type, CodeTree condition, CodeTree value) { | |
537 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
538 if (condition == null) { | |
539 builder.declaration(type, name, value); | |
540 } else { | |
541 builder.declaration(type, name, new CodeTreeBuilder(parent).defaultValue(type).getRoot()); | |
542 | |
543 builder.startIf().tree(condition).end(); | |
544 builder.startBlock(); | |
545 builder.startStatement(); | |
546 builder.string(name); | |
547 builder.string(" = "); | |
548 builder.tree(value); | |
549 builder.end(); // statement | |
550 builder.end(); // block | |
551 } | |
552 return builder.getRoot(); | |
553 } | |
554 | |
555 protected void emitEncounteredSynthetic(CodeTreeBuilder builder, TemplateMethod current) { | |
556 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); | |
557 builder.startCall("createInfo0"); | |
558 builder.doubleQuote("Unsupported values"); | |
559 addInternalValueParameterNames(builder, current, current, null, false, true); | |
560 builder.end().end().end(); | |
561 } | |
562 | |
563 private static List<ExecutableElement> findUserConstructors(TypeMirror nodeType) { | |
564 List<ExecutableElement> constructors = new ArrayList<>(); | |
565 for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(nodeType).getEnclosedElements())) { | |
566 if (constructor.getModifiers().contains(PRIVATE)) { | |
567 continue; | |
568 } | |
569 if (isCopyConstructor(constructor)) { | |
570 continue; | |
571 } | |
572 constructors.add(constructor); | |
573 } | |
574 | |
575 if (constructors.isEmpty()) { | |
576 constructors.add(new CodeExecutableElement(null, Utils.getSimpleName(nodeType))); | |
577 } | |
578 | |
579 return constructors; | |
580 } | |
581 | |
582 private static ExecutableElement findCopyConstructor(TypeMirror type) { | |
583 for (ExecutableElement constructor : ElementFilter.constructorsIn(Utils.fromTypeMirror(type).getEnclosedElements())) { | |
584 if (constructor.getModifiers().contains(PRIVATE)) { | |
585 continue; | |
586 } | |
587 if (isCopyConstructor(constructor)) { | |
588 return constructor; | |
589 } | |
590 } | |
591 | |
592 return null; | |
593 } | |
594 | |
595 private static boolean isCopyConstructor(ExecutableElement element) { | |
596 if (element.getParameters().size() != 1) { | |
597 return false; | |
598 } | |
599 VariableElement var = element.getParameters().get(0); | |
600 TypeElement type = Utils.findNearestEnclosingType(var); | |
601 | |
602 if (!Utils.typeEquals(var.asType(), type.asType())) { | |
603 return false; | |
604 } | |
605 return true; | |
606 } | |
607 | |
608 @Override | |
609 protected void createChildren(NodeData node) { | |
610 Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); | |
611 if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) { | |
612 for (NodeData nodeChild : node.getDeclaredNodes()) { | |
613 NodeCodeGenerator generator = new NodeCodeGenerator(getContext()); | |
614 childTypes.put(nodeChild, generator.process(null, nodeChild).getEnclosedElements()); | |
615 } | |
616 } | |
617 | |
618 if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { | |
619 add(new NodeFactoryFactory(context, childTypes), node); | |
620 } | |
621 } | |
622 | |
623 private class NodeFactoryFactory extends ClassElementFactory<NodeData> { | |
624 | |
625 private final Map<NodeData, List<TypeElement>> childTypes; | |
626 | |
627 private CodeTypeElement generatedNode; | |
628 | |
629 public NodeFactoryFactory(ProcessorContext context, Map<NodeData, List<TypeElement>> childElements) { | |
630 super(context); | |
631 this.childTypes = childElements; | |
632 } | |
633 | |
634 @Override | |
635 protected CodeTypeElement create(NodeData node) { | |
636 Modifier visibility = Utils.getVisibility(node.getTemplateType().getModifiers()); | |
637 CodeTypeElement clazz = createClass(node, modifiers(), factoryClassName(node), null, false); | |
638 if (visibility != null) { | |
639 clazz.getModifiers().add(visibility); | |
640 } | |
641 clazz.getModifiers().add(Modifier.FINAL); | |
642 clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); | |
643 return clazz; | |
644 } | |
645 | |
646 @Override | |
647 protected void createChildren(NodeData node) { | |
648 CodeTypeElement clazz = getElement(); | |
649 | |
650 Modifier createVisibility = Utils.getVisibility(clazz.getModifiers()); | |
651 | |
652 if (node.needsFactory()) { | |
653 NodeBaseFactory factory = new NodeBaseFactory(context); | |
654 add(factory, node.getGenericSpecialization() == null ? node.getSpecializations().get(0) : node.getGenericSpecialization()); | |
655 generatedNode = factory.getElement(); | |
656 | |
657 if (node.needsRewrites(context)) { | |
658 clazz.add(createCreateGenericMethod(node, createVisibility)); | |
659 } | |
660 | |
661 createFactoryMethods(node, clazz, createVisibility); | |
662 | |
663 PolymorphicNodeFactory generic = null; | |
664 for (SpecializationData specialization : node.getPolymorphicSpecializations()) { | |
665 PolymorphicNodeFactory polymorphicFactory = new PolymorphicNodeFactory(context, generic == null ? generatedNode : generic.getElement(), generic == null); | |
666 add(polymorphicFactory, specialization); | |
667 if (generic == null) { | |
668 generic = polymorphicFactory; | |
669 } | |
670 } | |
671 | |
672 for (SpecializationData specialization : node.getSpecializations()) { | |
673 if (!specialization.isReachable()) { | |
674 continue; | |
675 } | |
676 add(new SpecializedNodeFactory(context, generatedNode), specialization); | |
677 } | |
678 | |
679 TypeMirror nodeFactory = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(NodeFactory.class)), node.getNodeType()); | |
680 clazz.getImplements().add(nodeFactory); | |
681 clazz.add(createCreateNodeMethod(node)); | |
682 clazz.add(createCreateNodeGenericMethod(node)); | |
683 clazz.add(createGetNodeClassMethod(node)); | |
684 clazz.add(createGetNodeSignaturesMethod()); | |
685 clazz.add(createGetChildrenSignatureMethod(node)); | |
686 clazz.add(createGetInstanceMethod(node, createVisibility)); | |
687 clazz.add(createInstanceConstant(node, clazz.asType())); | |
688 } | |
689 | |
690 for (NodeData childNode : childTypes.keySet()) { | |
691 if (childNode.getTemplateType().getModifiers().contains(Modifier.PRIVATE)) { | |
692 continue; | |
693 } | |
694 | |
695 for (TypeElement type : childTypes.get(childNode)) { | |
696 Set<Modifier> typeModifiers = ((CodeTypeElement) type).getModifiers(); | |
697 Modifier visibility = Utils.getVisibility(type.getModifiers()); | |
698 typeModifiers.clear(); | |
699 if (visibility != null) { | |
700 typeModifiers.add(visibility); | |
701 } | |
702 | |
703 typeModifiers.add(Modifier.STATIC); | |
704 typeModifiers.add(Modifier.FINAL); | |
705 clazz.add(type); | |
706 } | |
707 } | |
708 | |
709 List<NodeData> children = node.getNodeDeclaringChildren(); | |
710 if (node.getParent() == null && children.size() > 0) { | |
711 clazz.add(createGetFactories(node)); | |
712 } | |
713 | |
714 } | |
715 | |
716 private CodeExecutableElement createGetNodeClassMethod(NodeData node) { | |
717 TypeMirror returnType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(Class.class)), node.getNodeType()); | |
718 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeClass"); | |
719 CodeTreeBuilder builder = method.createBuilder(); | |
720 builder.startReturn().typeLiteral(node.getNodeType()).end(); | |
721 return method; | |
722 } | |
723 | |
724 private CodeExecutableElement createGetNodeSignaturesMethod() { | |
725 TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); | |
726 TypeMirror classType = getContext().getType(Class.class); | |
727 TypeMirror returnType = Utils.getDeclaredType(listType, Utils.getDeclaredType(listType, classType)); | |
728 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getNodeSignatures"); | |
729 CodeTreeBuilder builder = method.createBuilder(); | |
730 builder.startReturn(); | |
731 builder.startStaticCall(getContext().getType(Arrays.class), "asList"); | |
732 List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType()); | |
733 for (ExecutableElement constructor : constructors) { | |
734 builder.tree(createAsList(builder, Utils.asTypeMirrors(constructor.getParameters()), classType)); | |
735 } | |
736 builder.end(); | |
737 builder.end(); | |
738 return method; | |
739 } | |
740 | |
741 private CodeExecutableElement createGetChildrenSignatureMethod(NodeData node) { | |
742 Types types = getContext().getEnvironment().getTypeUtils(); | |
743 TypeElement listType = Utils.fromTypeMirror(getContext().getType(List.class)); | |
744 TypeMirror classType = getContext().getType(Class.class); | |
745 TypeMirror nodeType = getContext().getTruffleTypes().getNode(); | |
746 TypeMirror wildcardNodeType = types.getWildcardType(nodeType, null); | |
747 classType = Utils.getDeclaredType(Utils.fromTypeMirror(classType), wildcardNodeType); | |
748 TypeMirror returnType = Utils.getDeclaredType(listType, classType); | |
749 | |
750 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getExecutionSignature"); | |
751 CodeTreeBuilder builder = method.createBuilder(); | |
752 | |
753 List<TypeMirror> signatureTypes = new ArrayList<>(); | |
754 assert !node.getSpecializations().isEmpty(); | |
755 SpecializationData data = node.getSpecializations().get(0); | |
756 for (ActualParameter parameter : data.getParameters()) { | |
757 ParameterSpec spec = parameter.getSpecification(); | |
758 NodeChildData field = node.findChild(spec.getName()); | |
759 if (field == null) { | |
760 continue; | |
761 } | |
762 | |
763 TypeMirror type; | |
764 if (field.getCardinality() == Cardinality.MANY && field.getNodeType().getKind() == TypeKind.ARRAY) { | |
765 type = ((ArrayType) field.getNodeType()).getComponentType(); | |
766 } else { | |
767 type = field.getNodeType(); | |
768 } | |
769 | |
770 signatureTypes.add(type); | |
771 } | |
772 | |
773 builder.startReturn().tree(createAsList(builder, signatureTypes, classType)).end(); | |
774 return method; | |
775 } | |
776 | |
777 private CodeTree createAsList(CodeTreeBuilder parent, List<TypeMirror> types, TypeMirror elementClass) { | |
778 CodeTreeBuilder builder = parent.create(); | |
779 builder.startGroup(); | |
780 builder.type(getContext().getType(Arrays.class)); | |
781 builder.string(".<").type(elementClass).string(">"); | |
782 builder.startCall("asList"); | |
783 for (TypeMirror typeMirror : types) { | |
784 builder.typeLiteral(typeMirror); | |
785 } | |
786 builder.end().end(); | |
787 return builder.getRoot(); | |
788 } | |
789 | |
790 private CodeExecutableElement createCreateNodeMethod(NodeData node) { | |
791 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNode"); | |
792 CodeVariableElement arguments = new CodeVariableElement(getContext().getType(Object.class), "arguments"); | |
793 method.setVarArgs(true); | |
794 method.addParameter(arguments); | |
795 | |
796 CodeTreeBuilder builder = method.createBuilder(); | |
797 List<ExecutableElement> signatures = findUserConstructors(generatedNode.asType()); | |
798 boolean ifStarted = false; | |
799 | |
800 for (ExecutableElement element : signatures) { | |
801 ifStarted = builder.startIf(ifStarted); | |
802 builder.string("arguments.length == " + element.getParameters().size()); | |
803 | |
804 int index = 0; | |
805 for (VariableElement param : element.getParameters()) { | |
806 builder.string(" && "); | |
807 if (!param.asType().getKind().isPrimitive()) { | |
808 builder.string("(arguments[" + index + "] == null || "); | |
809 } | |
810 builder.string("arguments[" + index + "] instanceof "); | |
811 builder.type(Utils.boxType(getContext(), param.asType())); | |
812 if (!param.asType().getKind().isPrimitive()) { | |
813 builder.string(")"); | |
814 } | |
815 index++; | |
816 } | |
817 builder.end(); | |
818 builder.startBlock(); | |
819 | |
820 builder.startReturn().startCall("create"); | |
821 index = 0; | |
822 for (VariableElement param : element.getParameters()) { | |
823 builder.startGroup(); | |
824 builder.string("(").type(param.asType()).string(") "); | |
825 builder.string("arguments[").string(String.valueOf(index)).string("]"); | |
826 builder.end(); | |
827 index++; | |
828 } | |
829 builder.end().end(); | |
830 | |
831 builder.end(); // block | |
832 } | |
833 | |
834 builder.startElseBlock(); | |
835 builder.startThrow().startNew(getContext().getType(IllegalArgumentException.class)); | |
836 builder.doubleQuote("Invalid create signature."); | |
837 builder.end().end(); | |
838 builder.end(); // else block | |
839 return method; | |
840 } | |
841 | |
842 private CodeExecutableElement createCreateNodeGenericMethod(NodeData node) { | |
843 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), node.getNodeType(), "createNodeGeneric"); | |
844 CodeVariableElement nodeParam = new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME); | |
845 method.addParameter(nodeParam); | |
846 | |
847 CodeTreeBuilder builder = method.createBuilder(); | |
848 if (!node.needsRewrites(getContext())) { | |
849 builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).doubleQuote("No specialized version.").end().end(); | |
850 } else { | |
851 builder.startReturn().startCall("createGeneric"); | |
852 builder.string(THIS_NODE_LOCAL_VAR_NAME); | |
853 builder.end().end(); | |
854 } | |
855 return method; | |
856 } | |
857 | |
858 private ExecutableElement createGetInstanceMethod(NodeData node, Modifier visibility) { | |
859 TypeElement nodeFactoryType = Utils.fromTypeMirror(getContext().getType(NodeFactory.class)); | |
860 TypeMirror returnType = Utils.getDeclaredType(nodeFactoryType, node.getNodeType()); | |
861 | |
862 CodeExecutableElement method = new CodeExecutableElement(modifiers(), returnType, "getInstance"); | |
863 if (visibility != null) { | |
864 method.getModifiers().add(visibility); | |
865 } | |
866 method.getModifiers().add(Modifier.STATIC); | |
867 | |
868 String varName = instanceVarName(node); | |
869 | |
870 CodeTreeBuilder builder = method.createBuilder(); | |
871 builder.startIf(); | |
872 builder.string(varName).string(" == null"); | |
873 builder.end().startBlock(); | |
874 | |
875 builder.startStatement(); | |
876 builder.string(varName); | |
877 builder.string(" = "); | |
878 builder.startNew(factoryClassName(node)).end(); | |
879 builder.end(); | |
880 | |
881 builder.end(); | |
882 builder.startReturn().string(varName).end(); | |
883 return method; | |
884 } | |
885 | |
886 private String instanceVarName(NodeData node) { | |
887 if (node.getParent() != null) { | |
888 return Utils.firstLetterLowerCase(factoryClassName(node)) + "Instance"; | |
889 } else { | |
890 return "instance"; | |
891 } | |
892 } | |
893 | |
894 private CodeVariableElement createInstanceConstant(NodeData node, TypeMirror factoryType) { | |
895 String varName = instanceVarName(node); | |
896 CodeVariableElement var = new CodeVariableElement(modifiers(), factoryType, varName); | |
897 var.getModifiers().add(Modifier.PRIVATE); | |
898 var.getModifiers().add(Modifier.STATIC); | |
899 return var; | |
900 } | |
901 | |
902 private ExecutableElement createGetFactories(NodeData node) { | |
903 List<NodeData> children = node.getNodeDeclaringChildren(); | |
904 if (node.needsFactory()) { | |
905 children.add(node); | |
906 } | |
907 | |
908 List<TypeMirror> nodeTypesList = new ArrayList<>(); | |
909 TypeMirror prev = null; | |
910 boolean allSame = true; | |
911 for (NodeData child : children) { | |
912 nodeTypesList.add(child.getNodeType()); | |
913 if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) { | |
914 allSame = false; | |
915 } | |
916 prev = child.getNodeType(); | |
917 } | |
918 TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); | |
919 | |
920 Types types = getContext().getEnvironment().getTypeUtils(); | |
921 TypeMirror factoryType = getContext().getType(NodeFactory.class); | |
922 TypeMirror baseType; | |
923 if (allSame) { | |
924 baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); | |
925 } else { | |
926 baseType = Utils.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); | |
927 } | |
928 TypeMirror listType = Utils.getDeclaredType(Utils.fromTypeMirror(getContext().getType(List.class)), baseType); | |
929 | |
930 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), listType, "getFactories"); | |
931 | |
932 CodeTreeBuilder builder = method.createBuilder(); | |
933 builder.startReturn(); | |
934 builder.startStaticCall(getContext().getType(Arrays.class), "asList"); | |
935 | |
936 for (NodeData child : children) { | |
937 builder.startGroup(); | |
938 NodeData childNode = child; | |
939 List<NodeData> factories = new ArrayList<>(); | |
940 while (childNode.getParent() != null) { | |
941 factories.add(childNode); | |
942 childNode = childNode.getParent(); | |
943 } | |
944 Collections.reverse(factories); | |
945 for (NodeData nodeData : factories) { | |
946 builder.string(factoryClassName(nodeData)).string("."); | |
947 } | |
948 builder.string("getInstance()"); | |
949 builder.end(); | |
950 } | |
951 builder.end(); | |
952 builder.end(); | |
953 return method; | |
954 } | |
955 | |
956 private void createFactoryMethods(NodeData node, CodeTypeElement clazz, Modifier createVisibility) { | |
957 List<ExecutableElement> constructors = findUserConstructors(generatedNode.asType()); | |
958 for (ExecutableElement constructor : constructors) { | |
959 clazz.add(createCreateMethod(node, createVisibility, constructor)); | |
960 } | |
961 } | |
962 | |
963 private CodeExecutableElement createCreateMethod(NodeData node, Modifier visibility, ExecutableElement constructor) { | |
964 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), constructor); | |
965 method.setSimpleName(CodeNames.of("create")); | |
966 method.getModifiers().clear(); | |
967 if (visibility != null) { | |
968 method.getModifiers().add(visibility); | |
969 } | |
970 method.getModifiers().add(Modifier.STATIC); | |
971 method.setReturnType(node.getNodeType()); | |
972 | |
973 CodeTreeBuilder body = method.createBuilder(); | |
974 body.startReturn(); | |
975 if (node.getSpecializations().isEmpty()) { | |
976 body.nullLiteral(); | |
977 } else { | |
978 body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0))); | |
979 for (VariableElement var : method.getParameters()) { | |
980 body.string(var.getSimpleName().toString()); | |
981 } | |
982 body.end(); | |
983 } | |
984 body.end(); | |
985 return method; | |
986 } | |
987 | |
988 private CodeExecutableElement createCreateGenericMethod(NodeData node, Modifier visibility) { | |
989 CodeExecutableElement method = new CodeExecutableElement(modifiers(), node.getNodeType(), "createGeneric"); | |
990 if (visibility != null) { | |
991 method.getModifiers().add(visibility); | |
992 } | |
993 method.getModifiers().add(Modifier.STATIC); | |
994 method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); | |
995 | |
996 CodeTreeBuilder body = method.createBuilder(); | |
997 | |
998 SpecializationData found = null; | |
999 List<SpecializationData> specializations = node.getSpecializations(); | |
1000 for (int i = 0; i < specializations.size(); i++) { | |
1001 if (specializations.get(i).isReachable()) { | |
1002 found = specializations.get(i); | |
1003 } | |
1004 } | |
1005 | |
1006 if (found == null) { | |
1007 body.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); | |
1008 } else { | |
1009 body.startReturn().startNew(nodeSpecializationClassName(found)).startGroup().cast(baseClassName(node)).string(THIS_NODE_LOCAL_VAR_NAME).end().end().end(); | |
1010 } | |
1011 return method; | |
1012 } | |
1013 } | |
1014 | |
1015 private class NodeBaseFactory extends ClassElementFactory<SpecializationData> { | |
1016 | |
1017 public NodeBaseFactory(ProcessorContext context) { | |
1018 super(context); | |
1019 } | |
1020 | |
1021 @Override | |
1022 protected CodeTypeElement create(SpecializationData specialization) { | |
1023 NodeData node = specialization.getNode(); | |
1024 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, ABSTRACT, STATIC), baseClassName(node), node.getNodeType(), false); | |
1025 | |
1026 for (NodeChildData child : node.getChildren()) { | |
1027 clazz.add(createChildField(child)); | |
1028 | |
1029 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { | |
1030 ExecutableElement getter = (ExecutableElement) child.getAccessElement(); | |
1031 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); | |
1032 method.getModifiers().remove(Modifier.ABSTRACT); | |
1033 method.createBuilder().startReturn().string("this.").string(child.getName()).end(); | |
1034 clazz.add(method); | |
1035 } | |
1036 } | |
1037 | |
1038 for (String assumption : node.getAssumptions()) { | |
1039 clazz.add(createAssumptionField(assumption)); | |
1040 } | |
1041 | |
1042 createConstructors(node, clazz); | |
1043 | |
1044 return clazz; | |
1045 } | |
1046 | |
1047 protected String typeGetterName(ActualParameter parameter) { | |
1048 return "get" + Utils.firstLetterUpperCase(parameter.getLocalName()) + "Type"; | |
1049 } | |
1050 | |
1051 @Override | |
1052 protected void createChildren(SpecializationData specialization) { | |
1053 NodeData node = specialization.getNode(); | |
1054 CodeTypeElement clazz = getElement(); | |
1055 | |
1056 if (node.needsRewrites(context)) { | |
1057 | |
1058 if (node.getPolymorphicDepth() > 1) { | |
1059 | |
1060 CodeVariableElement var = new CodeVariableElement(modifiers(PROTECTED), clazz.asType(), "next0"); | |
1061 var.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); | |
1062 clazz.add(var); | |
1063 | |
1064 CodeExecutableElement setter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(void.class), "setNext0"); | |
1065 setter.getParameters().add(new CodeVariableElement(clazz.asType(), "next0")); | |
1066 CodeTreeBuilder builder = setter.createBuilder(); | |
1067 builder.statement("this.next0 = adoptChild(next0)"); | |
1068 clazz.add(setter); | |
1069 | |
1070 createTypeGetters(clazz, node.getGenericSpecialization()); | |
1071 | |
1072 clazz.add(createCreateSpecialization(node)); | |
1073 | |
1074 CodeExecutableElement genericCachedExecute = null; | |
1075 for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { | |
1076 CodeExecutableElement cachedExecute = createCachedExecute(node, polymorph, genericCachedExecute); | |
1077 clazz.add(cachedExecute); | |
1078 if (genericCachedExecute == null) { | |
1079 genericCachedExecute = cachedExecute; | |
1080 } | |
1081 } | |
1082 } | |
1083 | |
1084 clazz.add(createGenericExecuteAndSpecialize(node)); | |
1085 clazz.add(createInfoMessage(node)); | |
1086 } | |
1087 | |
1088 if (node.getGenericSpecialization() != null && node.getGenericSpecialization().isReachable()) { | |
1089 clazz.add(createGenericExecute(node)); | |
1090 } | |
1091 } | |
1092 | |
1093 private Element createInfoMessage(NodeData node) { | |
1094 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), getContext().getType(String.class), "createInfo0"); | |
1095 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "message")); | |
1096 addInternalValueParameters(method, node.getGenericSpecialization(), false, false); | |
1097 | |
1098 CodeTreeBuilder builder = method.createBuilder(); | |
1099 builder.startStatement().string("StringBuilder builder = new StringBuilder(message)").end(); | |
1100 builder.startStatement().startCall("builder", "append").doubleQuote(" (").end().end(); | |
1101 | |
1102 String sep = null; | |
1103 for (ActualParameter parameter : node.getGenericSpecialization().getParameters()) { | |
1104 if (!parameter.getSpecification().isSignature()) { | |
1105 continue; | |
1106 } | |
1107 | |
1108 builder.startStatement(); | |
1109 builder.string("builder"); | |
1110 if (sep != null) { | |
1111 builder.startCall(".append").doubleQuote(sep).end(); | |
1112 } | |
1113 builder.startCall(".append").doubleQuote(parameter.getLocalName()).end(); | |
1114 builder.startCall(".append").doubleQuote(" = ").end(); | |
1115 builder.startCall(".append").string(parameter.getLocalName()).end(); | |
1116 builder.end(); | |
1117 | |
1118 if (!Utils.isPrimitive(parameter.getType())) { | |
1119 builder.startIf().string(parameter.getLocalName() + " != null").end(); | |
1120 builder.startBlock(); | |
1121 } | |
1122 builder.startStatement(); | |
1123 if (Utils.isPrimitive(parameter.getType())) { | |
1124 builder.startCall("builder.append").doubleQuote(" (" + Utils.getSimpleName(parameter.getType()) + ")").end(); | |
1125 } else { | |
1126 builder.startCall("builder.append").doubleQuote(" (").end(); | |
1127 builder.startCall(".append").string(parameter.getLocalName() + ".getClass().getSimpleName()").end(); | |
1128 builder.startCall(".append").doubleQuote(")").end(); | |
1129 } | |
1130 builder.end(); | |
1131 if (!Utils.isPrimitive(parameter.getType())) { | |
1132 builder.end(); | |
1133 } | |
1134 | |
1135 sep = ", "; | |
1136 } | |
1137 | |
1138 builder.startStatement().startCall("builder", "append").doubleQuote(")").end().end(); | |
1139 | |
1140 builder.startReturn().string("builder.toString()").end(); | |
1141 | |
1142 return method; | |
1143 } | |
1144 | |
1145 protected void createTypeGetters(CodeTypeElement clazz, SpecializationData specialization) { | |
1146 for (ActualParameter parameter : specialization.getReturnTypeAndParameters()) { | |
1147 if (!parameter.getSpecification().isSignature()) { | |
1148 continue; | |
1149 } | |
1150 CodeExecutableElement typeGetter = new CodeExecutableElement(modifiers(PROTECTED), context.getType(Class.class), typeGetterName(parameter)); | |
1151 CodeTreeBuilder builder = typeGetter.createBuilder(); | |
1152 builder.startReturn().typeLiteral(parameter.getType()).end(); | |
1153 clazz.add(typeGetter); | |
1154 } | |
1155 } | |
1156 | |
1157 private CodeExecutableElement createCachedExecute(NodeData node, SpecializationData polymorph, CodeExecutableElement genericPolymorphMethod) { | |
1158 int index = node.getPolymorphicSpecializations().indexOf(polymorph); | |
1159 assert index != -1; | |
1160 boolean generic = index == 0; | |
1161 | |
1162 String name = "executeCached" + index; | |
1163 CodeExecutableElement cachedExecute = new CodeExecutableElement(modifiers(PROTECTED), polymorph.getReturnType().getType(), name); | |
1164 addInternalValueParameters(cachedExecute, polymorph, true, true); | |
1165 | |
1166 if (generic) { | |
1167 cachedExecute.getModifiers().add(ABSTRACT); | |
1168 } else { | |
1169 SpecializationData genericPolymorph = node.getPolymorphicSpecializations().get(0); | |
1170 CodeTreeBuilder builder = cachedExecute.createBuilder(); | |
1171 ExecutableTypeData genericExecutable = new ExecutableTypeData(genericPolymorph, genericPolymorphMethod, node.getTypeSystem(), genericPolymorph.getReturnType().getTypeSystemType()); | |
1172 ExecutableTypeData specificExecutable = new ExecutableTypeData(polymorph, cachedExecute, node.getTypeSystem(), polymorph.getReturnType().getTypeSystemType()); | |
1173 builder.tree(createCastingExecute(builder, polymorph, specificExecutable, genericExecutable)); | |
1174 } | |
1175 | |
1176 return cachedExecute; | |
1177 | |
1178 } | |
1179 | |
1180 private CodeExecutableElement createCreateSpecialization(NodeData node) { | |
1181 CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getElement().asType(), "createSpezialization0"); | |
1182 method.getParameters().add(new CodeVariableElement(context.getType(Class.class), "clazz")); | |
1183 CodeTreeBuilder builder = method.createBuilder(); | |
1184 | |
1185 builder.startStatement().type(getElement().asType()).string(" node").end(); | |
1186 | |
1187 boolean elseIf = false; | |
1188 for (SpecializationData specialization : node.getSpecializations()) { | |
1189 if (specialization.isGeneric() || specialization.isUninitialized()) { | |
1190 continue; | |
1191 } | |
1192 | |
1193 elseIf = builder.startIf(elseIf); | |
1194 builder.startGroup().string("clazz == ").string(nodeSpecializationClassName(specialization)).string(".class").end(); | |
1195 builder.end(); | |
1196 builder.startBlock(); | |
1197 builder.startStatement(); | |
1198 builder.string("node = "); | |
1199 builder.startNew(nodeSpecializationClassName(specialization)).string("this").end(); | |
1200 builder.end(); | |
1201 builder.end(); | |
1202 } | |
1203 | |
1204 builder.startElseBlock(); | |
1205 builder.startThrow().startNew(context.getType(AssertionError.class)).end().end(); | |
1206 builder.end(); | |
1207 | |
1208 builder.startStatement().startCall("node", "setNext0"); | |
1209 builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); | |
1210 builder.end().end(); | |
1211 | |
1212 builder.startReturn().string("node").end(); | |
1213 | |
1214 return method; | |
1215 } | |
1216 | |
1217 private void createConstructors(NodeData node, CodeTypeElement clazz) { | |
1218 List<ExecutableElement> constructors = findUserConstructors(node.getNodeType()); | |
1219 if (constructors.isEmpty()) { | |
1220 clazz.add(createUserConstructor(clazz, null)); | |
1221 } else { | |
1222 for (ExecutableElement constructor : constructors) { | |
1223 clazz.add(createUserConstructor(clazz, constructor)); | |
1224 } | |
1225 } | |
1226 if (node.needsRewrites(getContext())) { | |
1227 clazz.add(createCopyConstructor(clazz, findCopyConstructor(node.getNodeType()))); | |
1228 } | |
1229 } | |
1230 | |
1231 private CodeExecutableElement createUserConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
1232 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
1233 CodeTreeBuilder builder = method.createBuilder(); | |
1234 | |
1235 NodeData node = getModel().getNode(); | |
1236 | |
1237 if (superConstructor != null) { | |
1238 for (VariableElement param : superConstructor.getParameters()) { | |
1239 method.getParameters().add(CodeVariableElement.clone(param)); | |
1240 } | |
1241 } | |
1242 | |
1243 for (VariableElement var : type.getFields()) { | |
1244 NodeChildData child = node.findChild(var.getSimpleName().toString()); | |
1245 if (child != null) { | |
1246 method.getParameters().add(new CodeVariableElement(child.getOriginalType(), child.getName())); | |
1247 } else { | |
1248 method.getParameters().add(new CodeVariableElement(var.asType(), var.getSimpleName().toString())); | |
1249 } | |
1250 } | |
1251 | |
1252 if (superConstructor != null) { | |
1253 builder.startStatement().startSuperCall(); | |
1254 for (VariableElement param : superConstructor.getParameters()) { | |
1255 builder.string(param.getSimpleName().toString()); | |
1256 } | |
1257 builder.end().end(); | |
1258 } | |
1259 | |
1260 for (VariableElement var : type.getFields()) { | |
1261 builder.startStatement(); | |
1262 String fieldName = var.getSimpleName().toString(); | |
1263 | |
1264 CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString()); | |
1265 builder.string("this.").string(var.getSimpleName().toString()); | |
1266 | |
1267 NodeChildData child = node.findChild(fieldName); | |
1268 if (child != null) { | |
1269 CreateCastData createCast = node.findCast(child.getName()); | |
1270 if (createCast != null) { | |
1271 fieldInit = createTemplateMethodCall(builder, null, node.getGenericSpecialization(), createCast, null, child.getName()); | |
1272 } | |
1273 } | |
1274 | |
1275 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
1276 builder.string(" = adoptChild(").tree(fieldInit).string(")"); | |
1277 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
1278 builder.string(" = adoptChildren(").tree(fieldInit).string(")"); | |
1279 } else { | |
1280 builder.string(" = ").tree(fieldInit); | |
1281 } | |
1282 builder.end(); | |
1283 } | |
1284 return method; | |
1285 } | |
1286 | |
1287 private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { | |
1288 CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); | |
1289 CodeTreeBuilder builder = method.createBuilder(); | |
1290 if (!(superConstructor == null && type.getFields().isEmpty())) { | |
1291 method.getParameters().add(new CodeVariableElement(type.asType(), "copy")); | |
1292 } | |
1293 | |
1294 if (superConstructor != null) { | |
1295 builder.startStatement().startSuperCall().string("copy").end().end(); | |
1296 } | |
1297 | |
1298 for (VariableElement var : type.getFields()) { | |
1299 builder.startStatement(); | |
1300 String varName = var.getSimpleName().toString(); | |
1301 builder.string("this.").string(varName); | |
1302 if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { | |
1303 builder.string(" = adoptChild(copy.").string(varName).string(")"); | |
1304 } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { | |
1305 builder.string(" = adoptChildren(copy.").string(varName).string(")"); | |
1306 } else { | |
1307 builder.string(" = copy.").string(varName); | |
1308 } | |
1309 builder.end(); | |
1310 } | |
1311 if (getModel().getNode().getPolymorphicDepth() > 1) { | |
1312 builder.statement("this.next0 = adoptChild(copy.next0)"); | |
1313 } | |
1314 | |
1315 return method; | |
1316 } | |
1317 | |
1318 private CodeVariableElement createAssumptionField(String assumption) { | |
1319 CodeVariableElement var = new CodeVariableElement(getContext().getTruffleTypes().getAssumption(), assumption); | |
1320 var.getModifiers().add(Modifier.FINAL); | |
1321 return var; | |
1322 } | |
1323 | |
1324 private CodeVariableElement createChildField(NodeChildData child) { | |
1325 CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); | |
1326 var.getModifiers().add(Modifier.PROTECTED); | |
1327 | |
1328 DeclaredType annotationType; | |
1329 if (child.getCardinality() == Cardinality.MANY) { | |
1330 annotationType = getContext().getTruffleTypes().getChildrenAnnotation(); | |
1331 } else { | |
1332 annotationType = getContext().getTruffleTypes().getChildAnnotation(); | |
1333 } | |
1334 | |
1335 var.getAnnotationMirrors().add(new CodeAnnotationMirror(annotationType)); | |
1336 return var; | |
1337 } | |
1338 | |
1339 private CodeExecutableElement createGenericExecuteAndSpecialize(NodeData node) { | |
1340 | |
1341 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); | |
1342 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_SPECIALIZE_NAME); | |
1343 method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); | |
1344 addInternalValueParameters(method, node.getGenericSpecialization(), true, false); | |
1345 method.addParameter(new CodeVariableElement(getContext().getType(String.class), "reason")); | |
1346 | |
1347 CodeTreeBuilder builder = method.createBuilder(); | |
1348 builder.startStatement(); | |
1349 builder.startStaticCall(getContext().getTruffleTypes().getCompilerAsserts(), "neverPartOfCompilation").end(); | |
1350 builder.end(); | |
1351 | |
1352 emitSpecializationListeners(builder, node); | |
1353 builder.defaultDeclaration(node.getGenericSpecialization().getReturnType().getTypeSystemType().getPrimitiveType(), "result"); | |
1354 | |
1355 builder.defaultDeclaration(getContext().getType(Class.class), "resultClass"); | |
1356 | |
1357 builder.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); | |
1358 | |
1359 builder.startStatement().string("String message = ").startCall("createInfo0").string("reason"); | |
1360 addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, false, true); | |
1361 builder.end().end(); | |
1362 | |
1363 String prefix = null; | |
1364 | |
1365 List<SpecializationData> specializations = node.getSpecializations(); | |
1366 | |
1367 for (SpecializationData current : specializations) { | |
1368 if (current.isUninitialized() || !current.isReachable()) { | |
1369 continue; | |
1370 } | |
1371 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1372 | |
1373 execute.tree(createGenericInvokeAndSpecialize(builder, node.getGenericSpecialization(), current)); | |
1374 | |
1375 if (!current.isGeneric()) { | |
1376 builder.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(current)).string(".class)").end(); | |
1377 } | |
1378 | |
1379 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); | |
1380 } | |
1381 | |
1382 for (SpecializationData current : specializations) { | |
1383 if (current.isUninitialized() || current.isReachable()) { | |
1384 continue; | |
1385 } | |
1386 builder.string("// unreachable ").string(current.getId()).newLine(); | |
1387 } | |
1388 | |
1389 return method; | |
1390 } | |
1391 | |
1392 private CodeExecutableElement createGenericExecute(NodeData node) { | |
1393 TypeMirror genericReturnType = node.getGenericSpecialization().getReturnType().getType(); | |
1394 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), genericReturnType, EXECUTE_GENERIC_NAME); | |
1395 addInternalValueParameters(method, node.getGenericSpecialization(), true, false); | |
1396 CodeTreeBuilder builder = method.createBuilder(); | |
1397 | |
1398 String prefix = null; | |
1399 List<SpecializationData> specializations = node.getSpecializations(); | |
1400 | |
1401 for (SpecializationData current : specializations) { | |
1402 if (current.isUninitialized() || !current.isReachable()) { | |
1403 continue; | |
1404 } | |
1405 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1406 execute.tree(createGenericInvoke(builder, node.getGenericSpecialization(), current)); | |
1407 builder.tree(createGuardAndCast(builder, prefix, current.getNode().getGenericSpecialization(), current, true, execute.getRoot(), null, true, false)); | |
1408 } | |
1409 | |
1410 for (SpecializationData current : specializations) { | |
1411 if (current.isUninitialized() || current.isReachable()) { | |
1412 continue; | |
1413 } | |
1414 builder.string("// unreachable ").string(current.getId()).newLine(); | |
1415 } | |
1416 | |
1417 return method; | |
1418 } | |
1419 | |
1420 protected CodeTree createGenericInvoke(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { | |
1421 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1422 | |
1423 if (current.getMethod() == null) { | |
1424 emitEncounteredSynthetic(builder, current); | |
1425 } else { | |
1426 builder.startReturn().tree(createTemplateMethodCall(builder, null, source, current, null)).end(); | |
1427 } | |
1428 | |
1429 return encloseThrowsWithFallThrough(current, builder.getRoot()); | |
1430 } | |
1431 | |
1432 protected CodeTree createGenericInvokeAndSpecialize(CodeTreeBuilder parent, SpecializationData source, SpecializationData current) { | |
1433 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1434 | |
1435 NodeData node = current.getNode(); | |
1436 | |
1437 builder.startIf().string("resultClass == null").end().startBlock(); | |
1438 if (current.getMethod() != null) { | |
1439 CodeTree executeCall = createTemplateMethodCall(builder, null, source, current, null); | |
1440 if (current.getReturnType().getTypeSystemType().isVoid()) { | |
1441 builder.statement(executeCall); | |
1442 } else { | |
1443 builder.startStatement().string("result = ").tree(executeCall).end(); | |
1444 } | |
1445 builder.startStatement(); | |
1446 builder.string("resultClass = ").string(nodeSpecializationClassName(current)).string(".class"); | |
1447 builder.end(); | |
1448 } else { | |
1449 emitEncounteredSynthetic(builder, current); | |
1450 } | |
1451 builder.end(); | |
1452 | |
1453 boolean ifAllowed = current.hasRewrite(getContext()); | |
1454 if (ifAllowed) { | |
1455 builder.startIf().string("allowed").end().startBlock(); | |
1456 } | |
1457 | |
1458 if (!current.isGeneric() || node.getPolymorphicDepth() <= 1) { | |
1459 // generic rewrite | |
1460 builder.tree(createRewriteGeneric(builder, current)); | |
1461 } else { | |
1462 boolean rewriteableToGeneric = node.getGenericSpecialization().getMethod() != null && node.getGenericSpecialization().isReachable(); | |
1463 if (rewriteableToGeneric) { | |
1464 builder.startIf().string("resultClass == ").string(nodeSpecializationClassName(node.getGenericSpecialization())).string(".class").end(); | |
1465 builder.startBlock(); | |
1466 | |
1467 boolean maybePolymorphic = node.getPolymorphicDepth() > 1; | |
1468 if (maybePolymorphic) { | |
1469 builder.startIf().string("next0 == null").end(); | |
1470 builder.startBlock(); | |
1471 } | |
1472 builder.tree(createRewriteGeneric(builder, current)); | |
1473 if (maybePolymorphic) { | |
1474 builder.end().startElseBlock(); | |
1475 builder.statement("Node searchNode = super.getParent()"); | |
1476 builder.startWhile().string("searchNode != null").end(); | |
1477 builder.startBlock(); | |
1478 builder.statement("searchNode = searchNode.getParent()"); | |
1479 builder.startIf().instanceOf("searchNode", nodePolymorphicClassName(node, node.getPolymorphicSpecializations().get(0))).end(); | |
1480 builder.startBlock().breakStatement().end(); | |
1481 builder.end(); | |
1482 builder.startStatement().startCall("searchNode", "replace"); | |
1483 builder.startGroup().startNew(nodeSpecializationClassName(current)).startGroup().cast(baseClassName(node)).string("searchNode").end().end().end(); | |
1484 builder.string("message"); | |
1485 builder.end().end().end(); | |
1486 } | |
1487 | |
1488 builder.end().startElseBlock(); | |
1489 } | |
1490 | |
1491 // polymorphic rewrite | |
1492 builder.tree(createRewritePolymorphic(builder, node)); | |
1493 | |
1494 if (rewriteableToGeneric) { | |
1495 builder.end(); | |
1496 } | |
1497 } | |
1498 | |
1499 if (current.getReturnType().getTypeSystemType().isVoid()) { | |
1500 builder.returnStatement(); | |
1501 } else { | |
1502 builder.startReturn().string("result").end(); | |
1503 } | |
1504 if (ifAllowed) { | |
1505 builder.end(); | |
1506 } | |
1507 | |
1508 return encloseThrowsWithFallThrough(current, builder.getRoot()); | |
1509 } | |
1510 | |
1511 private CodeTree encloseThrowsWithFallThrough(SpecializationData current, CodeTree tree) { | |
1512 if (current.getExceptions().isEmpty()) { | |
1513 return tree; | |
1514 } | |
1515 CodeTreeBuilder builder = new CodeTreeBuilder(null); | |
1516 | |
1517 builder.startTryBlock(); | |
1518 builder.tree(tree); | |
1519 for (SpecializationThrowsData exception : current.getExceptions()) { | |
1520 builder.end().startCatchBlock(exception.getJavaClass(), "rewriteEx"); | |
1521 builder.string("// fall through").newLine(); | |
1522 } | |
1523 builder.end(); | |
1524 | |
1525 return builder.getRoot(); | |
1526 } | |
1527 | |
1528 private CodeTree createRewriteGeneric(CodeTreeBuilder parent, SpecializationData current) { | |
1529 CodeTreeBuilder builder = parent.create(); | |
1530 builder.startStatement().startCall("super", "replace"); | |
1531 builder.startGroup().startNew(nodeSpecializationClassName(current)).string("this").end().end(); | |
1532 builder.string("message"); | |
1533 builder.end().end(); | |
1534 return builder.getRoot(); | |
1535 } | |
1536 | |
1537 private CodeTree createRewritePolymorphic(CodeTreeBuilder parent, NodeData node) { | |
1538 CodeTreeBuilder builder = parent.create(); | |
1539 builder.startStatement(); | |
1540 builder.string(nodePolymorphicClassName(node, null)); | |
1541 builder.string(" polymorphic = "); | |
1542 builder.startNew(nodePolymorphicClassName(node, null)).string("this").end(); | |
1543 builder.end(); | |
1544 for (NodeChildData child : node.getChildren()) { | |
1545 builder.startStatement().string("this.").string(child.getName()).string(" = null").end(); | |
1546 } | |
1547 builder.startStatement().startCall("super", "replace"); | |
1548 builder.string("polymorphic"); | |
1549 builder.string("message"); | |
1550 builder.end().end(); | |
1551 | |
1552 builder.statement("polymorphic.setNext0(this)"); | |
1553 builder.statement("setNext0(createSpezialization0(resultClass))"); | |
1554 | |
1555 builder.statement("polymorphic.optimizeTypes()"); | |
1556 return builder.getRoot(); | |
1557 } | |
1558 | |
1559 private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { | |
1560 for (TemplateMethod listener : node.getSpecializationListeners()) { | |
1561 builder.startStatement(); | |
1562 builder.tree(createTemplateMethodCall(builder, null, listener, listener, null)); | |
1563 builder.end(); // statement | |
1564 } | |
1565 } | |
1566 | |
1567 protected CodeTree createCastingExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable, ExecutableTypeData castExecutable) { | |
1568 TypeData type = executable.getType(); | |
1569 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1570 NodeData node = specialization.getNode(); | |
1571 | |
1572 ExecutableTypeData castedType = node.findExecutableType(type, 0); | |
1573 TypeData primaryType = castExecutable.getType(); | |
1574 | |
1575 boolean needsTry = castExecutable.hasUnexpectedValue(getContext()); | |
1576 boolean returnVoid = type.isVoid(); | |
1577 | |
1578 List<ActualParameter> executeParameters = new ArrayList<>(); | |
1579 for (ActualParameter sourceParameter : executable.getParameters()) { | |
1580 if (!sourceParameter.getSpecification().isSignature()) { | |
1581 continue; | |
1582 } | |
1583 | |
1584 ActualParameter targetParameter = castExecutable.findParameter(sourceParameter.getLocalName()); | |
1585 if (targetParameter != null) { | |
1586 executeParameters.add(targetParameter); | |
1587 } | |
1588 } | |
1589 | |
1590 builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true)); | |
1591 | |
1592 CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null); | |
1593 if (needsTry) { | |
1594 if (!returnVoid) { | |
1595 builder.declaration(primaryType.getPrimitiveType(), "value"); | |
1596 } | |
1597 builder.startTryBlock(); | |
1598 | |
1599 if (returnVoid) { | |
1600 builder.statement(primaryExecuteCall); | |
1601 } else { | |
1602 builder.startStatement(); | |
1603 builder.string("value = "); | |
1604 builder.tree(primaryExecuteCall); | |
1605 builder.end(); | |
1606 } | |
1607 | |
1608 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); | |
1609 if (returnVoid) { | |
1610 builder.string("// ignore").newLine(); | |
1611 } else { | |
1612 builder.startReturn(); | |
1613 builder.tree(createExpectExecutableType(node, specialization.getNode().getTypeSystem().getGenericTypeData(), castedType, CodeTreeBuilder.singleString("ex.getResult()"))); | |
1614 builder.end(); | |
1615 } | |
1616 builder.end(); | |
1617 | |
1618 if (!returnVoid) { | |
1619 builder.startReturn(); | |
1620 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), executable, CodeTreeBuilder.singleString("value"))); | |
1621 builder.end(); | |
1622 } | |
1623 } else { | |
1624 if (returnVoid) { | |
1625 builder.statement(primaryExecuteCall); | |
1626 } else { | |
1627 builder.startReturn(); | |
1628 builder.tree(createExpectExecutableType(node, castExecutable.getReturnType().getTypeSystemType(), executable, primaryExecuteCall)); | |
1629 builder.end(); | |
1630 } | |
1631 } | |
1632 | |
1633 return builder.getRoot(); | |
1634 } | |
1635 | |
1636 protected CodeTree createExpectExecutableType(NodeData node, TypeData sourceType, ExecutableTypeData castedType, CodeTree value) { | |
1637 boolean hasUnexpected = castedType.hasUnexpectedValue(getContext()); | |
1638 return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); | |
1639 } | |
1640 | |
1641 protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { | |
1642 if (targetType == null) { | |
1643 return value; | |
1644 } else if (!sourceType.needsCastTo(getContext(), targetType)) { | |
1645 return value; | |
1646 } | |
1647 | |
1648 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1649 String targetMethodName; | |
1650 if (expect) { | |
1651 targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); | |
1652 } else { | |
1653 targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); | |
1654 } | |
1655 startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); | |
1656 | |
1657 builder.tree(value); | |
1658 builder.end().end(); | |
1659 return builder.getRoot(); | |
1660 } | |
1661 | |
1662 protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters, | |
1663 ActualParameter unexpectedParameter, boolean cast) { | |
1664 NodeData sourceNode = specialization.getNode(); | |
1665 | |
1666 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1667 | |
1668 for (ActualParameter targetParameter : targetParameters) { | |
1669 NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName()); | |
1670 if (!targetParameter.getSpecification().isSignature()) { | |
1671 continue; | |
1672 } | |
1673 | |
1674 TypeData targetType = targetParameter.getTypeSystemType(); | |
1675 ExecutableTypeData targetExecutable = null; | |
1676 if (field != null) { | |
1677 targetExecutable = field.findExecutableType(getContext(), targetType); | |
1678 } | |
1679 | |
1680 ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); | |
1681 | |
1682 String targetVariableName = valueName(targetParameter); | |
1683 CodeTree executionExpression = null; | |
1684 if ((sourceParameter != null && cast) || sourceParameter != null) { | |
1685 TypeData sourceType = sourceParameter.getTypeSystemType(); | |
1686 if (targetExecutable == null || !sourceType.needsCastTo(getContext(), targetType)) { | |
1687 if (field != null && field.isShortCircuit() && sourceParameter != null) { | |
1688 builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); | |
1689 } | |
1690 builder.startStatement(); | |
1691 builder.type(targetParameter.getType()).string(" "); | |
1692 builder.string(valueName(targetParameter)).string(" = "); | |
1693 builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); | |
1694 builder.end(); | |
1695 continue; | |
1696 } else { | |
1697 CodeTree valueTree = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); | |
1698 executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, valueTree); | |
1699 } | |
1700 } else if (sourceParameter == null) { | |
1701 executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); | |
1702 } | |
1703 | |
1704 if (executionExpression != null) { | |
1705 CodeTreeVariable executionVar = new CodeTreeVariable(); | |
1706 CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, specialization, targetParameter, unexpectedParameter); | |
1707 CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, | |
1708 shortCircuitTree != executionVar); | |
1709 | |
1710 executionVar.set(unexpectedTree); | |
1711 builder.tree(shortCircuitTree); | |
1712 } | |
1713 } | |
1714 return builder.getRoot(); | |
1715 } | |
1716 | |
1717 private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, | |
1718 ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { | |
1719 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1720 boolean unexpected = targetExecutable.hasUnexpectedValue(getContext()); | |
1721 boolean cast = false; | |
1722 if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) { | |
1723 unexpected = true; | |
1724 cast = true; | |
1725 } | |
1726 | |
1727 if (specialization.isGeneric() && unexpected) { | |
1728 throw new AssertionError("Generic has unexpected parameters. " + specialization.toString()); | |
1729 } | |
1730 | |
1731 builder.startStatement(); | |
1732 | |
1733 if (!shortCircuit) { | |
1734 builder.type(param.getType()).string(" ").string(targetVariableName); | |
1735 } | |
1736 | |
1737 if (unexpected) { | |
1738 if (!shortCircuit) { | |
1739 builder.end(); | |
1740 } | |
1741 builder.startTryBlock(); | |
1742 builder.startStatement(); | |
1743 builder.string(targetVariableName); | |
1744 } else if (shortCircuit) { | |
1745 builder.startStatement(); | |
1746 builder.string(targetVariableName); | |
1747 } | |
1748 builder.string(" = "); | |
1749 if (cast) { | |
1750 builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body)); | |
1751 } else { | |
1752 builder.tree(body); | |
1753 } | |
1754 builder.end(); | |
1755 | |
1756 if (unexpected) { | |
1757 builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); | |
1758 SpecializationData generic = specialization.getNode().getGenericSpecialization(); | |
1759 ActualParameter genericParameter = generic.findParameter(param.getLocalName()); | |
1760 | |
1761 List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); | |
1762 builder.tree(createDeoptimize(builder)); | |
1763 builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); | |
1764 if (specialization.isPolymorphic()) { | |
1765 builder.tree(createReturnOptimizeTypes(builder, specialization, param)); | |
1766 } else { | |
1767 builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization.findNextSpecialization(), param, "Expected " + param.getLocalName() + " instanceof " + | |
1768 Utils.getSimpleName(param.getType()))); | |
1769 } | |
1770 builder.end(); // catch block | |
1771 } | |
1772 | |
1773 return builder.getRoot(); | |
1774 } | |
1775 | |
1776 private CodeTree createReturnOptimizeTypes(CodeTreeBuilder parent, SpecializationData specialization, ActualParameter param) { | |
1777 NodeData node = specialization.getNode(); | |
1778 assert !node.getPolymorphicSpecializations().isEmpty(); | |
1779 SpecializationData generic = node.getPolymorphicSpecializations().get(0); | |
1780 | |
1781 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1782 builder.startReturn(); | |
1783 | |
1784 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
1785 execute.startCall("next0", "executeCached0"); | |
1786 addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true); | |
1787 execute.end(); | |
1788 | |
1789 TypeData sourceType = generic.getReturnType().getTypeSystemType(); | |
1790 TypeData targetType = specialization.getReturnType().getTypeSystemType(); | |
1791 | |
1792 builder.tree(createCastType(node, sourceType, targetType, true, execute.getRoot())); | |
1793 | |
1794 builder.end(); | |
1795 return builder.getRoot(); | |
1796 } | |
1797 | |
1798 private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { | |
1799 TypeData type = sourceParameter.getTypeSystemType(); | |
1800 ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); | |
1801 | |
1802 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1803 if (targetField != null) { | |
1804 Element accessElement = targetField.getAccessElement(); | |
1805 if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { | |
1806 builder.string("this.").string(targetField.getName()); | |
1807 } else if (accessElement.getKind() == ElementKind.FIELD) { | |
1808 builder.string("this.").string(accessElement.getSimpleName().toString()); | |
1809 } else { | |
1810 throw new AssertionError(); | |
1811 } | |
1812 if (sourceParameter.getSpecification().isIndexed()) { | |
1813 builder.string("[" + sourceParameter.getIndex() + "]"); | |
1814 } | |
1815 builder.string("."); | |
1816 } | |
1817 | |
1818 builder.startCall(execType.getMethodName()); | |
1819 | |
1820 int index = 0; | |
1821 for (ActualParameter parameter : execType.getParameters()) { | |
1822 | |
1823 if (!parameter.getSpecification().isSignature()) { | |
1824 builder.string(parameter.getLocalName()); | |
1825 } else { | |
1826 if (index < targetField.getExecuteWith().size()) { | |
1827 NodeChildData child = targetField.getExecuteWith().get(index); | |
1828 | |
1829 ParameterSpec spec = getModel().getSpecification().findParameterSpec(child.getName()); | |
1830 List<ActualParameter> specializationParams = getModel().findParameters(spec); | |
1831 | |
1832 if (specializationParams.isEmpty()) { | |
1833 builder.defaultValue(parameter.getType()); | |
1834 continue; | |
1835 } | |
1836 | |
1837 ActualParameter specializationParam = specializationParams.get(0); | |
1838 | |
1839 TypeData targetType = parameter.getTypeSystemType(); | |
1840 TypeData sourceType = specializationParam.getTypeSystemType(); | |
1841 String localName = specializationParam.getLocalName(); | |
1842 | |
1843 if (unexpectedParameter != null && unexpectedParameter.getLocalName().equals(specializationParam.getLocalName())) { | |
1844 localName = "ex.getResult()"; | |
1845 sourceType = getModel().getNode().getTypeSystem().getGenericTypeData(); | |
1846 } | |
1847 | |
1848 CodeTree value = CodeTreeBuilder.singleString(localName); | |
1849 | |
1850 if (sourceType.needsCastTo(getContext(), targetType)) { | |
1851 value = createCallTypeSystemMethod(getContext(), builder, getModel().getNode(), TypeSystemCodeGenerator.asTypeMethodName(targetType), value); | |
1852 } | |
1853 builder.tree(value); | |
1854 } else { | |
1855 builder.defaultValue(parameter.getType()); | |
1856 } | |
1857 index++; | |
1858 } | |
1859 } | |
1860 | |
1861 builder.end(); | |
1862 | |
1863 return builder.getRoot(); | |
1864 } | |
1865 | |
1866 private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, | |
1867 ActualParameter exceptionParam) { | |
1868 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1869 | |
1870 NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); | |
1871 if (forField == null) { | |
1872 return body; | |
1873 } | |
1874 | |
1875 if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { | |
1876 return body; | |
1877 } | |
1878 | |
1879 ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); | |
1880 | |
1881 builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); | |
1882 | |
1883 builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); | |
1884 builder.startIf().string(shortCircuitParam.getLocalName()).end(); | |
1885 builder.startBlock(); | |
1886 builder.tree(body); | |
1887 builder.end(); | |
1888 | |
1889 return builder.getRoot(); | |
1890 } | |
1891 | |
1892 private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeChildData forField, ActualParameter shortCircuitParam, ActualParameter exceptionParam) { | |
1893 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1894 int shortCircuitIndex = 0; | |
1895 for (NodeChildData field : specialization.getNode().getChildren()) { | |
1896 if (field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { | |
1897 if (field == forField) { | |
1898 break; | |
1899 } | |
1900 shortCircuitIndex++; | |
1901 } | |
1902 } | |
1903 | |
1904 builder.startStatement().type(shortCircuitParam.getType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); | |
1905 ShortCircuitData shortCircuitData = specialization.getShortCircuits().get(shortCircuitIndex); | |
1906 builder.tree(createTemplateMethodCall(builder, null, specialization, shortCircuitData, exceptionParam != null ? exceptionParam.getLocalName() : null)); | |
1907 builder.end(); // statement | |
1908 | |
1909 return builder.getRoot(); | |
1910 } | |
1911 | |
1912 protected CodeTree createDeoptimize(CodeTreeBuilder parent) { | |
1913 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1914 builder.startStatement(); | |
1915 builder.startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end(); | |
1916 builder.end(); | |
1917 return builder.getRoot(); | |
1918 } | |
1919 | |
1920 protected CodeTree createReturnExecuteAndSpecialize(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData nextSpecialization, ActualParameter exceptionParam, String reason) { | |
1921 SpecializationData generic = getModel().getNode().getGenericSpecialization(); | |
1922 CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); | |
1923 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); | |
1924 specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); | |
1925 addInternalValueParameterNames(specializeCall, generic, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); | |
1926 specializeCall.doubleQuote(reason); | |
1927 specializeCall.end().end(); | |
1928 | |
1929 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
1930 | |
1931 builder.startReturn(); | |
1932 builder.tree(createExpectExecutableType(nextSpecialization.getNode(), generic.getReturnType().getTypeSystemType(), executable, specializeCall.getRoot())); | |
1933 builder.end(); | |
1934 | |
1935 return builder.getRoot(); | |
1936 } | |
1937 } | |
1938 | |
1939 private class PolymorphicNodeFactory extends SpecializedNodeFactory { | |
1940 | |
1941 private final boolean generic; | |
1942 | |
1943 public PolymorphicNodeFactory(ProcessorContext context, CodeTypeElement nodeGen, boolean generic) { | |
1944 super(context, nodeGen); | |
1945 this.generic = generic; | |
1946 } | |
1947 | |
1948 @Override | |
1949 public CodeTypeElement create(SpecializationData specialization) { | |
1950 NodeData node = specialization.getNode(); | |
1951 TypeMirror baseType = node.getNodeType(); | |
1952 if (nodeGen != null) { | |
1953 baseType = nodeGen.asType(); | |
1954 } | |
1955 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC), nodePolymorphicClassName(node, specialization), baseType, false); | |
1956 | |
1957 if (!generic) { | |
1958 clazz.getModifiers().add(Modifier.FINAL); | |
1959 } | |
1960 | |
1961 clazz.getAnnotationMirrors().add(createNodeInfo(node, Kind.POLYMORPHIC)); | |
1962 | |
1963 return clazz; | |
1964 } | |
1965 | |
1966 @Override | |
1967 protected void createChildren(SpecializationData specialization) { | |
1968 // super.createChildren(specialization); | |
1969 CodeTypeElement clazz = getElement(); | |
1970 | |
1971 createConstructors(clazz); | |
1972 createExecuteMethods(specialization); | |
1973 | |
1974 if (generic) { | |
1975 getElement().add(createOptimizeTypes()); | |
1976 createCachedExecuteMethods(specialization); | |
1977 } | |
1978 } | |
1979 | |
1980 private CodeExecutableElement createOptimizeTypes() { | |
1981 NodeData node = getModel().getNode(); | |
1982 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), getContext().getType(void.class), "optimizeTypes"); | |
1983 CodeTreeBuilder builder = method.createBuilder(); | |
1984 builder.startStatement().string(baseClassName(node)).string(" node = this.next0").end(); | |
1985 TypeMirror classType = getContext().getType(Class.class); | |
1986 | |
1987 SpecializationData genericSpecialization = node.getGenericSpecialization(); | |
1988 | |
1989 CodeTreeBuilder whileBodyBuilder = builder.create(); | |
1990 for (ActualParameter parameter : node.getGenericSpecialization().getReturnTypeAndParameters()) { | |
1991 if (!parameter.getSpecification().isSignature()) { | |
1992 continue; | |
1993 } | |
1994 | |
1995 ActualParameter genericParameter = genericSpecialization.findParameter(parameter.getLocalName()); | |
1996 | |
1997 String name = parameter.getLocalName() + "Type"; | |
1998 | |
1999 builder.declaration(classType, name, builder.create().startCall("node", typeGetterName(parameter)).end().getRoot()); | |
2000 | |
2001 whileBodyBuilder.startIf().string(name).string(" != ").startCall("node", typeGetterName(parameter)).end().end(); | |
2002 whileBodyBuilder.startBlock(); | |
2003 whileBodyBuilder.startStatement().string(name).string(" = ").typeLiteral(genericParameter.getType()).end(); | |
2004 whileBodyBuilder.end(); | |
2005 } | |
2006 | |
2007 builder.startWhile().string("node != null && !(").instanceOf("node", nodeSpecializationClassName(node.getUninitializedSpecialization())).string(")").end(); | |
2008 builder.startBlock(); | |
2009 builder.tree(whileBodyBuilder.getRoot()); | |
2010 builder.statement("node = node.next0"); | |
2011 builder.end(); | |
2012 | |
2013 boolean elseIf = false; | |
2014 for (SpecializationData polymorph : node.getPolymorphicSpecializations()) { | |
2015 elseIf = builder.startIf(elseIf); | |
2016 String and = ""; | |
2017 StringBuilder reason = new StringBuilder("Optimized polymorphic types for ("); | |
2018 for (ActualParameter parameter : polymorph.getReturnTypeAndParameters()) { | |
2019 if (!parameter.getSpecification().isSignature()) { | |
2020 continue; | |
2021 } | |
2022 String name = parameter.getLocalName() + "Type"; | |
2023 builder.string(and).string(name).string(" == ").typeLiteral(parameter.getType()); | |
2024 | |
2025 if (!and.isEmpty()) { | |
2026 reason.append(", "); | |
2027 } | |
2028 reason.append(Utils.getSimpleName(parameter.getType())); | |
2029 and = " && "; | |
2030 } | |
2031 reason.append(")"); | |
2032 builder.end(); | |
2033 builder.startBlock(); | |
2034 | |
2035 String className = nodePolymorphicClassName(node, polymorph); | |
2036 builder.startIf().string("getClass() != ").string(className).string(".class").end(); | |
2037 builder.startBlock(); | |
2038 builder.startStatement().startCall("super", "replace"); | |
2039 builder.startNew(className).string("this").end(); | |
2040 builder.doubleQuote(reason.toString()); | |
2041 builder.end().end(); // call | |
2042 builder.end(); // block | |
2043 builder.end(); | |
2044 } | |
2045 return method; | |
2046 } | |
2047 } | |
2048 | |
2049 private class SpecializedNodeFactory extends NodeBaseFactory { | |
2050 | |
2051 protected final CodeTypeElement nodeGen; | |
2052 | |
2053 public SpecializedNodeFactory(ProcessorContext context, CodeTypeElement nodeGen) { | |
2054 super(context); | |
2055 this.nodeGen = nodeGen; | |
2056 } | |
2057 | |
2058 @Override | |
2059 public CodeTypeElement create(SpecializationData specialization) { | |
2060 NodeData node = specialization.getNode(); | |
2061 TypeMirror baseType = node.getNodeType(); | |
2062 if (nodeGen != null) { | |
2063 baseType = nodeGen.asType(); | |
2064 } | |
2065 CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), baseType, false); | |
2066 | |
2067 Kind kind; | |
2068 if (specialization.isGeneric()) { | |
2069 kind = Kind.GENERIC; | |
2070 } else if (specialization.isUninitialized()) { | |
2071 kind = Kind.UNINITIALIZED; | |
2072 } else { | |
2073 kind = Kind.SPECIALIZED; | |
2074 } | |
2075 clazz.getAnnotationMirrors().add(createNodeInfo(node, kind)); | |
2076 | |
2077 return clazz; | |
2078 } | |
2079 | |
2080 protected CodeAnnotationMirror createNodeInfo(NodeData node, Kind kind) { | |
2081 String shortName = node.getShortName(); | |
2082 CodeAnnotationMirror nodeInfoMirror = new CodeAnnotationMirror(getContext().getTruffleTypes().getNodeInfoAnnotation()); | |
2083 if (shortName != null) { | |
2084 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("shortName"), new CodeAnnotationValue(shortName)); | |
2085 } | |
2086 | |
2087 DeclaredType nodeinfoKind = getContext().getTruffleTypes().getNodeInfoKind(); | |
2088 VariableElement varKind = Utils.findVariableElement(nodeinfoKind, kind.name()); | |
2089 | |
2090 nodeInfoMirror.setElementValue(nodeInfoMirror.findExecutableElement("kind"), new CodeAnnotationValue(varKind)); | |
2091 return nodeInfoMirror; | |
2092 } | |
2093 | |
2094 @Override | |
2095 protected void createChildren(SpecializationData specialization) { | |
2096 CodeTypeElement clazz = getElement(); | |
2097 createConstructors(clazz); | |
2098 | |
2099 NodeData node = specialization.getNode(); | |
2100 | |
2101 if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic() && node.needsRewrites(getContext()) && node.getPolymorphicDepth() > 1) { | |
2102 | |
2103 createTypeGetters(clazz, specialization); | |
2104 } | |
2105 | |
2106 createExecuteMethods(specialization); | |
2107 createCachedExecuteMethods(specialization); | |
2108 } | |
2109 | |
2110 protected void createConstructors(CodeTypeElement clazz) { | |
2111 TypeElement superTypeElement = Utils.fromTypeMirror(clazz.getSuperclass()); | |
2112 for (ExecutableElement constructor : ElementFilter.constructorsIn(superTypeElement.getEnclosedElements())) { | |
2113 if (getModel().getNode().getUninitializedSpecialization() != null && !getModel().isUninitialized() && | |
2114 (constructor.getParameters().size() != 1 || constructor.getParameters().get(0).getSimpleName().toString().equals(baseClassName(getModel().getNode())))) { | |
2115 continue; | |
2116 } | |
2117 | |
2118 CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); | |
2119 if (superConstructor != null) { | |
2120 if (getModel().isGeneric() && getModel().getNode().getPolymorphicDepth() > 1) { | |
2121 CodeTree body = superConstructor.getBodyTree(); | |
2122 CodeTreeBuilder builder = superConstructor.createBuilder(); | |
2123 builder.tree(body); | |
2124 builder.statement("this.next0 = null"); | |
2125 } | |
2126 | |
2127 clazz.add(superConstructor); | |
2128 } | |
2129 } | |
2130 } | |
2131 | |
2132 protected void createExecuteMethods(SpecializationData specialization) { | |
2133 NodeData node = specialization.getNode(); | |
2134 CodeTypeElement clazz = getElement(); | |
2135 | |
2136 for (ExecutableTypeData execType : node.getExecutableTypes()) { | |
2137 if (execType.isFinal()) { | |
2138 continue; | |
2139 } | |
2140 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, true); | |
2141 clazz.add(executeMethod); | |
2142 CodeTreeBuilder builder = executeMethod.createBuilder(); | |
2143 CodeTree result = createExecuteBody(builder, specialization, execType); | |
2144 if (result != null) { | |
2145 builder.tree(result); | |
2146 } else { | |
2147 clazz.remove(executeMethod); | |
2148 } | |
2149 } | |
2150 } | |
2151 | |
2152 protected void createCachedExecuteMethods(SpecializationData specialization) { | |
2153 NodeData node = specialization.getNode(); | |
2154 CodeTypeElement clazz = getElement(); | |
2155 int index = 0; | |
2156 for (SpecializationData polymorphic : node.getPolymorphicSpecializations()) { | |
2157 boolean matchFound = false; | |
2158 if (!specialization.isGeneric() && !specialization.isUninitialized() && !specialization.isPolymorphic()) { | |
2159 matchFound = polymorphic.getSignature().hasAnyParameterMatch(specialization.getSignature()); | |
2160 } | |
2161 | |
2162 if (matchFound || index == 0) { | |
2163 ExecutableElement executeCached = nodeGen.getMethod("executeCached" + index); | |
2164 ExecutableTypeData execType = new ExecutableTypeData(polymorphic, executeCached, node.getTypeSystem(), polymorphic.getReturnType().getTypeSystemType()); | |
2165 | |
2166 CodeExecutableElement executeMethod = createExecutableTypeOverride(execType, false); | |
2167 CodeTreeBuilder builder = executeMethod.createBuilder(); | |
2168 | |
2169 if (specialization.isGeneric() || specialization.isPolymorphic()) { | |
2170 builder.startThrow().startNew(getContext().getType(AssertionError.class)); | |
2171 builder.doubleQuote("Should not be reached."); | |
2172 builder.end().end(); | |
2173 } else if (specialization.isUninitialized()) { | |
2174 builder.tree(createAppendPolymorphic(builder, specialization)); | |
2175 } else { | |
2176 CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); | |
2177 elseBuilder.startReturn().startCall("this.next0", "executeCached" + index); | |
2178 addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true); | |
2179 elseBuilder.end().end(); | |
2180 CodeTreeBuilder execute = new CodeTreeBuilder(builder); | |
2181 execute.tree(createGenericInvoke(builder, polymorphic, specialization)); | |
2182 boolean forceElse = !specialization.getExceptions().isEmpty(); | |
2183 builder.tree(createGuardAndCast(builder, null, polymorphic, specialization, true, execute.getRoot(), elseBuilder.getRoot(), true, forceElse)); | |
2184 } | |
2185 clazz.add(executeMethod); | |
2186 } | |
2187 index++; | |
2188 } | |
2189 } | |
2190 | |
2191 private CodeTree createAppendPolymorphic(CodeTreeBuilder parent, SpecializationData specialization) { | |
2192 NodeData node = specialization.getNode(); | |
2193 String genericClassName = nodePolymorphicClassName(node, null); | |
2194 | |
2195 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2196 builder.startStatement().startStaticCall(getContext().getTruffleTypes().getCompilerDirectives(), "transferToInterpreter").end().end(); | |
2197 | |
2198 builder.declaration(getContext().getTruffleTypes().getNode(), "searchNode", "super.getParent()"); | |
2199 builder.declaration(getContext().getType(int.class), "depth", "0"); | |
2200 builder.startWhile().string("searchNode != null").end(); | |
2201 builder.startBlock(); | |
2202 builder.statement("depth++"); | |
2203 builder.statement("searchNode = searchNode.getParent()"); | |
2204 | |
2205 builder.startIf().instanceOf("searchNode", genericClassName).end(); | |
2206 builder.startBlock().breakStatement().end(); | |
2207 builder.end(); // if | |
2208 builder.end(); // while | |
2209 | |
2210 builder.startAssert().instanceOf("searchNode", genericClassName).end(); | |
2211 | |
2212 builder.startStatement(); | |
2213 builder.string(genericClassName).string(" ").string("polymorphic = ").string("(").string(genericClassName).string(") searchNode"); | |
2214 builder.end(); | |
2215 | |
2216 builder.startIf().string("depth >= ").string(String.valueOf(node.getPolymorphicDepth())).end(); | |
2217 builder.startBlock(); | |
2218 builder.startStatement(); | |
2219 builder.startCall("searchNode", "replace"); | |
2220 builder.startNew(nodeSpecializationClassName(node.getGenericSpecialization())).string("this").end(); | |
2221 builder.doubleQuote("Polymorphic limit reached (" + node.getPolymorphicDepth() + ")"); | |
2222 builder.end(); | |
2223 builder.end(); | |
2224 | |
2225 builder.startReturn().startCall("super", EXECUTE_GENERIC_NAME); | |
2226 addInternalValueParameterNames(builder, specialization, node.getGenericSpecialization(), null, true, true); | |
2227 builder.end().end(); | |
2228 | |
2229 builder.end().startElseBlock(); | |
2230 builder.startStatement().startCall("super", "setNext0"); | |
2231 builder.startNew(nodeSpecializationClassName(node.getUninitializedSpecialization())).string("this").end(); | |
2232 builder.end().end(); | |
2233 | |
2234 CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder); | |
2235 specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); | |
2236 specializeCall.string(nodeSpecializationClassName(node.getUninitializedSpecialization()) + ".class"); | |
2237 addInternalValueParameterNames(specializeCall, specialization, node.getGenericSpecialization(), null, true, true); | |
2238 specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end(); | |
2239 specializeCall.end().end(); | |
2240 | |
2241 builder.declaration(node.getGenericSpecialization().getReturnType().getType(), "result", specializeCall.getRoot()); | |
2242 | |
2243 builder.statement("polymorphic.optimizeTypes()"); | |
2244 | |
2245 if (Utils.isVoid(builder.findMethod().getReturnType())) { | |
2246 builder.returnStatement(); | |
2247 } else { | |
2248 builder.startReturn().string("result").end(); | |
2249 } | |
2250 | |
2251 builder.end(); | |
2252 | |
2253 return builder.getRoot(); | |
2254 } | |
2255 | |
2256 private CodeTree createExecuteBody(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData execType) { | |
2257 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | |
2258 | |
2259 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2260 | |
2261 List<ExecutableTypeData> primaryExecutes = findFunctionalExecutableType(specialization, execType.getEvaluatedCount()); | |
2262 | |
2263 if (primaryExecutes.contains(execType) || primaryExecutes.isEmpty()) { | |
2264 builder.tree(createFunctionalExecute(builder, specialization, execType)); | |
2265 } else if (needsCastingExecuteMethod(execType, primaryType)) { | |
2266 assert !primaryExecutes.isEmpty(); | |
2267 builder.tree(createCastingExecute(builder, specialization, execType, primaryExecutes.get(0))); | |
2268 } else { | |
2269 return null; | |
2270 } | |
2271 | |
2272 return builder.getRoot(); | |
2273 } | |
2274 | |
2275 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType, boolean evaluated) { | |
2276 CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), execType.getMethod()); | |
2277 | |
2278 int i = 0; | |
2279 for (VariableElement param : method.getParameters()) { | |
2280 CodeVariableElement var = CodeVariableElement.clone(param); | |
2281 ActualParameter actualParameter = execType.getParameters().get(i); | |
2282 if (evaluated && actualParameter.getSpecification().isSignature()) { | |
2283 var.setName(valueNameEvaluated(actualParameter)); | |
2284 } else { | |
2285 var.setName(valueName(actualParameter)); | |
2286 } | |
2287 method.getParameters().set(i, var); | |
2288 i++; | |
2289 } | |
2290 | |
2291 method.getAnnotationMirrors().clear(); | |
2292 method.getModifiers().remove(Modifier.ABSTRACT); | |
2293 return method; | |
2294 } | |
2295 | |
2296 private boolean needsCastingExecuteMethod(ExecutableTypeData execType, TypeData primaryType) { | |
2297 if (execType.isAbstract()) { | |
2298 return true; | |
2299 } | |
2300 if (Utils.isPrimitiveOrVoid(primaryType.getPrimitiveType()) && Utils.isPrimitiveOrVoid(execType.getType().getPrimitiveType())) { | |
2301 return true; | |
2302 } | |
2303 if (execType.getType().isGeneric()) { | |
2304 return true; | |
2305 } | |
2306 return false; | |
2307 } | |
2308 | |
2309 private List<ExecutableTypeData> findFunctionalExecutableType(SpecializationData specialization, int evaluatedCount) { | |
2310 TypeData primaryType = specialization.getReturnType().getTypeSystemType(); | |
2311 List<ExecutableTypeData> otherTypes = specialization.getNode().getExecutableTypes(evaluatedCount); | |
2312 | |
2313 List<ExecutableTypeData> filteredTypes = new ArrayList<>(); | |
2314 for (ExecutableTypeData compareType : otherTypes) { | |
2315 if (!Utils.typeEquals(compareType.getType().getPrimitiveType(), primaryType.getPrimitiveType())) { | |
2316 continue; | |
2317 } | |
2318 filteredTypes.add(compareType); | |
2319 } | |
2320 | |
2321 // no direct matches found use generic where the type is Object | |
2322 if (filteredTypes.isEmpty()) { | |
2323 for (ExecutableTypeData compareType : otherTypes) { | |
2324 if (compareType.getType().isGeneric() && !compareType.hasUnexpectedValue(getContext())) { | |
2325 filteredTypes.add(compareType); | |
2326 } | |
2327 } | |
2328 } | |
2329 | |
2330 if (filteredTypes.isEmpty()) { | |
2331 for (ExecutableTypeData compareType : otherTypes) { | |
2332 if (compareType.getType().isGeneric()) { | |
2333 filteredTypes.add(compareType); | |
2334 } | |
2335 } | |
2336 } | |
2337 | |
2338 return filteredTypes; | |
2339 } | |
2340 | |
2341 private CodeTree createFunctionalExecute(CodeTreeBuilder parent, SpecializationData specialization, ExecutableTypeData executable) { | |
2342 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2343 if (specialization.isUninitialized()) { | |
2344 builder.tree(createDeoptimize(builder)); | |
2345 } | |
2346 | |
2347 builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); | |
2348 | |
2349 CodeTree executeNode = createExecute(builder, executable, specialization); | |
2350 | |
2351 SpecializationData next = specialization.findNextSpecialization(); | |
2352 CodeTree returnSpecialized = null; | |
2353 if (next != null) { | |
2354 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(builder); | |
2355 returnBuilder.tree(createDeoptimize(builder)); | |
2356 returnBuilder.tree(createReturnExecuteAndSpecialize(builder, executable, next, null, "One of guards " + specialization.getGuards() + " failed")); | |
2357 returnSpecialized = returnBuilder.getRoot(); | |
2358 } | |
2359 builder.tree(createGuardAndCast(builder, null, specialization, specialization, true, executeNode, returnSpecialized, false, false)); | |
2360 | |
2361 return builder.getRoot(); | |
2362 } | |
2363 | |
2364 private CodeTree createExecute(CodeTreeBuilder parent, ExecutableTypeData executable, SpecializationData specialization) { | |
2365 NodeData node = specialization.getNode(); | |
2366 CodeTreeBuilder builder = new CodeTreeBuilder(parent); | |
2367 if (!specialization.getExceptions().isEmpty() || !specialization.getAssumptions().isEmpty()) { | |
2368 builder.startTryBlock(); | |
2369 } | |
2370 | |
2371 for (String assumption : specialization.getAssumptions()) { | |
2372 builder.startStatement(); | |
2373 builder.string("this.").string(assumption).string(".check()"); | |
2374 builder.end(); | |
2375 } | |
2376 | |
2377 CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); | |
2378 if (specialization.isPolymorphic()) { | |
2379 int index = 0; | |
2380 if (executable.hasUnexpectedValue(getContext())) { | |
2381 index = specialization.getNode().getPolymorphicSpecializations().indexOf(specialization); | |
2382 } | |
2383 returnBuilder.startCall("next0", "executeCached" + index); | |
2384 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2385 returnBuilder.end(); | |
2386 } else if (specialization.isUninitialized()) { | |
2387 returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); | |
2388 returnBuilder.startGroup().string(nodeSpecializationClassName(specialization)).string(".class").end(); | |
2389 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2390 returnBuilder.doubleQuote("Uninitialized monomorphic"); | |
2391 returnBuilder.end(); | |
2392 } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { | |
2393 emitEncounteredSynthetic(builder, specialization); | |
2394 } else if (specialization.isGeneric()) { | |
2395 returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); | |
2396 addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); | |
2397 returnBuilder.end(); | |
2398 } else { | |
2399 returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); | |
2400 } | |
2401 | |
2402 if (!returnBuilder.isEmpty()) { | |
2403 builder.startReturn(); | |
2404 | |
2405 TypeData targetType = node.getTypeSystem().findTypeData(builder.findMethod().getReturnType()); | |
2406 TypeData sourceType = specialization.getReturnType().getTypeSystemType(); | |
2407 | |
2408 if (targetType == null || sourceType == null) { | |
2409 builder.tree(returnBuilder.getRoot()); | |
2410 } else if (sourceType.needsCastTo(getContext(), targetType)) { | |
2411 builder.tree(createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.expectTypeMethodName(targetType), returnBuilder.getRoot())); | |
2412 } else { | |
2413 builder.tree(returnBuilder.getRoot()); | |
2414 } | |
2415 builder.end(); | |
2416 } | |
2417 | |
2418 if (!specialization.getExceptions().isEmpty()) { | |
2419 for (SpecializationThrowsData exception : specialization.getExceptions()) { | |
2420 builder.end().startCatchBlock(exception.getJavaClass(), "ex"); | |
2421 builder.tree(createDeoptimize(builder)); | |
2422 builder.tree(createReturnExecuteAndSpecialize(parent, executable, exception.getTransitionTo(), null, "Thrown " + Utils.getSimpleName(exception.getJavaClass()))); | |
2423 } | |
2424 builder.end(); | |
2425 } | |
2426 if (!specialization.getAssumptions().isEmpty()) { | |
2427 builder.end().startCatchBlock(getContext().getTruffleTypes().getInvalidAssumption(), "ex"); | |
2428 builder.tree(createReturnExecuteAndSpecialize(parent, executable, specialization.findNextSpecialization(), null, "Assumption failed")); | |
2429 builder.end(); | |
2430 } | |
2431 | |
2432 return builder.getRoot(); | |
2433 } | |
2434 | |
2435 } | |
2436 | |
2437 } |