Mercurial > hg > graal-compiler
comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java @ 18761:a665483c3881
Truffle-DSL: new node layout implementation.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Mon, 29 Dec 2014 23:38:54 +0100 |
parents | |
children | a720bf2e2f43 |
comparison
equal
deleted
inserted
replaced
18760:6fa3999631d8 | 18761:a665483c3881 |
---|---|
1 /* | |
2 * Copyright (c) 2014, 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.generator; | |
24 | |
25 import static com.oracle.truffle.dsl.processor.generator.GeneratorUtils.*; | |
26 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*; | |
27 import static javax.lang.model.element.Modifier.*; | |
28 | |
29 import java.util.*; | |
30 | |
31 import javax.lang.model.element.*; | |
32 import javax.lang.model.type.*; | |
33 import javax.lang.model.util.*; | |
34 | |
35 import com.oracle.truffle.api.*; | |
36 import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; | |
37 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; | |
38 import com.oracle.truffle.api.dsl.internal.*; | |
39 import com.oracle.truffle.api.dsl.internal.DSLOptions.ImplicitCastOptimization; | |
40 import com.oracle.truffle.api.dsl.internal.DSLOptions.TypeBoxingOptimization; | |
41 import com.oracle.truffle.api.frame.*; | |
42 import com.oracle.truffle.api.nodes.*; | |
43 import com.oracle.truffle.api.nodes.Node.Child; | |
44 import com.oracle.truffle.dsl.processor.*; | |
45 import com.oracle.truffle.dsl.processor.java.*; | |
46 import com.oracle.truffle.dsl.processor.java.model.*; | |
47 import com.oracle.truffle.dsl.processor.model.*; | |
48 import com.oracle.truffle.dsl.processor.parser.*; | |
49 import com.oracle.truffle.dsl.processor.parser.SpecializationGroup.TypeGuard; | |
50 | |
51 public class NodeGenFactory { | |
52 | |
53 private static final String FRAME_VALUE = "frameValue"; | |
54 | |
55 private final ProcessorContext context; | |
56 private final NodeData node; | |
57 private final TypeSystemData typeSystem; | |
58 private final TypeData genericType; | |
59 private final DSLOptions options; | |
60 | |
61 public NodeGenFactory(ProcessorContext context, NodeData node) { | |
62 this.context = context; | |
63 this.node = node; | |
64 this.typeSystem = node.getTypeSystem(); | |
65 this.genericType = typeSystem.getGenericTypeData(); | |
66 this.options = typeSystem.getOptions(); | |
67 } | |
68 | |
69 public static String nodeTypeName(NodeData node) { | |
70 return resolveNodeId(node) + "NodeGen"; | |
71 } | |
72 | |
73 private static String resolveNodeId(NodeData node) { | |
74 String nodeid = node.getNodeId(); | |
75 if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { | |
76 nodeid = nodeid.substring(0, nodeid.length() - 4); | |
77 } | |
78 return nodeid; | |
79 } | |
80 | |
81 public static TypeMirror nodeType(NodeData node) { | |
82 return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()), nodeTypeName(node)); | |
83 } | |
84 | |
85 private static String specializationTypeName(SpecializationData specialization) { | |
86 return specialization.getId() + "Node"; | |
87 } | |
88 | |
89 private static TypeMirror specializationType(SpecializationData specialization) { | |
90 return new GeneratedTypeMirror(ElementUtils.getPackageName(specialization.getNode().getTemplateType()) + "." + nodeTypeName(specialization.getNode()), specializationTypeName(specialization)); | |
91 } | |
92 | |
93 private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) { | |
94 return execution.getName() + "Type_"; | |
95 } | |
96 | |
97 private static String nodeFieldName(NodeExecutionData execution) { | |
98 return execution.getName() + "_"; | |
99 } | |
100 | |
101 private static String specializationStartFieldName() { | |
102 return "specialization_"; | |
103 } | |
104 | |
105 private static String excludedFieldName(SpecializationData specialization) { | |
106 return "exclude" + specialization.getId() + "_"; | |
107 } | |
108 | |
109 private static String executeChildMethodName(NodeExecutionData execution, TypeData type) { | |
110 return "execute" + ElementUtils.firstLetterUpperCase(execution.getName()) + (type.isGeneric() ? "" : getTypeId(type.getBoxedType())) + "_"; | |
111 } | |
112 | |
113 private static CodeTree accessParent(String name) { | |
114 if (name == null) { | |
115 return CodeTreeBuilder.singleString("root"); | |
116 } else { | |
117 return CodeTreeBuilder.createBuilder().string("root.").string(name).build(); | |
118 } | |
119 } | |
120 | |
121 private static String assumptionName(String assumption) { | |
122 return assumption + "_"; | |
123 } | |
124 | |
125 public CodeTypeElement create() { | |
126 String typeName = nodeTypeName(node); | |
127 TypeMirror baseType = node.getTemplateType().asType(); | |
128 CodeTypeElement clazz = GeneratorUtils.createClass(node, null, modifiers(PUBLIC, FINAL), typeName, baseType); | |
129 | |
130 clazz.getImplements().add(getType(SpecializedNode.class)); | |
131 | |
132 for (String assumption : node.getAssumptions()) { | |
133 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getType(Assumption.class), assumptionName(assumption))); | |
134 } | |
135 | |
136 for (NodeChildData child : node.getChildren()) { | |
137 clazz.addOptional(createAccessChildMethod(child)); | |
138 } | |
139 | |
140 for (NodeFieldData field : node.getFields()) { | |
141 if (!field.isGenerated()) { | |
142 continue; | |
143 } | |
144 | |
145 clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), field.getType(), field.getName())); | |
146 if (field.getGetter() != null && field.getGetter().getModifiers().contains(Modifier.ABSTRACT)) { | |
147 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), field.getGetter()); | |
148 method.getModifiers().remove(Modifier.ABSTRACT); | |
149 method.createBuilder().startReturn().string("this.").string(field.getName()).end(); | |
150 clazz.add(method); | |
151 } | |
152 } | |
153 | |
154 List<? extends ExecutableElement> superConstructors = ElementFilter.constructorsIn(node.getTemplateType().getEnclosedElements()); | |
155 for (ExecutableElement superConstructor : superConstructors) { | |
156 if (getVisibility(superConstructor.getModifiers()) == PRIVATE) { | |
157 continue; | |
158 } | |
159 if (superConstructors.size() > 1 && superConstructor.getParameters().size() > 0 && | |
160 ElementUtils.typeEquals(superConstructor.getEnclosingElement().asType(), superConstructor.getParameters().get(0).asType())) { | |
161 // constructor is copy constructor | |
162 continue; | |
163 } | |
164 clazz.add(createNodeConstructor(clazz, superConstructor)); | |
165 } | |
166 | |
167 for (NodeExecutionData execution : node.getChildExecutions()) { | |
168 clazz.add(createNodeField(PRIVATE, execution.getNodeType(), nodeFieldName(execution), Child.class)); | |
169 } | |
170 | |
171 for (NodeExecutionData execution : node.getChildExecutions()) { | |
172 if (findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) { | |
173 continue; | |
174 } | |
175 clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class)); | |
176 } | |
177 | |
178 for (SpecializationData specialization : node.getSpecializations()) { | |
179 if (mayBeExcluded(specialization)) { | |
180 clazz.add(createNodeField(PRIVATE, getType(boolean.class), excludedFieldName(specialization), CompilationFinal.class)); | |
181 } | |
182 } | |
183 | |
184 clazz.add(createNodeField(PRIVATE, TypeSystemNodeFactory.nodeType(node.getTypeSystem()), specializationStartFieldName(), Child.class)); | |
185 clazz.add(createMethodGetSpecializationNode()); | |
186 clazz.add(createDeepCopyMethod()); | |
187 clazz.add(createGetCostMethod()); | |
188 | |
189 Collection<TypeData> specializedTypes = node.findSpecializedReturnTypes(); | |
190 for (ExecutableTypeData execType : node.getExecutableTypes()) { | |
191 if (shouldImplementExecutableType(specializedTypes, execType)) { | |
192 clazz.add(createExecutableTypeOverride(execType)); | |
193 } | |
194 } | |
195 | |
196 SpecializationData initialSpecialization = createSpecializations(clazz); | |
197 | |
198 for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { | |
199 CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder(); | |
200 builder.startStatement(); | |
201 builder.string("this.").string(specializationStartFieldName()); | |
202 builder.string(" = ").tree(createCallCreateMethod(initialSpecialization, "this", null)); | |
203 builder.end(); | |
204 } | |
205 | |
206 return clazz; | |
207 } | |
208 | |
209 private CodeExecutableElement createNodeConstructor(CodeTypeElement clazz, ExecutableElement superConstructor) { | |
210 CodeExecutableElement constructor = GeneratorUtils.createConstructorUsingFields(modifiers(PUBLIC), clazz, superConstructor); | |
211 | |
212 List<CodeVariableElement> childParameters = new ArrayList<>(); | |
213 for (NodeChildData child : node.getChildren()) { | |
214 childParameters.add(new CodeVariableElement(child.getOriginalType(), child.getName())); | |
215 } | |
216 constructor.getParameters().addAll(superConstructor.getParameters().size(), childParameters); | |
217 | |
218 CodeTreeBuilder builder = constructor.appendBuilder(); | |
219 List<String> childValues = new ArrayList<>(node.getChildren().size()); | |
220 for (NodeChildData child : node.getChildren()) { | |
221 String name = child.getName(); | |
222 if (child.getCardinality().isMany()) { | |
223 CreateCastData createCast = node.findCast(child.getName()); | |
224 if (createCast != null) { | |
225 CodeTree nameTree = CodeTreeBuilder.singleString(name); | |
226 CodeTreeBuilder callBuilder = builder.create(); | |
227 callBuilder.string(name).string(" != null ? "); | |
228 callBuilder.tree(callTemplateMethod(builder, null, createCast, nameTree)); | |
229 callBuilder.string(" : null"); | |
230 name += "_"; | |
231 builder.declaration(child.getNodeType(), name, callBuilder.build()); | |
232 } | |
233 } | |
234 childValues.add(name); | |
235 } | |
236 | |
237 for (NodeExecutionData execution : node.getChildExecutions()) { | |
238 CreateCastData createCast = node.findCast(execution.getChild().getName()); | |
239 | |
240 builder.startStatement(); | |
241 builder.string("this.").string(nodeFieldName(execution)).string(" = "); | |
242 | |
243 String name = childValues.get(node.getChildren().indexOf(execution.getChild())); | |
244 CodeTreeBuilder accessorBuilder = builder.create(); | |
245 accessorBuilder.string(name); | |
246 | |
247 if (execution.isIndexed()) { | |
248 accessorBuilder.string("[").string(String.valueOf(execution.getIndex())).string("]"); | |
249 } | |
250 | |
251 CodeTree accessor = accessorBuilder.build(); | |
252 | |
253 if (createCast != null && execution.getChild().getCardinality().isOne()) { | |
254 accessor = callTemplateMethod(builder, null, createCast, accessor); | |
255 } | |
256 | |
257 if (execution.isIndexed()) { | |
258 CodeTreeBuilder nullCheck = builder.create(); | |
259 nullCheck.string(name).string(" != null ? "); | |
260 nullCheck.tree(accessor); | |
261 nullCheck.string(" : null"); | |
262 accessor = nullCheck.build(); | |
263 } | |
264 | |
265 builder.tree(accessor); | |
266 | |
267 builder.end(); | |
268 } | |
269 | |
270 return constructor; | |
271 } | |
272 | |
273 private static boolean mayBeExcluded(SpecializationData specialization) { | |
274 return !specialization.getExceptions().isEmpty() || !specialization.getExcludedBy().isEmpty(); | |
275 } | |
276 | |
277 private SpecializationData createSpecializations(CodeTypeElement clazz) { | |
278 List<SpecializationData> reachableSpecializations = getReachableSpecializations(); | |
279 | |
280 if (isSingleSpecializable(reachableSpecializations)) { | |
281 SpecializationData single = reachableSpecializations.get(0); | |
282 clazz.add(createSingleSpecialization(single)); | |
283 return single; | |
284 } else { | |
285 CodeTypeElement baseSpecialization = clazz.add(createBaseSpecialization(clazz)); | |
286 TypeMirror baseSpecializationType = baseSpecialization.asType(); | |
287 | |
288 Map<SpecializationData, CodeTypeElement> generated = new LinkedHashMap<>(); | |
289 | |
290 List<SpecializationData> generateSpecializations = new ArrayList<>(); | |
291 generateSpecializations.add(node.getUninitializedSpecialization()); | |
292 if (needsPolymorphic(reachableSpecializations)) { | |
293 generateSpecializations.add(node.getPolymorphicSpecialization()); | |
294 } | |
295 generateSpecializations.addAll(reachableSpecializations); | |
296 | |
297 for (SpecializationData specialization : generateSpecializations) { | |
298 generated.put(specialization, clazz.add(createSpecialization(specialization, baseSpecializationType))); | |
299 } | |
300 | |
301 baseSpecialization.addOptional(createCreateNext(generated)); | |
302 baseSpecialization.addOptional(createCreateFallback(generated)); | |
303 baseSpecialization.addOptional(createCreatePolymorphic(generated)); | |
304 | |
305 return node.getUninitializedSpecialization(); | |
306 } | |
307 } | |
308 | |
309 // create specialization | |
310 | |
311 private CodeTypeElement createBaseSpecialization(CodeTypeElement parentClass) { | |
312 CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, STATIC, ABSTRACT), "BaseNode", TypeSystemNodeFactory.nodeType(typeSystem)); | |
313 | |
314 clazz.addOptional(createSpecializationConstructor(clazz, null, null)); | |
315 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); | |
316 | |
317 clazz.addOptional(createUnsupported()); | |
318 clazz.add(createGetSuppliedChildren()); | |
319 | |
320 int signatureSize = node.getSignatureSize(); | |
321 Set<Integer> evaluatedCount = getEvaluatedCounts(); | |
322 for (int evaluated : evaluatedCount) { | |
323 if (signatureSize != evaluated || signatureSize == 0) { | |
324 clazz.add(createFastPathExecuteMethod(null, evaluated > 0 ? null : genericType, evaluated)); | |
325 } | |
326 } | |
327 | |
328 for (NodeExecutionData execution : node.getChildExecutions()) { | |
329 Collection<TypeData> specializedTypes = node.findSpecializedTypes(execution); | |
330 specializedTypes.add(genericType); | |
331 for (TypeData specializedType : specializedTypes) { | |
332 if (isExecuteChildShared(execution, specializedType)) { | |
333 if (specializedType.isGeneric()) { | |
334 parentClass.add(createExecuteChildMethod(execution, specializedType)); | |
335 } else { | |
336 clazz.add(createExecuteChildMethod(execution, specializedType)); | |
337 } | |
338 } | |
339 } | |
340 } | |
341 | |
342 return clazz; | |
343 } | |
344 | |
345 private CodeTypeElement createSingleSpecialization(SpecializationData specialization) { | |
346 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), TypeSystemNodeFactory.nodeType(typeSystem)); | |
347 CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, null, "0")); | |
348 clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); | |
349 TypeData returnType = specialization.getReturnType().getTypeSystemType(); | |
350 Set<Integer> evaluatedCount = getEvaluatedCounts(); | |
351 for (int evaluated : evaluatedCount) { | |
352 clazz.add(createFastPathExecuteMethod(specialization, null, evaluated)); | |
353 } | |
354 if (isTypeBoxingEliminated(specialization)) { | |
355 clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); | |
356 } | |
357 clazz.add(createFastPathWrapExecuteMethod(genericType, null)); | |
358 | |
359 clazz.addOptional(createUnsupported()); | |
360 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); | |
361 clazz.add(createGetSuppliedChildren()); | |
362 | |
363 return clazz; | |
364 } | |
365 | |
366 private CodeTypeElement createSpecialization(SpecializationData specialization, TypeMirror baseType) { | |
367 CodeTypeElement clazz = createClass(node, specialization, modifiers(PRIVATE, STATIC, FINAL), specializationTypeName(specialization), baseType); | |
368 | |
369 CodeExecutableElement constructor = clazz.addOptional(createSpecializationConstructor(clazz, specialization, null)); | |
370 | |
371 for (Parameter p : specialization.getSignatureParameters()) { | |
372 TypeData targetType = p.getTypeSystemType(); | |
373 if (targetType.hasImplicitSourceTypes()) { | |
374 NodeExecutionData execution = p.getSpecification().getExecution(); | |
375 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); | |
376 if (implicitProfile != null) { | |
377 implicitProfile.getModifiers().add(PRIVATE); | |
378 implicitProfile.getModifiers().add(FINAL); | |
379 clazz.add(implicitProfile); | |
380 } | |
381 } | |
382 } | |
383 | |
384 if (specialization.isFallback()) { | |
385 clazz.add(createFallbackGuardMethod()); | |
386 } | |
387 | |
388 clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); | |
389 clazz.addOptional(createMergeMethod(specialization)); | |
390 clazz.addOptional(createIsSameMethod(specialization)); | |
391 | |
392 TypeData returnType = specialization.getReturnType().getTypeSystemType(); | |
393 int signatureSize = specialization.getSignatureSize(); | |
394 | |
395 clazz.add(createFastPathExecuteMethod(specialization, null, signatureSize)); | |
396 | |
397 if (isTypeBoxingEliminated(specialization)) { | |
398 clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); | |
399 | |
400 if (signatureSize > 0 && !returnType.isGeneric()) { | |
401 clazz.add(createFastPathWrapExecuteMethod(genericType, returnType)); | |
402 } | |
403 | |
404 ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0); | |
405 if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) { | |
406 clazz.add(createFastPathWrapVoidMethod(returnType)); | |
407 } | |
408 } | |
409 | |
410 return clazz; | |
411 } | |
412 | |
413 private Element createDeepCopyMethod() { | |
414 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), getType(Node.class), "deepCopy"); | |
415 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
416 CodeTreeBuilder builder = executable.createBuilder(); | |
417 builder.startReturn().startStaticCall(getType(SpecializationNode.class), "updateRoot").string("super.deepCopy()").end().end(); | |
418 return executable; | |
419 } | |
420 | |
421 private Element createGetCostMethod() { | |
422 TypeMirror returnType = getType(NodeCost.class); | |
423 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), returnType, "getCost"); | |
424 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
425 CodeTreeBuilder builder = executable.createBuilder(); | |
426 builder.startReturn().startCall(specializationStartFieldName(), "getNodeCost").end().end(); | |
427 return executable; | |
428 } | |
429 | |
430 private CodeExecutableElement createIsSameMethod(SpecializationData specialization) { | |
431 if (!specialization.isSpecialized() || !options.implicitCastOptimization().isDuplicateTail()) { | |
432 return null; | |
433 } | |
434 | |
435 List<CodeVariableElement> profiles = new ArrayList<>(); | |
436 for (Parameter parameter : specialization.getSignatureParameters()) { | |
437 NodeExecutionData execution = parameter.getSpecification().getExecution(); | |
438 if (execution == null) { | |
439 continue; | |
440 } | |
441 CodeVariableElement var = createImplicitProfileParameter(execution, parameter.getTypeSystemType()); | |
442 if (var != null) { | |
443 profiles.add(var); | |
444 } | |
445 } | |
446 | |
447 if (profiles.isEmpty()) { | |
448 return null; | |
449 } | |
450 | |
451 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), getType(boolean.class), "isSame"); | |
452 method.addParameter(new CodeVariableElement(getType(SpecializationNode.class), "other")); | |
453 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
454 CodeTreeBuilder builder = method.createBuilder(); | |
455 | |
456 builder.startReturn(); | |
457 builder.string("super.isSame(other)"); | |
458 | |
459 for (CodeVariableElement profile : profiles) { | |
460 builder.string(" && "); | |
461 builder.string("this.").string(profile.getName()).string(" == ").string("(").cast(specializationType(specialization)).string("other).").string(profile.getName()); | |
462 } | |
463 | |
464 builder.end(); | |
465 return method; | |
466 } | |
467 | |
468 private Element createMergeMethod(SpecializationData specialization) { | |
469 if (specialization.getExcludedBy().isEmpty() && !specialization.isPolymorphic()) { | |
470 return null; | |
471 } | |
472 TypeMirror specializationNodeType = getType(SpecializationNode.class); | |
473 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), specializationNodeType, "merge"); | |
474 executable.addParameter(new CodeVariableElement(specializationNodeType, "newNode")); | |
475 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
476 CodeTreeBuilder builder = executable.createBuilder(); | |
477 | |
478 if (specialization.isPolymorphic()) { | |
479 builder.statement("return polymorphicMerge(newNode)"); | |
480 } else { | |
481 boolean elseIf = false; | |
482 for (SpecializationData containedSpecialization : specialization.getExcludedBy()) { | |
483 elseIf = builder.startIf(elseIf); | |
484 builder.string("newNode.getClass() == ").typeLiteral(specializationType(containedSpecialization)); | |
485 builder.end(); | |
486 builder.startBlock(); | |
487 builder.statement("removeSame(\"Contained by " + containedSpecialization.createReferenceName() + "\")"); | |
488 builder.end(); | |
489 } | |
490 builder.statement("return super.merge(newNode)"); | |
491 } | |
492 | |
493 return executable; | |
494 } | |
495 | |
496 private Element createFastPathWrapVoidMethod(TypeData wrap) { | |
497 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), TypeSystemNodeFactory.executeName(typeSystem.getVoidType())); | |
498 executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE)); | |
499 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
500 CodeTreeBuilder builder = executable.createBuilder(); | |
501 builder.startStatement(); | |
502 builder.startCall(TypeSystemNodeFactory.voidBoxingExecuteName(wrap)); | |
503 builder.string(FRAME_VALUE); | |
504 builder.end(); | |
505 builder.end(); | |
506 | |
507 return executable; | |
508 } | |
509 | |
510 private Element createFastPathWrapExecuteMethod(TypeData override, TypeData wrap) { | |
511 CodeExecutableElement executable = new CodeExecutableElement(modifiers(PUBLIC), override.getPrimitiveType(), TypeSystemNodeFactory.executeName(override)); | |
512 executable.addParameter(new CodeVariableElement(getType(VirtualFrame.class), FRAME_VALUE)); | |
513 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
514 CodeTreeBuilder builder = executable.createBuilder(); | |
515 if (wrap != null) { | |
516 builder.startTryBlock(); | |
517 } | |
518 builder.startReturn(); | |
519 builder.startCall(TypeSystemNodeFactory.executeName(wrap)); | |
520 builder.string(FRAME_VALUE); | |
521 builder.end(); | |
522 builder.end(); | |
523 if (wrap != null) { | |
524 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
525 builder.statement("return ex.getResult()"); | |
526 builder.end(); | |
527 } | |
528 | |
529 return executable; | |
530 } | |
531 | |
532 private boolean needsPolymorphic(List<SpecializationData> reachableSpecializations) { | |
533 if (reachableSpecializations.size() > 1) { | |
534 return true; | |
535 } | |
536 if (options.implicitCastOptimization().isDuplicateTail()) { | |
537 SpecializationData specialization = reachableSpecializations.get(0); | |
538 for (Parameter parameter : specialization.getSignatureParameters()) { | |
539 if (parameter.getTypeSystemType().hasImplicitSourceTypes()) { | |
540 return true; | |
541 } | |
542 } | |
543 } | |
544 return false; | |
545 } | |
546 | |
547 private Element createCreateFallback(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) { | |
548 SpecializationData fallback = node.getGenericSpecialization(); | |
549 if (fallback == null) { | |
550 return null; | |
551 } | |
552 CodeTypeElement generatedType = generatedSpecializationClasses.get(fallback); | |
553 if (generatedType == null) { | |
554 return null; | |
555 } | |
556 | |
557 TypeMirror returnType = getType(SpecializationNode.class); | |
558 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createFallback"); | |
559 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
560 method.createBuilder().startReturn().tree(createCallCreateMethod(fallback, null, null)).end(); | |
561 return method; | |
562 } | |
563 | |
564 private Element createCreatePolymorphic(Map<SpecializationData, CodeTypeElement> generatedSpecializationClasses) { | |
565 SpecializationData polymorphic = node.getPolymorphicSpecialization(); | |
566 CodeTypeElement generatedPolymorphic = generatedSpecializationClasses.get(polymorphic); | |
567 if (generatedPolymorphic == null) { | |
568 return null; | |
569 } | |
570 TypeMirror returnType = getType(SpecializationNode.class); | |
571 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), returnType, "createPolymorphic"); | |
572 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
573 method.createBuilder().startReturn().tree(createCallCreateMethod(polymorphic, null, null)).end(); | |
574 return method; | |
575 } | |
576 | |
577 private CodeExecutableElement createCreateNext(final Map<SpecializationData, CodeTypeElement> specializationClasses) { | |
578 final LocalContext locals = LocalContext.load(this); | |
579 | |
580 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), getType(SpecializationNode.class), "createNext", FRAME_VALUE); | |
581 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
582 | |
583 CodeTreeBuilder builder = method.createBuilder(); | |
584 SpecializationGroup group = createSpecializationGroups(); | |
585 CodeTree execution = createGuardAndCast(group, genericType, locals, new SpecializationExecution() { | |
586 public CodeTree createExecute(SpecializationData specialization, LocalContext values) { | |
587 CodeTypeElement generatedType = specializationClasses.get(specialization); | |
588 if (generatedType == null) { | |
589 throw new AssertionError("No generated type for " + specialization); | |
590 } | |
591 return createSlowPathExecute(specialization, locals); | |
592 } | |
593 | |
594 public boolean isFastPath() { | |
595 return false; | |
596 } | |
597 }); | |
598 | |
599 builder.tree(execution); | |
600 | |
601 if (hasFallthrough(group, genericType, locals, false)) { | |
602 builder.returnNull(); | |
603 } | |
604 return method; | |
605 } | |
606 | |
607 private CodeExecutableElement createFallbackGuardMethod() { | |
608 boolean frameUsed = node.isFrameUsedByAnyGuard(context); | |
609 LocalContext locals = LocalContext.load(this); | |
610 | |
611 if (!frameUsed) { | |
612 locals.removeValue(FRAME_VALUE); | |
613 } | |
614 | |
615 CodeExecutableElement boundaryMethod = locals.createMethod(modifiers(PRIVATE), getType(boolean.class), "guardFallback", FRAME_VALUE); | |
616 if (!frameUsed) { | |
617 boundaryMethod.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(TruffleBoundary.class))); | |
618 } | |
619 | |
620 CodeTreeBuilder builder = boundaryMethod.createBuilder(); | |
621 builder.startReturn(); | |
622 builder.startCall("createNext"); | |
623 locals.addReferencesTo(builder, FRAME_VALUE); | |
624 builder.end(); | |
625 builder.string(" == null"); | |
626 builder.end(); | |
627 return boundaryMethod; | |
628 } | |
629 | |
630 private ExecutableElement createAccessChildMethod(NodeChildData child) { | |
631 if (child.getAccessElement() != null && child.getAccessElement().getModifiers().contains(Modifier.ABSTRACT)) { | |
632 ExecutableElement getter = (ExecutableElement) child.getAccessElement(); | |
633 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), getter); | |
634 method.getModifiers().remove(Modifier.ABSTRACT); | |
635 | |
636 List<NodeExecutionData> executions = new ArrayList<>(); | |
637 for (NodeExecutionData execution : node.getChildExecutions()) { | |
638 if (execution.getChild() == child) { | |
639 executions.add(execution); | |
640 } | |
641 } | |
642 | |
643 CodeTreeBuilder builder = method.createBuilder(); | |
644 if (child.getCardinality().isMany()) { | |
645 builder.startReturn().startNewArray((ArrayType) child.getOriginalType(), null); | |
646 for (NodeExecutionData execution : executions) { | |
647 builder.string(nodeFieldName(execution)); | |
648 } | |
649 builder.end().end(); | |
650 } else { | |
651 for (NodeExecutionData execution : executions) { | |
652 builder.startReturn().string("this.").string(nodeFieldName(execution)).end(); | |
653 break; | |
654 } | |
655 } | |
656 return method; | |
657 } | |
658 return null; | |
659 } | |
660 | |
661 private boolean isTypeBoxingEliminated(SpecializationData specialization) { | |
662 if (specialization.getMethod() == null) { | |
663 return false; | |
664 } | |
665 | |
666 TypeBoxingOptimization optimization = options.monomorphicTypeBoxingOptimization(); | |
667 if (isTypeBoxingOptimized(optimization, specialization.getReturnType().getTypeSystemType())) { | |
668 return true; | |
669 } | |
670 for (Parameter p : specialization.getSignatureParameters()) { | |
671 if (isTypeBoxingOptimized(optimization, p.getTypeSystemType())) { | |
672 return true; | |
673 } | |
674 } | |
675 return false; | |
676 | |
677 } | |
678 | |
679 private Set<Integer> getEvaluatedCounts() { | |
680 Set<Integer> evaluatedCount = new TreeSet<>(); | |
681 Collection<TypeData> returnSpecializedTypes = node.findSpecializedReturnTypes(); | |
682 for (ExecutableTypeData execType : node.getExecutableTypes()) { | |
683 if (shouldImplementExecutableType(returnSpecializedTypes, execType)) { | |
684 evaluatedCount.add(execType.getEvaluatedCount()); | |
685 } | |
686 } | |
687 return evaluatedCount; | |
688 } | |
689 | |
690 // create specialization | |
691 | |
692 private Element createUnsupported() { | |
693 SpecializationData fallback = node.getGenericSpecialization(); | |
694 if (fallback == null || optimizeFallback(fallback) || fallback.getMethod() == null) { | |
695 return null; | |
696 } | |
697 LocalContext locals = LocalContext.load(this); | |
698 | |
699 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), genericType.getPrimitiveType(), "unsupported", FRAME_VALUE); | |
700 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
701 | |
702 CodeTreeBuilder builder = method.createBuilder(); | |
703 builder.startReturn(); | |
704 builder.tree(callTemplateMethod(builder, accessParent(null), fallback, locals)); | |
705 builder.end(); | |
706 | |
707 return method; | |
708 } | |
709 | |
710 private boolean isSingleSpecializable(List<SpecializationData> reachableSpecializations) { | |
711 if (reachableSpecializations.size() != 1) { | |
712 return false; | |
713 } | |
714 return !reachableSpecializations.get(0).hasRewrite(context); | |
715 } | |
716 | |
717 private List<SpecializationData> getReachableSpecializations() { | |
718 List<SpecializationData> specializations = new ArrayList<>(); | |
719 for (SpecializationData specialization : node.getSpecializations()) { | |
720 if (specialization.isReachable() && // | |
721 (specialization.isSpecialized() // | |
722 || (specialization.isFallback() && optimizeFallback(specialization)))) { | |
723 specializations.add(specialization); | |
724 } | |
725 } | |
726 return specializations; | |
727 } | |
728 | |
729 private boolean optimizeFallback(SpecializationData specialization) { | |
730 switch (options.optimizeFallback()) { | |
731 case NEVER: | |
732 return false; | |
733 case DECLARED: | |
734 return specialization.getMethod() != null; | |
735 case ALWAYS: | |
736 return true; | |
737 default: | |
738 throw new AssertionError(); | |
739 } | |
740 } | |
741 | |
742 private CodeExecutableElement createExecutableTypeOverride(ExecutableTypeData execType) { | |
743 final String varArgsName = "args"; | |
744 final TypeData returnType = execType.getType(); | |
745 final TypeData executedType = execType.getEvaluatedCount() > 0 ? null : returnType; | |
746 | |
747 CodeExecutableElement method = cloneExecutableTypeOverride(execType, varArgsName); | |
748 | |
749 LocalContext locals = LocalContext.load(this, execType.getSignatureSize()); | |
750 | |
751 // rename varargs parameter | |
752 int signatureIndex = 0; | |
753 for (Parameter parameter : execType.getSignatureParameters()) { | |
754 if (parameter.isTypeVarArgs()) { | |
755 String newName = varArgsName + "[" + parameter.getTypeVarArgsIndex() + "]"; | |
756 NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); | |
757 locals.setValue(execution, locals.getValue(execution).accessWith(CodeTreeBuilder.singleString(newName))); | |
758 } | |
759 signatureIndex++; | |
760 } | |
761 | |
762 CodeTreeBuilder builder = method.createBuilder(); | |
763 | |
764 // create acceptAndExecute | |
765 CodeTreeBuilder executeBuilder = builder.create(); | |
766 executeBuilder.startCall(specializationStartFieldName(), TypeSystemNodeFactory.executeName(executedType)); | |
767 Parameter frame = execType.getFrame(); | |
768 if (frame == null) { | |
769 executeBuilder.nullLiteral(); | |
770 } else { | |
771 executeBuilder.string(frame.getLocalName()); | |
772 } | |
773 locals.addReferencesTo(executeBuilder); | |
774 executeBuilder.end(); | |
775 | |
776 CodeTreeBuilder contentBuilder = builder.create(); | |
777 contentBuilder.startReturn(); | |
778 contentBuilder.tree(TypeSystemCodeGenerator.expect(executedType, returnType, executeBuilder.build())); | |
779 contentBuilder.end(); | |
780 | |
781 // try catch assert if unexpected value is not expected | |
782 if (!execType.hasUnexpectedValue(context) && !returnType.isGeneric() && !returnType.isVoid()) { | |
783 builder.startTryBlock(); | |
784 builder.tree(contentBuilder.build()); | |
785 builder.end().startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
786 builder.startThrow().startNew(getType(AssertionError.class)).end().end(); | |
787 builder.end(); | |
788 } else { | |
789 builder.tree(contentBuilder.build()); | |
790 } | |
791 | |
792 return method; | |
793 } | |
794 | |
795 private CodeExecutableElement cloneExecutableTypeOverride(ExecutableTypeData execType, final String varArgsName) throws AssertionError { | |
796 CodeExecutableElement method = CodeExecutableElement.clone(context.getEnvironment(), execType.getMethod()); | |
797 | |
798 method.getAnnotationMirrors().clear(); | |
799 method.getModifiers().remove(Modifier.ABSTRACT); | |
800 | |
801 if (!execType.getMethod().isVarArgs() && execType.getParameters().size() != method.getParameters().size()) { | |
802 throw new AssertionError("Should be verified in the parser"); | |
803 } | |
804 | |
805 // align argument names | |
806 int index = 0; | |
807 for (Parameter parameter : execType.getParameters()) { | |
808 CodeVariableElement var = (CodeVariableElement) method.getParameters().get(index); | |
809 if (parameter.isTypeVarArgs()) { | |
810 var.getAnnotationMirrors().clear(); | |
811 var.setName(varArgsName); | |
812 break; | |
813 } | |
814 var.setName(LocalVariable.fromParameter(parameter).createParameter().getName()); | |
815 var.getAnnotationMirrors().clear(); | |
816 index++; | |
817 } | |
818 return method; | |
819 } | |
820 | |
821 private boolean shouldImplementExecutableType(Collection<TypeData> specializedTypes, ExecutableTypeData execType) { | |
822 TypeData type = execType.getType(); | |
823 Set<Modifier> modifiers = execType.getMethod().getModifiers(); | |
824 if (modifiers.contains(FINAL) || modifiers.contains(STATIC) || modifiers.contains(PRIVATE)) { | |
825 return false; | |
826 } else if (execType.isAbstract()) { | |
827 return true; | |
828 } else if (type.isGeneric()) { | |
829 return true; | |
830 } else if (type.isVoid()) { | |
831 for (TypeData specializedType : specializedTypes) { | |
832 if (isTypeBoxingOptimized(options.voidBoxingOptimization(), specializedType)) { | |
833 return true; | |
834 } | |
835 } | |
836 return false; | |
837 } else if (!specializedTypes.contains(type)) { | |
838 return false; | |
839 } else if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), type)) { | |
840 return false; | |
841 } | |
842 return true; | |
843 } | |
844 | |
845 private Element createMethodGetSpecializationNode() { | |
846 TypeMirror returntype = getType(SpecializationNode.class); | |
847 CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), returntype, "getSpecializationNode"); | |
848 method.createBuilder().startReturn().string(specializationStartFieldName()).end(); | |
849 return method; | |
850 } | |
851 | |
852 private TypeMirror getType(Class<?> clazz) { | |
853 return context.getType(clazz); | |
854 } | |
855 | |
856 private CodeVariableElement createNodeField(Modifier visibility, TypeMirror type, String name, Class<?> annotationType) { | |
857 CodeVariableElement childField = new CodeVariableElement(modifiers(), type, name); | |
858 childField.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(annotationType))); | |
859 setVisibility(childField.getModifiers(), visibility); | |
860 return childField; | |
861 } | |
862 | |
863 private static List<ExecutableTypeData> findSpecializedExecutables(NodeExecutionData execution, Collection<TypeData> types, TypeBoxingOptimization optimization) { | |
864 if (optimization == TypeBoxingOptimization.NONE) { | |
865 return Collections.emptyList(); | |
866 } | |
867 | |
868 List<ExecutableTypeData> executables = new ArrayList<>(); | |
869 for (TypeData type : types) { | |
870 if (!isTypeBoxingOptimized(optimization, type)) { | |
871 continue; | |
872 } | |
873 ExecutableTypeData foundType = execution.getChild().getNodeData().findExecutableType(type, execution.getChild().getExecuteWith().size()); | |
874 if (foundType != null) { | |
875 executables.add(foundType); | |
876 } | |
877 } | |
878 return executables; | |
879 } | |
880 | |
881 private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, CodeTree... boundValues) { | |
882 CodeTreeBuilder builder = parent.create(); | |
883 if (method.getMethod().getModifiers().contains(STATIC)) { | |
884 builder.startStaticCall(method.getMethod().getEnclosingElement().asType(), method.getMethodName()); | |
885 } else { | |
886 builder.startCall(receiver, method.getMethodName()); | |
887 } | |
888 int index = -1; | |
889 for (Parameter parameter : method.getParameters()) { | |
890 index++; | |
891 if (index < boundValues.length) { | |
892 CodeTree tree = boundValues[index]; | |
893 if (tree != null) { | |
894 builder.tree(tree); | |
895 continue; | |
896 } | |
897 } | |
898 builder.string(parameter.getLocalName()); | |
899 } | |
900 builder.end(); | |
901 return builder.build(); | |
902 } | |
903 | |
904 private static CodeTree callTemplateMethod(CodeTreeBuilder parent, CodeTree receiver, TemplateMethod method, LocalContext currentValues) { | |
905 CodeTree[] bindings = new CodeTree[method.getParameters().size()]; | |
906 | |
907 int signatureIndex = 0; | |
908 for (int i = 0; i < bindings.length; i++) { | |
909 Parameter parameter = method.getParameters().get(i); | |
910 LocalVariable var = currentValues.get(parameter, signatureIndex); | |
911 if (var != null) { | |
912 CodeTree valueReference = bindings[i] = var.createReference(); | |
913 if (parameter.getTypeSystemType() != null && var.getType() != null && var.getType().needsCastTo(parameter.getTypeSystemType())) { | |
914 valueReference = TypeSystemCodeGenerator.cast(parameter.getTypeSystemType(), valueReference); | |
915 } | |
916 bindings[i] = valueReference; | |
917 } | |
918 if (parameter.getSpecification().isSignature()) { | |
919 signatureIndex++; | |
920 } | |
921 } | |
922 return callTemplateMethod(parent, receiver, method, bindings); | |
923 } | |
924 | |
925 private SpecializationGroup createSpecializationGroups() { | |
926 return SpecializationGroup.create(getReachableSpecializations()); | |
927 } | |
928 | |
929 private CodeTree createSlowPathExecute(SpecializationData specialization, LocalContext currentValues) { | |
930 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
931 if (specialization.isFallback()) { | |
932 return builder.returnNull().build(); | |
933 } | |
934 if (node.isFrameUsedByAnyGuard(context)) { | |
935 builder.tree(createTransferToInterpreterAndInvalidate()); | |
936 } | |
937 for (SpecializationData otherSpeciailzation : node.getSpecializations()) { | |
938 if (otherSpeciailzation == specialization) { | |
939 continue; | |
940 } | |
941 if (otherSpeciailzation.getExcludedBy().contains(specialization)) { | |
942 builder.startStatement(); | |
943 builder.tree(accessParent(excludedFieldName(otherSpeciailzation))); | |
944 builder.string(" = true"); | |
945 builder.end(); | |
946 } | |
947 } | |
948 | |
949 builder.startReturn().tree(createCallCreateMethod(specialization, null, currentValues)).end(); | |
950 | |
951 if (mayBeExcluded(specialization)) { | |
952 CodeTreeBuilder checkHasSeenBuilder = builder.create(); | |
953 checkHasSeenBuilder.startIf().string("!").tree(accessParent(excludedFieldName(specialization))).end().startBlock(); | |
954 checkHasSeenBuilder.tree(builder.build()); | |
955 checkHasSeenBuilder.end(); | |
956 return checkHasSeenBuilder.build(); | |
957 } | |
958 return builder.build(); | |
959 } | |
960 | |
961 private static boolean hasFallthrough(SpecializationGroup group, TypeData forType, LocalContext currentValues, boolean fastPath) { | |
962 for (TypeGuard guard : group.getTypeGuards()) { | |
963 if (currentValues.getValue(guard.getSignatureIndex()) == null) { | |
964 // not evaluated | |
965 return true; | |
966 } | |
967 LocalVariable value = currentValues.getValue(guard.getSignatureIndex()); | |
968 if (value.getType().needsCastTo(guard.getType())) { | |
969 return true; | |
970 } | |
971 } | |
972 | |
973 List<GuardExpression> expressions = new ArrayList<>(group.getGuards()); | |
974 expressions.removeAll(group.findElseConnectableGuards()); | |
975 if (!expressions.isEmpty()) { | |
976 return true; | |
977 } | |
978 | |
979 if ((!fastPath || forType.isGeneric()) && !group.getAssumptions().isEmpty()) { | |
980 return true; | |
981 } | |
982 | |
983 if (!fastPath && group.getSpecialization() != null && !group.getSpecialization().getExceptions().isEmpty()) { | |
984 return true; | |
985 } | |
986 | |
987 if (!group.getChildren().isEmpty()) { | |
988 return hasFallthrough(group.getChildren().get(group.getChildren().size() - 1), forType, currentValues, fastPath); | |
989 } | |
990 | |
991 return false; | |
992 } | |
993 | |
994 private Element createGetSuppliedChildren() { | |
995 ArrayType nodeArray = context.getEnvironment().getTypeUtils().getArrayType(getType(Node.class)); | |
996 | |
997 CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, FINAL), nodeArray, "getSuppliedChildren"); | |
998 method.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
999 | |
1000 CodeTreeBuilder builder = method.createBuilder(); | |
1001 | |
1002 builder.startReturn().startNewArray(nodeArray, null); | |
1003 for (int i = 0; i < node.getChildExecutions().size(); i++) { | |
1004 NodeExecutionData execution = node.getChildExecutions().get(i); | |
1005 if (execution.isShortCircuit()) { | |
1006 builder.nullLiteral(); | |
1007 } | |
1008 builder.tree(accessParent(nodeFieldName(execution))); | |
1009 } | |
1010 builder.end().end(); | |
1011 | |
1012 return method; | |
1013 } | |
1014 | |
1015 // create specialization | |
1016 | |
1017 private CodeTree createCallCreateMethod(SpecializationData specialization, String rootName, LocalContext currentValues) { | |
1018 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1019 | |
1020 TypeMirror specializationType = specializationType(specialization); | |
1021 if (options.useLazyClassLoading()) { | |
1022 builder.startStaticCall(specializationType(specialization), "create"); | |
1023 } else { | |
1024 builder.startNew(specializationType); | |
1025 } | |
1026 if (rootName != null) { | |
1027 builder.string(rootName); | |
1028 } else { | |
1029 builder.string("root"); | |
1030 } | |
1031 if (currentValues != null) { | |
1032 for (Parameter p : specialization.getSignatureParameters()) { | |
1033 LocalVariable local = currentValues.get(p.getLocalName()); | |
1034 CodeVariableElement var = createImplicitProfileParameter(p.getSpecification().getExecution(), p.getTypeSystemType()); | |
1035 if (var != null) { | |
1036 builder.tree(local.createReference()); | |
1037 } | |
1038 } | |
1039 } | |
1040 builder.end(); | |
1041 | |
1042 return builder.build(); | |
1043 } | |
1044 | |
1045 private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) { | |
1046 if (!options.useLazyClassLoading()) { | |
1047 return null; | |
1048 } | |
1049 | |
1050 CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor); | |
1051 | |
1052 TypeMirror specializationType = specializationType(specialization); | |
1053 | |
1054 executable.setReturnType(TypeSystemNodeFactory.nodeType(typeSystem)); | |
1055 executable.setSimpleName(CodeNames.of("create")); | |
1056 executable.getModifiers().add(STATIC); | |
1057 | |
1058 CodeTreeBuilder builder = executable.createBuilder(); | |
1059 builder.startReturn().startNew(specializationType); | |
1060 for (VariableElement parameter : executable.getParameters()) { | |
1061 builder.string(parameter.getSimpleName().toString()); | |
1062 } | |
1063 builder.end().end(); | |
1064 return executable; | |
1065 } | |
1066 | |
1067 private static String implicitClassFieldName(NodeExecutionData execution) { | |
1068 return execution.getName() + "ImplicitType"; | |
1069 } | |
1070 | |
1071 private static String implicitNodeFieldName(NodeExecutionData execution) { | |
1072 return execution.getName() + "Cast"; | |
1073 } | |
1074 | |
1075 private CodeExecutableElement createSpecializationConstructor(CodeTypeElement clazz, SpecializationData specialization, String constantIndex) { | |
1076 CodeExecutableElement constructor = new CodeExecutableElement(modifiers(), null, clazz.getSimpleName().toString()); | |
1077 | |
1078 constructor.addParameter(new CodeVariableElement(nodeType(node), "root")); | |
1079 CodeTreeBuilder builder = constructor.createBuilder(); | |
1080 | |
1081 if (specialization == null) { | |
1082 if (constantIndex == null) { | |
1083 builder.statement("super(index)"); | |
1084 constructor.addParameter(new CodeVariableElement(getType(int.class), "index")); | |
1085 } else { | |
1086 builder.startStatement().startSuperCall().string(constantIndex).end().end(); | |
1087 } | |
1088 builder.statement("this.root = root"); | |
1089 } else { | |
1090 int index = resolveSpecializationIndex(specialization); | |
1091 builder.startStatement().startSuperCall().string("root").string(String.valueOf(index)).end().end(); | |
1092 | |
1093 for (Parameter p : specialization.getSignatureParameters()) { | |
1094 NodeExecutionData execution = p.getSpecification().getExecution(); | |
1095 | |
1096 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, p.getTypeSystemType()); | |
1097 if (implicitProfile != null) { | |
1098 LocalVariable var = LocalVariable.fromParameter(p).makeGeneric(); | |
1099 | |
1100 String implicitFieldName = implicitProfile.getName(); | |
1101 if (options.implicitCastOptimization().isDuplicateTail()) { | |
1102 constructor.addParameter(var.createParameter()); | |
1103 CodeTree implicitType = TypeSystemCodeGenerator.implicitType(p.getTypeSystemType(), var.createReference()); | |
1104 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(implicitType).end(); | |
1105 } else if (options.implicitCastOptimization().isMergeCasts()) { | |
1106 // use node that supports polymorphism | |
1107 constructor.addParameter(var.createParameter()); | |
1108 builder.startStatement().string("this.").string(implicitFieldName).string(" = ").tree(ImplicitCastNodeFactory.create(p.getTypeSystemType(), var.createReference())).end(); | |
1109 } else { | |
1110 throw new AssertionError(); | |
1111 } | |
1112 } | |
1113 } | |
1114 } | |
1115 | |
1116 if (constructor.getParameters().isEmpty()) { | |
1117 // do not generate default constructor | |
1118 return null; | |
1119 } | |
1120 return constructor; | |
1121 } | |
1122 | |
1123 // TODO this logic can be inlined to the parser as soon as the old NodeGen layout is gone | |
1124 private static int resolveSpecializationIndex(SpecializationData specialization) { | |
1125 if (specialization.isFallback()) { | |
1126 return Integer.MAX_VALUE - 1; | |
1127 } else if (specialization.isUninitialized()) { | |
1128 return Integer.MAX_VALUE; | |
1129 } else if (specialization.isPolymorphic()) { | |
1130 return 0; | |
1131 } else { | |
1132 return specialization.getIndex(); | |
1133 } | |
1134 } | |
1135 | |
1136 private CodeTree createCallNext(TypeData forType, LocalContext currentValues) { | |
1137 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1138 builder.startCall("next", TypeSystemNodeFactory.executeName(null)); | |
1139 currentValues.addReferencesTo(builder, FRAME_VALUE); | |
1140 builder.end(); | |
1141 return TypeSystemCodeGenerator.expect(genericType, forType, builder.build()); | |
1142 } | |
1143 | |
1144 private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { | |
1145 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1146 builder.startCall(methodName); | |
1147 if (reason != null) { | |
1148 builder.doubleQuote(reason); | |
1149 } | |
1150 currentValues.addReferencesTo(builder, FRAME_VALUE); | |
1151 builder.end(); | |
1152 | |
1153 TypeData executedType = forType.getTypeSystem().getGenericTypeData(); | |
1154 return TypeSystemCodeGenerator.expect(executedType, forType, builder.build()); | |
1155 } | |
1156 | |
1157 private static ExecutableTypeData findSpecializedExecutableType(NodeExecutionData execution, TypeData type) { | |
1158 NodeChildData child = execution.getChild(); | |
1159 int executeWithCount = child.getExecuteWith().size(); | |
1160 return child.getNodeData().findExecutableType(type, executeWithCount); | |
1161 } | |
1162 | |
1163 private boolean hasUnexpectedResult(NodeExecutionData execution, TypeData type) { | |
1164 if (type.isGeneric() || type.isVoid()) { | |
1165 return false; | |
1166 } | |
1167 List<ExecutableTypeData> executableTypes = new ArrayList<>(); | |
1168 executableTypes.add(findSpecializedExecutableType(execution, type)); | |
1169 | |
1170 if (!options.implicitCastOptimization().isNone()) { | |
1171 executableTypes.addAll(findSpecializedExecutables(execution, type.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization())); | |
1172 } | |
1173 | |
1174 for (ExecutableTypeData executableType : executableTypes) { | |
1175 if (executableType != null && executableType.hasUnexpectedValue(context)) { | |
1176 return true; | |
1177 } | |
1178 } | |
1179 return false; | |
1180 } | |
1181 | |
1182 private Element createFastPathExecuteMethod(SpecializationData specialization, final TypeData forType, int evaluatedArguments) { | |
1183 TypeData type = forType == null ? genericType : forType; | |
1184 LocalContext currentLocals = LocalContext.load(this, evaluatedArguments); | |
1185 | |
1186 CodeExecutableElement executable = currentLocals.createMethod(modifiers(PUBLIC), type.getPrimitiveType(), TypeSystemNodeFactory.executeName(forType), FRAME_VALUE); | |
1187 executable.getAnnotationMirrors().add(new CodeAnnotationMirror(context.getDeclaredType(Override.class))); | |
1188 | |
1189 if (!type.isGeneric()) { | |
1190 executable.getThrownTypes().add(getType(UnexpectedResultException.class)); | |
1191 } | |
1192 | |
1193 CodeTreeBuilder builder = executable.createBuilder(); | |
1194 | |
1195 for (NodeExecutionData execution : node.getChildExecutions()) { | |
1196 LocalVariable var = currentLocals.getValue(execution); | |
1197 if (var == null) { | |
1198 TypeData targetType; | |
1199 if (specialization == null) { | |
1200 targetType = genericType; | |
1201 } else { | |
1202 targetType = specialization.findParameterOrDie(execution).getTypeSystemType(); | |
1203 } | |
1204 LocalVariable shortCircuit = resolveShortCircuit(specialization, execution, currentLocals); | |
1205 LocalVariable value = currentLocals.createValue(execution, targetType).nextName(); | |
1206 builder.tree(createAssignExecuteChild(execution, type, value, shortCircuit, currentLocals)); | |
1207 currentLocals.setValue(execution, value); | |
1208 } | |
1209 } | |
1210 | |
1211 LocalContext originalValues = currentLocals.copy(); | |
1212 if (specialization == null) { | |
1213 builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); | |
1214 } else if (specialization.isPolymorphic()) { | |
1215 builder.startReturn().tree(createCallNext(type, currentLocals)).end(); | |
1216 } else if (specialization.isUninitialized()) { | |
1217 builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); | |
1218 } else { | |
1219 final TypeData type_ = type; | |
1220 SpecializationGroup group = SpecializationGroup.create(specialization); | |
1221 SpecializationExecution executionFactory = new SpecializationExecution() { | |
1222 public CodeTree createExecute(SpecializationData s, LocalContext values) { | |
1223 return createFastPathExecute(type_, s, values); | |
1224 } | |
1225 | |
1226 public boolean isFastPath() { | |
1227 return true; | |
1228 } | |
1229 }; | |
1230 builder.tree(createGuardAndCast(group, type, currentLocals, executionFactory)); | |
1231 if (hasFallthrough(group, type, originalValues, true) || group.getSpecialization().isFallback()) { | |
1232 builder.startReturn().tree(createCallNext(type, originalValues)).end(); | |
1233 } | |
1234 } | |
1235 | |
1236 return executable; | |
1237 } | |
1238 | |
1239 private LocalVariable resolveShortCircuit(SpecializationData specialization, NodeExecutionData execution, LocalContext currentLocals) { | |
1240 LocalVariable shortCircuit = null; | |
1241 SpecializationData resolvedSpecialization = specialization; | |
1242 if (specialization == null) { | |
1243 resolvedSpecialization = node.getGenericSpecialization(); | |
1244 } | |
1245 | |
1246 if (execution.isShortCircuit()) { | |
1247 ShortCircuitData shortCircuitData = resolvedSpecialization.getShortCircuits().get(calculateShortCircuitIndex(execution)); | |
1248 CodeTree access = callTemplateMethod(CodeTreeBuilder.createBuilder(), accessParent(null), shortCircuitData, currentLocals); | |
1249 shortCircuit = currentLocals.createShortCircuitValue(execution).accessWith(access); | |
1250 } | |
1251 return shortCircuit; | |
1252 } | |
1253 | |
1254 private int calculateShortCircuitIndex(NodeExecutionData execution) { | |
1255 int shortCircuitIndex = 0; | |
1256 for (NodeExecutionData otherExectuion : node.getChildExecutions()) { | |
1257 if (otherExectuion.isShortCircuit()) { | |
1258 if (otherExectuion == execution) { | |
1259 break; | |
1260 } | |
1261 shortCircuitIndex++; | |
1262 } | |
1263 } | |
1264 return shortCircuitIndex; | |
1265 } | |
1266 | |
1267 private CodeTree createFastPathExecute(final TypeData forType, SpecializationData specialization, LocalContext currentValues) { | |
1268 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1269 int ifCount = 0; | |
1270 if (specialization.isFallback()) { | |
1271 builder.startIf().startCall("guardFallback"); | |
1272 if (node.isFrameUsedByAnyGuard(context)) { | |
1273 builder.string(FRAME_VALUE); | |
1274 } | |
1275 currentValues.addReferencesTo(builder); | |
1276 | |
1277 builder.end(); | |
1278 builder.end(); | |
1279 builder.startBlock(); | |
1280 ifCount++; | |
1281 } | |
1282 CodeTreeBuilder execute = builder.create(); | |
1283 execute.startReturn(); | |
1284 if (specialization.getMethod() == null) { | |
1285 execute.startCall("unsupported"); | |
1286 currentValues.addReferencesTo(execute, FRAME_VALUE); | |
1287 execute.end(); | |
1288 } else { | |
1289 execute.tree(callTemplateMethod(execute, accessParent(null), specialization, currentValues)); | |
1290 } | |
1291 execute.end(); | |
1292 builder.tree(createFastPathTryCatchRewriteException(specialization, forType, currentValues, execute.build())); | |
1293 | |
1294 builder.end(ifCount); | |
1295 return builder.build(); | |
1296 } | |
1297 | |
1298 private CodeTree createGuardAndCast(SpecializationGroup group, TypeData forType, LocalContext currentValues, SpecializationExecution execution) { | |
1299 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1300 | |
1301 Set<TypeGuard> castGuards; | |
1302 if (execution.isFastPath()) { | |
1303 castGuards = null; // cast all | |
1304 } else { | |
1305 castGuards = new HashSet<>(); | |
1306 for (TypeGuard castGuard : group.getTypeGuards()) { | |
1307 if (isTypeGuardUsedInAnyGuardBelow(group, currentValues, castGuard)) { | |
1308 castGuards.add(castGuard); | |
1309 } | |
1310 } | |
1311 } | |
1312 CodeTree[] checkAndCast = createTypeCheckAndCast(group.getTypeGuards(), castGuards, currentValues, execution); | |
1313 CodeTree check = checkAndCast[0]; | |
1314 CodeTree cast = checkAndCast[1]; | |
1315 | |
1316 List<GuardExpression> elseGuardExpressions = group.findElseConnectableGuards(); | |
1317 List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards()); | |
1318 guardExpressions.removeAll(elseGuardExpressions); | |
1319 CodeTree methodGuards = createMethodGuardCheck(guardExpressions, currentValues); | |
1320 | |
1321 if (!group.getAssumptions().isEmpty()) { | |
1322 if (execution.isFastPath() && !forType.isGeneric()) { | |
1323 cast = appendAssumptionFastPath(cast, group.getAssumptions(), forType, currentValues); | |
1324 } else { | |
1325 methodGuards = appendAssumptionSlowPath(methodGuards, group.getAssumptions()); | |
1326 } | |
1327 } | |
1328 | |
1329 int ifCount = 0; | |
1330 if (!check.isEmpty()) { | |
1331 builder.startIf(); | |
1332 builder.tree(check).end(); | |
1333 builder.startBlock(); | |
1334 ifCount++; | |
1335 } | |
1336 if (!cast.isEmpty()) { | |
1337 builder.tree(cast); | |
1338 } | |
1339 boolean elseIf = !elseGuardExpressions.isEmpty(); | |
1340 if (!methodGuards.isEmpty()) { | |
1341 builder.startIf(elseIf); | |
1342 builder.tree(methodGuards).end(); | |
1343 builder.startBlock(); | |
1344 ifCount++; | |
1345 } else if (elseIf) { | |
1346 builder.startElseBlock(); | |
1347 ifCount++; | |
1348 } | |
1349 | |
1350 boolean reachable = isReachableGroup(group, ifCount); | |
1351 if (reachable) { | |
1352 for (SpecializationGroup child : group.getChildren()) { | |
1353 builder.tree(createGuardAndCast(child, forType, currentValues.copy(), execution)); | |
1354 } | |
1355 SpecializationData specialization = group.getSpecialization(); | |
1356 if (specialization != null) { | |
1357 builder.tree(execution.createExecute(specialization, currentValues)); | |
1358 } | |
1359 } | |
1360 builder.end(ifCount); | |
1361 | |
1362 return builder.build(); | |
1363 } | |
1364 | |
1365 private static CodeTree appendAssumptionSlowPath(CodeTree methodGuards, List<String> assumptions) { | |
1366 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1367 | |
1368 builder.tree(methodGuards); | |
1369 String connect = methodGuards.isEmpty() ? "" : " && "; | |
1370 for (String assumption : assumptions) { | |
1371 builder.string(connect); | |
1372 builder.startCall(accessParent(assumptionName(assumption)), "isValid").end(); | |
1373 connect = " && "; | |
1374 } | |
1375 | |
1376 return builder.build(); | |
1377 } | |
1378 | |
1379 private CodeTree appendAssumptionFastPath(CodeTree casts, List<String> assumptions, TypeData forType, LocalContext currentValues) { | |
1380 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1381 builder.tree(casts); | |
1382 builder.startTryBlock(); | |
1383 for (String assumption : assumptions) { | |
1384 builder.startStatement().startCall(accessParent(assumptionName(assumption)), "check").end().end(); | |
1385 } | |
1386 builder.end().startCatchBlock(getType(InvalidAssumptionException.class), "ae"); | |
1387 builder.startReturn().tree(createCallNext(forType, currentValues)).end(); | |
1388 builder.end(); | |
1389 return builder.build(); | |
1390 } | |
1391 | |
1392 private static boolean isReachableGroup(SpecializationGroup group, int ifCount) { | |
1393 if (ifCount != 0) { | |
1394 return true; | |
1395 } | |
1396 SpecializationGroup previous = group.getPreviousGroup(); | |
1397 if (previous == null || previous.findElseConnectableGuards().isEmpty()) { | |
1398 return true; | |
1399 } | |
1400 | |
1401 /* | |
1402 * Hacky else case. In this case the specialization is not reachable due to previous else | |
1403 * branch. This is only true if the minimum state is not checked. | |
1404 */ | |
1405 if (previous.getGuards().size() == 1 && previous.getTypeGuards().isEmpty() && previous.getAssumptions().isEmpty() && | |
1406 (previous.getParent() == null || previous.getMaxSpecializationIndex() != previous.getParent().getMaxSpecializationIndex())) { | |
1407 return false; | |
1408 } | |
1409 | |
1410 return true; | |
1411 } | |
1412 | |
1413 private boolean isTypeGuardUsedInAnyGuardBelow(SpecializationGroup group, LocalContext currentValues, TypeGuard typeGuard) { | |
1414 NodeExecutionData execution = node.getChildExecutions().get(typeGuard.getSignatureIndex()); | |
1415 | |
1416 for (GuardExpression guard : group.getGuards()) { | |
1417 List<Parameter> guardParameters = guard.getResolvedGuard().findByExecutionData(execution); | |
1418 TypeData sourceType = currentValues.getValue(typeGuard.getSignatureIndex()).getType(); | |
1419 | |
1420 for (Parameter guardParameter : guardParameters) { | |
1421 if (sourceType.needsCastTo(guardParameter.getType())) { | |
1422 return true; | |
1423 } | |
1424 } | |
1425 } | |
1426 | |
1427 for (SpecializationGroup child : group.getChildren()) { | |
1428 if (isTypeGuardUsedInAnyGuardBelow(child, currentValues, typeGuard)) { | |
1429 return true; | |
1430 } | |
1431 } | |
1432 | |
1433 return false; | |
1434 } | |
1435 | |
1436 private CodeExecutableElement createExecuteChildMethod(NodeExecutionData execution, TypeData targetType) { | |
1437 LocalContext locals = LocalContext.load(this, 0); | |
1438 | |
1439 CodeExecutableElement method = locals.createMethod(modifiers(PROTECTED, FINAL), targetType.getPrimitiveType(), executeChildMethodName(execution, targetType), FRAME_VALUE); | |
1440 if (hasUnexpectedResult(execution, targetType)) { | |
1441 method.getThrownTypes().add(getType(UnexpectedResultException.class)); | |
1442 } | |
1443 | |
1444 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetType); | |
1445 if (implicitProfile != null) { | |
1446 method.addParameter(implicitProfile); | |
1447 } | |
1448 | |
1449 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { | |
1450 NodeExecutionData executeWith = node.getChildExecutions().get(i); | |
1451 LocalVariable var = locals.createValue(executeWith, genericType); | |
1452 method.addParameter(var.createParameter()); | |
1453 locals.setValue(executeWith, var); | |
1454 } | |
1455 | |
1456 CodeTreeBuilder builder = method.createBuilder(); | |
1457 CodeTree executeChild = createExecuteChild(execution, targetType, locals.createValue(execution, targetType), locals, true); | |
1458 if (executeChild.isSingleLine()) { | |
1459 builder.statement(executeChild); | |
1460 } else { | |
1461 builder.tree(executeChild); | |
1462 } | |
1463 return method; | |
1464 } | |
1465 | |
1466 private CodeVariableElement createImplicitProfileParameter(NodeExecutionData execution, TypeData targetType) { | |
1467 if (targetType.hasImplicitSourceTypes()) { | |
1468 switch (options.implicitCastOptimization()) { | |
1469 case NONE: | |
1470 return null; | |
1471 case DUPLICATE_TAIL: | |
1472 return new CodeVariableElement(getType(Class.class), implicitClassFieldName(execution)); | |
1473 case MERGE_CASTS: | |
1474 return new CodeVariableElement(ImplicitCastNodeFactory.type(targetType), implicitNodeFieldName(execution)); | |
1475 } | |
1476 } | |
1477 return null; | |
1478 } | |
1479 | |
1480 private boolean isExecuteChildShared(NodeExecutionData execution, TypeData targetType) { | |
1481 if (targetType.isVoid()) { | |
1482 return false; | |
1483 } else if (targetType.isGeneric()) { | |
1484 if (isSingleSpecializable(getReachableSpecializations())) { | |
1485 return false; | |
1486 } | |
1487 return findSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1; | |
1488 } else { | |
1489 if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) { | |
1490 return false; | |
1491 } | |
1492 if (!targetType.hasImplicitSourceTypes()) { | |
1493 return false; | |
1494 } | |
1495 | |
1496 int uses = 0; | |
1497 for (SpecializationData specialization : node.getSpecializations()) { | |
1498 List<Parameter> parameters = specialization.findByExecutionData(execution); | |
1499 for (Parameter parameter : parameters) { | |
1500 if (targetType.equals(parameter.getTypeSystemType())) { | |
1501 uses++; | |
1502 } | |
1503 } | |
1504 } | |
1505 if (uses > 1) { | |
1506 return findSpecializedExecutables(execution, targetType.getImplicitSourceTypes(), options.implicitTypeBoxingOptimization()).size() > 1; | |
1507 } else { | |
1508 return false; | |
1509 } | |
1510 } | |
1511 } | |
1512 | |
1513 private CodeTree createAssignExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable targetValue, LocalVariable shortCircuit, LocalContext currentValues) { | |
1514 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1515 boolean hasUnexpected = hasUnexpectedResult(execution, targetValue.getType()); | |
1516 | |
1517 CodeTree executeChild; | |
1518 if (isExecuteChildShared(execution, targetValue.getType())) { | |
1519 executeChild = createCallSharedExecuteChild(execution, targetValue, currentValues); | |
1520 } else { | |
1521 executeChild = createExecuteChild(execution, targetValue.getType(), targetValue, currentValues, false); | |
1522 } | |
1523 | |
1524 builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected)); | |
1525 builder.end(); | |
1526 if (hasUnexpected) { | |
1527 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
1528 | |
1529 LocalContext slowPathValues = currentValues.copy(); | |
1530 slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); | |
1531 boolean found = false; | |
1532 for (NodeExecutionData otherExecution : node.getChildExecutions()) { | |
1533 if (found) { | |
1534 LocalVariable childEvaluatedValue = slowPathValues.createValue(otherExecution, genericType); | |
1535 LocalVariable genericShortCircuit = resolveShortCircuit(null, otherExecution, slowPathValues); | |
1536 builder.tree(createAssignExecuteChild(otherExecution, genericType, childEvaluatedValue, genericShortCircuit, slowPathValues)); | |
1537 slowPathValues.setValue(otherExecution, childEvaluatedValue); | |
1538 } else { | |
1539 // skip forward already evaluated | |
1540 found = execution == otherExecution; | |
1541 } | |
1542 } | |
1543 builder.startReturn().tree(createCallNext(returnType, slowPathValues)).end(); | |
1544 builder.end(); | |
1545 } | |
1546 | |
1547 if (shortCircuit != null) { | |
1548 currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null)); | |
1549 } | |
1550 return createShortCircuit(targetValue, shortCircuit, builder.build()); | |
1551 } | |
1552 | |
1553 private static CodeTree createShortCircuit(LocalVariable targetValue, LocalVariable shortCircuitValue, CodeTree tryExecute) { | |
1554 if (shortCircuitValue == null) { | |
1555 return tryExecute; | |
1556 } | |
1557 | |
1558 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1559 | |
1560 builder.tree(shortCircuitValue.createDeclaration(shortCircuitValue.createReference())); | |
1561 builder.tree(targetValue.createDeclaration(builder.create().defaultValue(targetValue.getTypeMirror()).build())); | |
1562 | |
1563 builder.startIf().string(shortCircuitValue.getName()).end().startBlock(); | |
1564 builder.tree(tryExecute); | |
1565 builder.end(); | |
1566 | |
1567 return builder.build(); | |
1568 } | |
1569 | |
1570 private static CodeTree createTryExecuteChild(LocalVariable value, CodeTree executeChild, boolean needDeclaration, boolean hasTry) { | |
1571 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1572 boolean hasDeclaration = false; | |
1573 if ((hasTry || !executeChild.isSingleLine()) && needDeclaration) { | |
1574 builder.tree(value.createDeclaration(null)); | |
1575 hasDeclaration = true; | |
1576 } | |
1577 | |
1578 if (hasTry) { | |
1579 builder.startTryBlock(); | |
1580 } else { | |
1581 builder.startGroup(); | |
1582 } | |
1583 | |
1584 if (executeChild.isSingleLine()) { | |
1585 builder.startStatement(); | |
1586 if (hasDeclaration || !needDeclaration) { | |
1587 builder.tree(executeChild); | |
1588 } else { | |
1589 builder.type(value.getTypeMirror()).string(" ").tree(executeChild); | |
1590 } | |
1591 builder.end(); | |
1592 } else { | |
1593 builder.tree(executeChild); | |
1594 } | |
1595 | |
1596 builder.end(); | |
1597 | |
1598 return builder.build(); | |
1599 } | |
1600 | |
1601 private CodeTree createCallSharedExecuteChild(NodeExecutionData execution, LocalVariable targetValue, LocalContext currentValues) { | |
1602 if (!isExecuteChildShared(execution, targetValue.getType())) { | |
1603 throw new AssertionError("Execute child not shared with method but called."); | |
1604 } | |
1605 | |
1606 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1607 builder.tree(targetValue.createReference()).string(" = "); | |
1608 if (targetValue.getType().isGeneric()) { | |
1609 builder.startCall("root", executeChildMethodName(execution, targetValue.getType())); | |
1610 } else { | |
1611 builder.startCall(executeChildMethodName(execution, targetValue.getType())); | |
1612 } | |
1613 builder.string(FRAME_VALUE); | |
1614 | |
1615 CodeVariableElement implicitProfile = createImplicitProfileParameter(execution, targetValue.getType()); | |
1616 if (implicitProfile != null) { | |
1617 builder.string(implicitProfile.getName()); | |
1618 } | |
1619 for (int i = 0; i < execution.getChild().getExecuteWith().size(); i++) { | |
1620 builder.tree(currentValues.getValue(i).createReference()); | |
1621 } | |
1622 builder.end(); | |
1623 return builder.build(); | |
1624 } | |
1625 | |
1626 private CodeTree createExecuteChild(NodeExecutionData execution, TypeData returnType, LocalVariable target, LocalContext currentValues, boolean shared) { | |
1627 final CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1628 final ExecutableTypeData executableType = findSpecializedExecutableType(execution, target.getType()); | |
1629 | |
1630 CodeTree assignment = createAssignmentStart(target, shared, false); | |
1631 | |
1632 if (executableType == null) { | |
1633 if (target.getType().isGeneric()) { | |
1634 throw new AssertionError("Should be caught by the parser."); | |
1635 } | |
1636 CodeTree genericExecute = createExecuteChild(execution, returnType, target.makeGeneric(), currentValues, shared); | |
1637 builder.tree(genericExecute); | |
1638 } else { | |
1639 if (target.getType().isGeneric() && executableType.getEvaluatedCount() == 0) { | |
1640 return createPolymorphicExecuteChild(execution, target, currentValues, shared); | |
1641 } else if (target.getType().hasImplicitSourceTypes()) { | |
1642 if (options.implicitCastOptimization().isNone()) { | |
1643 CodeTree execute = createCallSharedExecuteChild(execution, target.makeGeneric(), currentValues); | |
1644 return TypeSystemCodeGenerator.implicitExpect(target.getType(), execute, null); | |
1645 } else if (options.implicitCastOptimization().isDuplicateTail()) { | |
1646 builder.tree(createExecuteChildDuplicateTail(builder, execution, assignment, target, currentValues)); | |
1647 } else if (options.implicitCastOptimization().isMergeCasts()) { | |
1648 // TODO | |
1649 } else { | |
1650 throw new AssertionError(); | |
1651 } | |
1652 } else { | |
1653 builder.tree(assignment); | |
1654 | |
1655 CodeTree accessChild; | |
1656 if (shared && target.getType().isGeneric()) { | |
1657 accessChild = CodeTreeBuilder.singleString(nodeFieldName(execution)); | |
1658 } else { | |
1659 accessChild = accessParent(nodeFieldName(execution)); | |
1660 } | |
1661 | |
1662 CodeTree execute = callTemplateMethod(builder, accessChild, executableType, currentValues); | |
1663 CodeTree expect = TypeSystemCodeGenerator.expect(executableType.getType(), returnType, execute); | |
1664 builder.tree(expect); | |
1665 } | |
1666 } | |
1667 return builder.build(); | |
1668 } | |
1669 | |
1670 private CodeTree createPolymorphicExecuteChild(NodeExecutionData execution, LocalVariable target, LocalContext currentValues, boolean shared) throws AssertionError { | |
1671 ExecutableTypeData genericExecutableType = execution.getChild().getNodeData().findAnyGenericExecutableType(context, execution.getChild().getExecuteWith().size()); | |
1672 if (genericExecutableType == null) { | |
1673 throw new AssertionError("error should be caught by the parser"); | |
1674 } | |
1675 | |
1676 CodeTree assignment = createAssignmentStart(target, shared, true); | |
1677 | |
1678 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1679 CodeTreeBuilder polyChainBuilder = builder.create(); | |
1680 boolean hasUnexpectedResult = false; | |
1681 | |
1682 Set<TypeData> specializedTypes = new HashSet<>(); | |
1683 for (TypeData type : node.findSpecializedTypes(execution)) { | |
1684 specializedTypes.addAll(type.getImplicitSourceTypes()); | |
1685 } | |
1686 | |
1687 List<ExecutableTypeData> specializedExecutables = findSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); | |
1688 | |
1689 Collections.sort(specializedExecutables, new Comparator<ExecutableTypeData>() { | |
1690 public int compare(ExecutableTypeData o1, ExecutableTypeData o2) { | |
1691 return o1.getType().compareTo(o2.getType()); | |
1692 } | |
1693 }); | |
1694 | |
1695 if (isSingleSpecializable(getReachableSpecializations())) { | |
1696 specializedExecutables = Collections.emptyList(); | |
1697 } | |
1698 | |
1699 boolean hasSpecializedTypes = false; | |
1700 for (ExecutableTypeData executableType : specializedExecutables) { | |
1701 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); | |
1702 polyChainBuilder.tree(createAccessPolymorphicField(execution, shared)); | |
1703 polyChainBuilder.string(" == ").typeLiteral(executableType.getType().getPrimitiveType()); | |
1704 polyChainBuilder.end(); | |
1705 polyChainBuilder.startBlock(); | |
1706 polyChainBuilder.startStatement(); | |
1707 polyChainBuilder.tree(assignment); | |
1708 polyChainBuilder.tree(callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), executableType, currentValues)).end(); | |
1709 polyChainBuilder.end(); | |
1710 hasUnexpectedResult |= executableType.hasUnexpectedValue(context); | |
1711 } | |
1712 | |
1713 CodeTree executeGeneric = callTemplateMethod(polyChainBuilder, CodeTreeBuilder.singleString(nodeFieldName(execution)), genericExecutableType, currentValues); | |
1714 | |
1715 if (specializedExecutables.isEmpty()) { | |
1716 builder.tree(assignment); | |
1717 builder.tree(executeGeneric); | |
1718 } else { | |
1719 CodeTree accessPolymorphicProfile = createAccessPolymorphicField(execution, shared); | |
1720 polyChainBuilder.startElseIf().tree(accessPolymorphicProfile).string(" == null").end(); | |
1721 polyChainBuilder.startBlock(); | |
1722 polyChainBuilder.tree(createTransferToInterpreterAndInvalidate()); | |
1723 polyChainBuilder.declaration(genericExecutableType.getType().getPrimitiveType(), "value_", executeGeneric); | |
1724 | |
1725 hasSpecializedTypes = false; | |
1726 for (ExecutableTypeData executableType : specializedExecutables) { | |
1727 hasSpecializedTypes = polyChainBuilder.startIf(hasSpecializedTypes); | |
1728 polyChainBuilder.tree(TypeSystemCodeGenerator.check(executableType.getType(), CodeTreeBuilder.singleString("value_"))); | |
1729 polyChainBuilder.end(); | |
1730 polyChainBuilder.startBlock(); | |
1731 polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(executableType.getType().getPrimitiveType()).end(); | |
1732 polyChainBuilder.end(); | |
1733 } | |
1734 | |
1735 polyChainBuilder.startElseBlock(); | |
1736 polyChainBuilder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); | |
1737 polyChainBuilder.end(); | |
1738 | |
1739 polyChainBuilder.startReturn().string("value_").end(); | |
1740 | |
1741 polyChainBuilder.end(); | |
1742 polyChainBuilder.startElseBlock(); | |
1743 polyChainBuilder.startStatement().tree(assignment).tree(executeGeneric).end(); | |
1744 polyChainBuilder.end(); | |
1745 | |
1746 if (hasUnexpectedResult) { | |
1747 builder.startTryBlock(); | |
1748 } | |
1749 | |
1750 builder.tree(polyChainBuilder.build()); | |
1751 | |
1752 if (hasUnexpectedResult) { | |
1753 builder.end(); | |
1754 builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); | |
1755 builder.startStatement().tree(accessPolymorphicProfile).string(" = ").typeLiteral(genericType.getPrimitiveType()).end(); | |
1756 builder.startReturn().string("ex.getResult()").end(); | |
1757 builder.end(); | |
1758 } | |
1759 } | |
1760 return builder.build(); | |
1761 } | |
1762 | |
1763 private static CodeTree createAssignmentStart(LocalVariable target, boolean shared, boolean accessParent) { | |
1764 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1765 if (shared) { | |
1766 builder.string("return "); | |
1767 } else { | |
1768 builder.string(target.getName()).string(" = "); | |
1769 if (accessParent) { | |
1770 builder.tree(accessParent(null)).string("."); | |
1771 } | |
1772 } | |
1773 return builder.build(); | |
1774 } | |
1775 | |
1776 private static CodeTree createAccessPolymorphicField(NodeExecutionData execution, boolean shared) { | |
1777 String name = polymorphicTypeProfileFieldName(execution); | |
1778 if (shared) { | |
1779 return CodeTreeBuilder.singleString(name); | |
1780 } else { | |
1781 return accessParent(name); | |
1782 } | |
1783 } | |
1784 | |
1785 private CodeTree createExecuteChildDuplicateTail(CodeTreeBuilder parent, NodeExecutionData execution, CodeTree assignment, LocalVariable target, LocalContext currentValues) { | |
1786 CodeTreeBuilder builder = parent.create(); | |
1787 List<TypeData> sourceTypes = target.getType().getImplicitSourceTypes(); | |
1788 String implicitClassFieldName = implicitClassFieldName(execution); | |
1789 String nodeFieldName = nodeFieldName(execution); | |
1790 List<ExecutableTypeData> executableTypes = findSpecializedExecutables(execution, sourceTypes, options.implicitTypeBoxingOptimization()); | |
1791 | |
1792 boolean elseIf = false; | |
1793 for (ExecutableTypeData executableType : executableTypes) { | |
1794 elseIf = builder.startIf(elseIf); | |
1795 builder.string(implicitClassFieldName).string(" == ").typeLiteral(executableType.getType().getBoxedType()); | |
1796 builder.end(); | |
1797 builder.startBlock(); | |
1798 builder.startStatement().tree(assignment); | |
1799 | |
1800 CodeTree execute = callTemplateMethod(builder, accessParent(nodeFieldName), executableType, currentValues); | |
1801 ImplicitCastData cast = typeSystem.lookupCast(executableType.getType(), target.getType()); | |
1802 if (cast != null) { | |
1803 execute = callTemplateMethod(builder, null, cast, execute); | |
1804 } | |
1805 builder.tree(execute); | |
1806 builder.end(); | |
1807 builder.end(); | |
1808 } | |
1809 | |
1810 if (!executableTypes.isEmpty()) { | |
1811 builder.startElseBlock(); | |
1812 } | |
1813 | |
1814 LocalVariable genericValue = target.makeGeneric().nextName(); | |
1815 LocalVariable genericShortCircuit = resolveShortCircuit(null, execution, currentValues); | |
1816 | |
1817 builder.tree(createAssignExecuteChild(execution, genericValue.getType(), genericValue, genericShortCircuit, currentValues)); | |
1818 if (executableTypes.size() == sourceTypes.size()) { | |
1819 builder.startThrow().startNew(getType(UnexpectedResultException.class)).tree(genericValue.createReference()).end().end(); | |
1820 } else { | |
1821 builder.startStatement().tree(assignment); | |
1822 builder.tree(TypeSystemCodeGenerator.implicitExpect(target.getType(), genericValue.createReference(), implicitClassFieldName)); | |
1823 builder.end(); | |
1824 } | |
1825 | |
1826 if (!executableTypes.isEmpty()) { | |
1827 builder.end(); | |
1828 } | |
1829 return builder.build(); | |
1830 } | |
1831 | |
1832 private static CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) { | |
1833 if (specialization.getExceptions().isEmpty()) { | |
1834 return execution; | |
1835 } | |
1836 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1837 builder.startTryBlock(); | |
1838 builder.tree(execution); | |
1839 TypeMirror[] exceptionTypes = new TypeMirror[specialization.getExceptions().size()]; | |
1840 for (int i = 0; i < exceptionTypes.length; i++) { | |
1841 exceptionTypes[i] = specialization.getExceptions().get(i).getJavaClass(); | |
1842 } | |
1843 builder.end().startCatchBlock(exceptionTypes, "ex"); | |
1844 builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end(); | |
1845 builder.startReturn(); | |
1846 builder.tree(createCallDelegate("remove", "threw rewrite exception", forType, currentValues)); | |
1847 builder.end(); | |
1848 builder.end(); | |
1849 return builder.build(); | |
1850 } | |
1851 | |
1852 private static CodeTree createMethodGuardCheck(List<GuardExpression> guardExpressions, LocalContext currentValues) { | |
1853 CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); | |
1854 String and = ""; | |
1855 for (GuardExpression guard : guardExpressions) { | |
1856 builder.string(and); | |
1857 if (guard.isNegated()) { | |
1858 builder.string("!"); | |
1859 } | |
1860 builder.tree(callTemplateMethod(builder, accessParent(null), guard.getResolvedGuard(), currentValues)); | |
1861 and = " && "; | |
1862 } | |
1863 return builder.build(); | |
1864 } | |
1865 | |
1866 private CodeTree[] createTypeCheckAndCast(List<TypeGuard> typeGuards, Set<TypeGuard> castGuards, LocalContext currentValues, SpecializationExecution specializationExecution) { | |
1867 CodeTreeBuilder checksBuilder = CodeTreeBuilder.createBuilder(); | |
1868 CodeTreeBuilder castsBuilder = CodeTreeBuilder.createBuilder(); | |
1869 for (TypeGuard typeGuard : typeGuards) { | |
1870 int signatureIndex = typeGuard.getSignatureIndex(); | |
1871 LocalVariable value = currentValues.getValue(signatureIndex); | |
1872 TypeData targetType = typeGuard.getType(); | |
1873 if (!value.getType().needsCastTo(targetType)) { | |
1874 continue; | |
1875 } | |
1876 NodeExecutionData execution = node.getChildExecutions().get(signatureIndex); | |
1877 if (!checksBuilder.isEmpty()) { | |
1878 checksBuilder.string(" && "); | |
1879 } | |
1880 | |
1881 CodeTreeBuilder checkBuilder = checksBuilder.create(); | |
1882 CodeTreeBuilder castBuilder = checksBuilder.create(); | |
1883 | |
1884 LocalVariable shortCircuit = currentValues.getShortCircuit(execution); | |
1885 if (shortCircuit != null) { | |
1886 checkBuilder.string("("); | |
1887 CodeTreeBuilder referenceBuilder = checkBuilder.create(); | |
1888 if (!shortCircuit.getType().isPrimitive()) { | |
1889 referenceBuilder.string("(boolean) "); | |
1890 } | |
1891 referenceBuilder.tree(shortCircuit.createReference()); | |
1892 checkBuilder.string("!").tree(referenceBuilder.build()); | |
1893 checkBuilder.string(" || "); | |
1894 castBuilder.tree(referenceBuilder.build()).string(" ? "); | |
1895 } | |
1896 | |
1897 List<ImplicitCastData> sourceTypes = typeSystem.lookupByTargetType(targetType); | |
1898 CodeTree valueReference = value.createReference(); | |
1899 if (sourceTypes.isEmpty()) { | |
1900 checkBuilder.tree(TypeSystemCodeGenerator.check(targetType, value.createReference())); | |
1901 castBuilder.tree(TypeSystemCodeGenerator.cast(targetType, valueReference)); | |
1902 } else { | |
1903 ImplicitCastOptimization opt = options.implicitCastOptimization(); | |
1904 if (specializationExecution.isFastPath() && !opt.isNone()) { | |
1905 if (opt.isDuplicateTail()) { | |
1906 String typeHintField = implicitClassFieldName(execution); | |
1907 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, typeHintField)); | |
1908 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, typeHintField)); | |
1909 } else if (opt.isMergeCasts()) { | |
1910 checkBuilder.tree(ImplicitCastNodeFactory.check(implicitNodeFieldName(execution), valueReference)); | |
1911 castBuilder.tree(ImplicitCastNodeFactory.cast(implicitNodeFieldName(execution), valueReference)); | |
1912 } else { | |
1913 throw new AssertionError("implicit cast opt"); | |
1914 } | |
1915 } else { | |
1916 checkBuilder.tree(TypeSystemCodeGenerator.implicitCheck(targetType, valueReference, null)); | |
1917 castBuilder.tree(TypeSystemCodeGenerator.implicitCast(targetType, valueReference, null)); | |
1918 } | |
1919 } | |
1920 | |
1921 if (shortCircuit != null) { | |
1922 checkBuilder.string(")"); | |
1923 castBuilder.string(" : ").defaultValue(targetType.getPrimitiveType()); | |
1924 } | |
1925 | |
1926 if (castGuards == null || castGuards.contains(typeGuard)) { | |
1927 LocalVariable castVariable = currentValues.getValue(execution).nextName().newType(typeGuard.getType()).accessWith(null); | |
1928 currentValues.setValue(execution, castVariable); | |
1929 castsBuilder.tree(castVariable.createDeclaration(castBuilder.build())); | |
1930 } | |
1931 | |
1932 checksBuilder.tree(checkBuilder.build()); | |
1933 } | |
1934 return new CodeTree[]{checksBuilder.build(), castsBuilder.build()}; | |
1935 } | |
1936 | |
1937 public static final class LocalContext { | |
1938 | |
1939 private final NodeGenFactory factory; | |
1940 private final Map<String, LocalVariable> values = new HashMap<>(); | |
1941 | |
1942 private LocalContext(NodeGenFactory factory) { | |
1943 this.factory = factory; | |
1944 } | |
1945 | |
1946 public CodeExecutableElement createMethod(Set<Modifier> modifiers, TypeMirror returnType, String name, String... optionalArguments) { | |
1947 CodeExecutableElement method = new CodeExecutableElement(modifiers, returnType, name); | |
1948 addParametersTo(method, optionalArguments); | |
1949 return method; | |
1950 } | |
1951 | |
1952 public static LocalContext load(NodeGenFactory factory, int signatureSize) { | |
1953 LocalContext context = new LocalContext(factory); | |
1954 context.loadValues(signatureSize); | |
1955 return context; | |
1956 } | |
1957 | |
1958 public static LocalContext load(NodeGenFactory factory) { | |
1959 return load(factory, factory.node.getSignatureSize()); | |
1960 } | |
1961 | |
1962 public LocalContext copy() { | |
1963 LocalContext copy = new LocalContext(factory); | |
1964 copy.values.putAll(values); | |
1965 return copy; | |
1966 } | |
1967 | |
1968 private static String fieldValueName(NodeFieldData field) { | |
1969 return field.getName() + "Value"; | |
1970 } | |
1971 | |
1972 @SuppressWarnings("static-method") | |
1973 public LocalVariable createValue(NodeExecutionData execution, TypeData type) { | |
1974 return new LocalVariable(type, type.getPrimitiveType(), valueName(execution), null); | |
1975 } | |
1976 | |
1977 public LocalVariable createShortCircuitValue(NodeExecutionData execution) { | |
1978 return new LocalVariable(factory.typeSystem.getBooleanType(), factory.getType(boolean.class), shortCircuitName(execution), null); | |
1979 } | |
1980 | |
1981 private static String valueName(NodeExecutionData execution) { | |
1982 return execution.getName() + "Value"; | |
1983 } | |
1984 | |
1985 private static String shortCircuitName(NodeExecutionData execution) { | |
1986 return "has" + ElementUtils.firstLetterUpperCase(valueName(execution)); | |
1987 } | |
1988 | |
1989 public LocalVariable get(String id) { | |
1990 return values.get(id); | |
1991 } | |
1992 | |
1993 public LocalVariable get(Parameter parameter, int signatureIndex) { | |
1994 LocalVariable var = get(parameter.getLocalName()); | |
1995 if (var == null && parameter.getSpecification().isSignature()) { | |
1996 // lookup by signature index for executeWith | |
1997 NodeExecutionData execution = factory.node.getChildExecutions().get(signatureIndex); | |
1998 var = getValue(execution); | |
1999 } | |
2000 return var; | |
2001 } | |
2002 | |
2003 public LocalVariable getValue(NodeExecutionData execution) { | |
2004 return get(valueName(execution)); | |
2005 } | |
2006 | |
2007 public LocalVariable getValue(int signatureIndex) { | |
2008 return getValue(factory.node.getChildExecutions().get(signatureIndex)); | |
2009 } | |
2010 | |
2011 public void removeValue(String id) { | |
2012 values.remove(id); | |
2013 } | |
2014 | |
2015 public void setValue(NodeExecutionData execution, LocalVariable var) { | |
2016 values.put(valueName(execution), var); | |
2017 } | |
2018 | |
2019 public void setShortCircuitValue(NodeExecutionData execution, LocalVariable var) { | |
2020 if (var == null) { | |
2021 return; | |
2022 } | |
2023 values.put(shortCircuitName(execution), var); | |
2024 } | |
2025 | |
2026 private boolean needsVarargs(boolean requireLoaded) { | |
2027 int size = 0; | |
2028 for (NodeExecutionData execution : factory.node.getChildExecutions()) { | |
2029 if (requireLoaded && getValue(execution) == null) { | |
2030 continue; | |
2031 } | |
2032 if (execution.isShortCircuit()) { | |
2033 size += 2; | |
2034 } else { | |
2035 size++; | |
2036 } | |
2037 } | |
2038 return size > 4; | |
2039 } | |
2040 | |
2041 private void loadValues(int evaluatedArguments) { | |
2042 values.put(FRAME_VALUE, new LocalVariable(null, factory.getType(VirtualFrame.class), FRAME_VALUE, null)); | |
2043 | |
2044 for (NodeFieldData field : factory.node.getFields()) { | |
2045 String fieldName = fieldValueName(field); | |
2046 values.put(fieldName, new LocalVariable(null, field.getType(), fieldName, NodeGenFactory.accessParent(field.getName()))); | |
2047 } | |
2048 | |
2049 boolean varargs = needsVarargs(false); | |
2050 for (int i = 0; i < evaluatedArguments; i++) { | |
2051 NodeExecutionData execution = factory.node.getChildExecutions().get(i); | |
2052 if (execution.isShortCircuit()) { | |
2053 LocalVariable shortCircuit = createShortCircuitValue(execution).makeGeneric(); | |
2054 if (varargs) { | |
2055 shortCircuit = shortCircuit.accessWith(createReadVarargs(i)); | |
2056 } | |
2057 values.put(shortCircuit.getName(), shortCircuit); | |
2058 } | |
2059 LocalVariable value = createValue(execution, factory.genericType); | |
2060 if (varargs) { | |
2061 value = value.accessWith(createReadVarargs(i)); | |
2062 } | |
2063 values.put(value.getName(), value); | |
2064 } | |
2065 } | |
2066 | |
2067 private static CodeTree createReadVarargs(int i) { | |
2068 return CodeTreeBuilder.createBuilder().string("args_[").string(String.valueOf(i)).string("]").build(); | |
2069 } | |
2070 | |
2071 public void addReferencesTo(CodeTreeBuilder builder, String... optionalNames) { | |
2072 for (String var : optionalNames) { | |
2073 LocalVariable local = values.get(var); | |
2074 if (local == null) { | |
2075 builder.nullLiteral(); | |
2076 } else { | |
2077 builder.tree(local.createReference()); | |
2078 } | |
2079 } | |
2080 | |
2081 List<NodeExecutionData> executions = factory.node.getChildExecutions(); | |
2082 for (NodeExecutionData execution : executions) { | |
2083 if (execution.isShortCircuit()) { | |
2084 LocalVariable shortCircuitVar = getShortCircuit(execution); | |
2085 if (shortCircuitVar != null) { | |
2086 builder.tree(shortCircuitVar.createReference()); | |
2087 } | |
2088 } | |
2089 LocalVariable var = getValue(execution); | |
2090 if (var != null) { | |
2091 builder.startGroup(); | |
2092 if (executions.size() == 1 && ElementUtils.typeEquals(var.getTypeMirror(), factory.getType(Object[].class))) { | |
2093 // if the current type is Object[] do not use varargs for a single argument | |
2094 builder.string("(Object) "); | |
2095 } | |
2096 builder.tree(var.createReference()); | |
2097 builder.end(); | |
2098 } | |
2099 } | |
2100 } | |
2101 | |
2102 public void addParametersTo(CodeExecutableElement method, String... optionalNames) { | |
2103 for (String var : optionalNames) { | |
2104 LocalVariable local = values.get(var); | |
2105 if (local != null) { | |
2106 method.addParameter(local.createParameter()); | |
2107 } | |
2108 } | |
2109 if (needsVarargs(true)) { | |
2110 method.addParameter(new CodeVariableElement(factory.getType(Object[].class), "args_")); | |
2111 method.setVarArgs(true); | |
2112 } else { | |
2113 for (NodeExecutionData execution : factory.node.getChildExecutions()) { | |
2114 if (execution.isShortCircuit()) { | |
2115 LocalVariable shortCircuitVar = getShortCircuit(execution); | |
2116 if (shortCircuitVar != null) { | |
2117 method.addParameter(shortCircuitVar.createParameter()); | |
2118 } | |
2119 } | |
2120 | |
2121 LocalVariable var = getValue(execution); | |
2122 if (var != null) { | |
2123 method.addParameter(var.createParameter()); | |
2124 } | |
2125 } | |
2126 } | |
2127 } | |
2128 | |
2129 private LocalVariable getShortCircuit(NodeExecutionData execution) { | |
2130 return values.get(shortCircuitName(execution)); | |
2131 } | |
2132 | |
2133 } | |
2134 | |
2135 public final static class LocalVariable { | |
2136 | |
2137 private final TypeData type; | |
2138 private final TypeMirror typeMirror; | |
2139 private final CodeTree accessorTree; | |
2140 private final String name; | |
2141 | |
2142 public static LocalVariable fromParameter(Parameter parameter) { | |
2143 NodeExecutionData execution = parameter.getSpecification().getExecution(); | |
2144 String name = null; | |
2145 if (execution == null) { | |
2146 name = parameter.getLocalName(); | |
2147 } else { | |
2148 name = createName(execution); | |
2149 } | |
2150 return new LocalVariable(parameter.getTypeSystemType(), parameter.getType(), name, null); | |
2151 } | |
2152 | |
2153 private LocalVariable(TypeData type, TypeMirror typeMirror, String name, CodeTree accessorTree) { | |
2154 Objects.requireNonNull(typeMirror); | |
2155 this.typeMirror = typeMirror; | |
2156 this.accessorTree = accessorTree; | |
2157 this.type = type; | |
2158 this.name = name; | |
2159 } | |
2160 | |
2161 public TypeData getType() { | |
2162 return type; | |
2163 } | |
2164 | |
2165 public String getShortCircuitName() { | |
2166 return "has" + ElementUtils.firstLetterUpperCase(getName()); | |
2167 } | |
2168 | |
2169 public String getName() { | |
2170 return name; | |
2171 } | |
2172 | |
2173 private static String createNextName(String name) { | |
2174 return name + "_"; | |
2175 } | |
2176 | |
2177 private static String createName(NodeExecutionData execution) { | |
2178 if (execution == null) { | |
2179 return "<error>"; | |
2180 } | |
2181 return execution.getName() + "Value"; | |
2182 } | |
2183 | |
2184 public TypeMirror getTypeMirror() { | |
2185 return typeMirror; | |
2186 } | |
2187 | |
2188 public CodeVariableElement createParameter() { | |
2189 return new CodeVariableElement(getTypeMirror(), getName()); | |
2190 } | |
2191 | |
2192 public CodeTree createDeclaration(CodeTree init) { | |
2193 return CodeTreeBuilder.createBuilder().declaration(getTypeMirror(), getName(), init).build(); | |
2194 } | |
2195 | |
2196 public CodeTree createReference() { | |
2197 if (accessorTree != null) { | |
2198 return accessorTree; | |
2199 } else { | |
2200 return CodeTreeBuilder.singleString(getName()); | |
2201 } | |
2202 } | |
2203 | |
2204 public LocalVariable newType(TypeData newType) { | |
2205 return new LocalVariable(newType, newType.getPrimitiveType(), name, accessorTree); | |
2206 } | |
2207 | |
2208 public final LocalVariable accessWith(CodeTree tree) { | |
2209 return new LocalVariable(type, typeMirror, name, tree); | |
2210 } | |
2211 | |
2212 public final LocalVariable nextName() { | |
2213 return new LocalVariable(type, typeMirror, createNextName(name), accessorTree); | |
2214 } | |
2215 | |
2216 public final LocalVariable makeGeneric() { | |
2217 return newType(type.getTypeSystem().getGenericTypeData()); | |
2218 } | |
2219 | |
2220 } | |
2221 | |
2222 private interface SpecializationExecution { | |
2223 | |
2224 boolean isFastPath(); | |
2225 | |
2226 CodeTree createExecute(SpecializationData specialization, LocalContext currentValues); | |
2227 | |
2228 } | |
2229 | |
2230 } |