Mercurial > hg > truffle
diff graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java @ 11545:2fb276f5e3e9
Truffle-DSL: implemented implicit casts.
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Fri, 06 Sep 2013 16:16:40 +0200 |
parents | dcaf879d4a7e |
children | 5d5007c9a5aa |
line wrap: on
line diff
--- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Fri Sep 06 16:11:15 2013 +0200 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/node/NodeCodeGenerator.java Fri Sep 06 16:16:40 2013 +0200 @@ -62,12 +62,17 @@ return node.getNodeId() + "Factory"; } + private static String nodeCastClassName(NodeData node, TypeData type) { + String nodeid = resolveNodeId(node); + if (type == null) { + return nodeid + "ImplicitCast"; + } else { + return Utils.firstLetterUpperCase(Utils.getSimpleName(type.getPrimitiveType())) + "Cast"; + } + } + private static String nodeSpecializationClassName(SpecializationData specialization) { - String nodeid = specialization.getNode().getNodeId(); - if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { - nodeid = nodeid.substring(0, nodeid.length() - 4); - } - + String nodeid = resolveNodeId(specialization.getNode()); String name = Utils.firstLetterUpperCase(nodeid); name += Utils.firstLetterUpperCase(specialization.getId()); name += "Node"; @@ -75,10 +80,7 @@ } private static String nodePolymorphicClassName(NodeData node, SpecializationData specialization) { - String nodeid = node.getNodeId(); - if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { - nodeid = nodeid.substring(0, nodeid.length() - 4); - } + String nodeid = resolveNodeId(node); String name = Utils.firstLetterUpperCase(nodeid); if (specialization == node.getGenericPolymorphicSpecialization()) { @@ -89,10 +91,22 @@ return name; } + private static String resolveNodeId(NodeData node) { + String nodeid = node.getNodeId(); + if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { + nodeid = nodeid.substring(0, nodeid.length() - 4); + } + return nodeid; + } + private static String valueNameEvaluated(ActualParameter targetParameter) { return valueName(targetParameter) + "Evaluated"; } + private static String typeName(ActualParameter param) { + return param.getLocalName() + "Type"; + } + private static String valueName(ActualParameter param) { return param.getLocalName(); } @@ -147,7 +161,8 @@ } } - private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit) { + private void addInternalValueParameterNames(CodeTreeBuilder builder, TemplateMethod source, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeImplicit, + Map<String, String> customNames) { if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { builder.string("frameValue"); } @@ -166,7 +181,9 @@ ActualParameter sourceParameter = source.findParameter(parameter.getLocalName()); - if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { + if (customNames != null && customNames.containsKey(parameter.getLocalName())) { + builder.string(customNames.get(parameter.getLocalName())); + } else if (unexpectedValueName != null && parameter.getLocalName().equals(unexpectedValueName)) { builder.cast(parameter.getType(), CodeTreeBuilder.singleString("ex.getResult()")); } else if (sourceParameter != null) { builder.string(valueName(sourceParameter, parameter)); @@ -298,10 +315,7 @@ } private static String baseClassName(NodeData node) { - String nodeid = node.getNodeId(); - if (nodeid.endsWith("Node") && !nodeid.equals("Node")) { - nodeid = nodeid.substring(0, nodeid.length() - 4); - } + String nodeid = resolveNodeId(node); String name = Utils.firstLetterUpperCase(nodeid); name += "BaseNode"; return name; @@ -362,7 +376,7 @@ builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)); builder.startCall("createInfo0"); builder.doubleQuote("Unsupported values"); - addInternalValueParameterNames(builder, current, current, null, false, true); + addInternalValueParameterNames(builder, current, current, null, false, true, null); builder.end().end().end(); } @@ -422,7 +436,11 @@ } @Override + @SuppressWarnings("unchecked") protected void createChildren(NodeData node) { + List<CodeTypeElement> casts = new ArrayList<>(getElement().getEnclosedElements()); + getElement().getEnclosedElements().clear(); + Map<NodeData, List<TypeElement>> childTypes = new LinkedHashMap<>(); if (node.getDeclaredNodes() != null && !node.getDeclaredNodes().isEmpty()) { for (NodeData nodeChild : node.getDeclaredNodes()) { @@ -432,14 +450,35 @@ } if (node.needsFactory() || node.getNodeDeclaringChildren().size() > 0) { - add(new NodeFactoryFactory(context, childTypes), node); + NodeFactoryFactory factory = new NodeFactoryFactory(context, childTypes); + add(factory, node); + factory.getElement().getEnclosedElements().addAll(casts); + } + } + + protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { + if (targetType == null) { + return value; + } else if (sourceType != null && !sourceType.needsCastTo(getContext(), targetType)) { + return value; } + + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + String targetMethodName; + if (expect) { + targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); + } else { + targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); + } + startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); + builder.tree(value); + builder.end().end(); + return builder.getRoot(); } private class NodeFactoryFactory extends ClassElementFactory<NodeData> { private final Map<NodeData, List<TypeElement>> childTypes; - private CodeTypeElement generatedNode; public NodeFactoryFactory(ProcessorContext context, Map<NodeData, List<TypeElement>> childElements) { @@ -853,7 +892,8 @@ ExecutableElement getter = (ExecutableElement) child.getAccessElement(); CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), getter); method.getModifiers().remove(Modifier.ABSTRACT); - method.createBuilder().startReturn().string("this.").string(child.getName()).end(); + CodeTreeBuilder builder = method.createBuilder(); + builder.startReturn().string("this.").string(child.getName()).end(); clazz.add(method); } } @@ -1107,29 +1147,58 @@ builder.startStatement(); String fieldName = var.getSimpleName().toString(); - CodeTree fieldInit = CodeTreeBuilder.singleString(var.getSimpleName().toString()); - builder.string("this.").string(var.getSimpleName().toString()); - NodeChildData child = node.findChild(fieldName); - if (child != null) { - CreateCastData createCast = node.findCast(child.getName()); - if (createCast != null) { - fieldInit = createTemplateMethodCall(builder, null, node.getGenericSpecialization(), createCast, null, child.getName()); - } - } - - if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { - builder.string(" = adoptChild(").tree(fieldInit).string(")"); - } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { - builder.string(" = adoptChildren(").tree(fieldInit).string(")"); - } else { - builder.string(" = ").tree(fieldInit); - } + + CodeTree init = createStaticCast(builder, child, fieldName); + init = createAdoptChild(builder, var.asType(), init); + + builder.string("this.").string(fieldName).string(" = ").tree(init); builder.end(); } return method; } + private CodeTree createStaticCast(CodeTreeBuilder parent, NodeChildData child, String fieldName) { + NodeData parentNode = getModel().getNode(); + if (child != null) { + CreateCastData createCast = parentNode.findCast(child.getName()); + if (createCast != null) { + return createTemplateMethodCall(parent, null, parentNode.getGenericSpecialization(), createCast, null, fieldName); + } + } + return CodeTreeBuilder.singleString(fieldName); + } + + private CodeTree createAdoptChild(CodeTreeBuilder parent, TypeMirror type, CodeTree value) { + CodeTreeBuilder builder = new CodeTreeBuilder(parent); + if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNode())) { + builder.string("adoptChild(").tree(value).string(")"); + } else if (Utils.isAssignable(getContext(), type, getContext().getTruffleTypes().getNodeArray())) { + builder.string("adoptChildren(").tree(value).string(")"); + } else { + builder.tree(value); + } + return builder.getRoot(); + } + + private CodeTree createCopyArray(CodeTreeBuilder parent, NodeChildData child, TypeMirror arrayType, CodeBlock<String> accessElement) { + CodeTreeBuilder builder = parent.create(); + NodeData node = getModel().getNode(); + builder.string("new ").type(arrayType).string(" {"); + builder.startCommaGroup(); + for (ActualParameter parameter : getModel().getParameters()) { + NodeChildData foundChild = node.findChild(parameter.getSpecification().getName()); + if (foundChild == child) { + builder.startGroup(); + builder.tree(accessElement.create(builder, String.valueOf(parameter.getIndex()))); + builder.end(); + } + } + builder.end(); + builder.end().string("}"); + return builder.getRoot(); + } + private CodeExecutableElement createCopyConstructor(CodeTypeElement type, ExecutableElement superConstructor) { CodeExecutableElement method = new CodeExecutableElement(null, type.getSimpleName().toString()); CodeTreeBuilder builder = method.createBuilder(); @@ -1141,34 +1210,22 @@ for (VariableElement var : type.getFields()) { builder.startStatement(); - String varName = var.getSimpleName().toString(); - builder.string("this.").string(varName); - if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNode())) { - builder.string(" = adoptChild(copy.").string(varName).string(")"); - } else if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { - NodeData node = getModel().getNode(); - NodeChildData child = node.findChild(varName); - if (child != null) { - builder.string(" = adoptChildren("); - builder.string("new ").type((child.getNodeType())).string(" {"); - builder.startCommaGroup(); - for (ActualParameter parameter : getModel().getParameters()) { - NodeChildData foundChild = node.findChild(parameter.getSpecification().getName()); - if (foundChild == child) { - builder.startGroup(); - builder.string("copy.").string(varName).string("[").string(String.valueOf(parameter.getIndex())).string("]"); - builder.end(); - } + final String varName = var.getSimpleName().toString(); + final TypeMirror varType = var.asType(); + + final String copyAccess = "copy." + varName; + CodeTree init = CodeTreeBuilder.singleString(copyAccess); + if (Utils.isAssignable(getContext(), var.asType(), getContext().getTruffleTypes().getNodeArray())) { + NodeChildData child = getModel().getNode().findChild(varName); + init = createCopyArray(builder, child, varType, new CodeBlock<String>() { + + public CodeTree create(CodeTreeBuilder parent, String index) { + return CodeTreeBuilder.singleString(copyAccess + "[" + index + "]"); } - - builder.end().string("})"); - } else { - builder.string(" = adoptChildren(copy.").string(varName).string(")"); - } - } else { - builder.string(" = copy.").string(varName); + }); } - builder.end(); + init = createAdoptChild(builder, varType, init); + builder.startStatement().string("this.").string(varName).string(" = ").tree(init).end(); } if (getModel().getNode().isPolymorphic()) { builder.statement("this.next0 = adoptChild(copy.next0)"); @@ -1184,7 +1241,8 @@ } private CodeVariableElement createChildField(NodeChildData child) { - CodeVariableElement var = new CodeVariableElement(child.getNodeType(), child.getName()); + TypeMirror type = child.getNodeType(); + CodeVariableElement var = new CodeVariableElement(type, child.getName()); var.getModifiers().add(Modifier.PROTECTED); DeclaredType annotationType; @@ -1223,7 +1281,7 @@ } builder.startStatement().string("String message = ").startCall("createInfo0").string("reason"); - addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, false, true); + addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, false, true, null); builder.end().end(); final String currentNodeVar = currentNode; @@ -1434,7 +1492,7 @@ guardsAnd = " && "; } - CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType()); + CodeTree cast = createCast(castBuilder, child, valueParam, typeGuard.getType(), minimumState); if (cast != null) { castBuilder.tree(cast); } @@ -1526,7 +1584,15 @@ builder.string(" || "); } - startCallTypeSystemMethod(getContext(), builder, node, TypeSystemCodeGenerator.isTypeMethodName(targetType)); + String castMethodName; + List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + if (types.size() > 1) { + castMethodName = TypeSystemCodeGenerator.isImplicitTypeMethodName(targetType); + } else { + castMethodName = TypeSystemCodeGenerator.isTypeMethodName(targetType); + } + + startCallTypeSystemMethod(getContext(), builder, node, castMethodName); builder.string(valueName(source)); builder.end().end(); // call @@ -1539,7 +1605,7 @@ return builder.getRoot(); } - private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType) { + private CodeTree createCast(CodeTreeBuilder parent, NodeChildData field, ActualParameter source, TypeData targetType, boolean minimumState) { NodeData node = field.getNodeData(); TypeData sourceType = source.getTypeSystemType(); @@ -1554,9 +1620,24 @@ condition = CodeTreeBuilder.singleString(valueName(shortCircuit)); } - CodeTree value = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.asTypeMethodName(targetType), CodeTreeBuilder.singleString(valueName(source))); - - return createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value); + String castMethodName; + List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetType); + if (types.size() > 1) { + castMethodName = TypeSystemCodeGenerator.asImplicitTypeMethodName(targetType); + } else { + castMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); + } + + CodeTree value = createCallTypeSystemMethod(context, parent, node, castMethodName, CodeTreeBuilder.singleString(valueName(source))); + + CodeTreeBuilder builder = parent.create(); + builder.tree(createLazyAssignment(parent, castValueName(source), targetType.getPrimitiveType(), condition, value)); + if (minimumState && types.size() > 1) { + CodeTree castType = createCallTypeSystemMethod(context, parent, node, TypeSystemCodeGenerator.getImplicitClass(targetType), CodeTreeBuilder.singleString(valueName(source))); + builder.tree(createLazyAssignment(builder, typeName(source), getContext().getType(Class.class), condition, castType)); + } + + return builder.getRoot(); } private CodeTree createMethodGuard(CodeTreeBuilder parent, String prefix, SpecializationData source, GuardData guard) { @@ -1595,7 +1676,6 @@ builder.tree(createRewriteGeneric(builder, source, current, currentNodeVar)); builder.end(); } else { - // simple rewrite if (current.getExceptions().isEmpty()) { builder.tree(createGenericInvoke(builder, source, current, createReplaceCall(builder, current, currentNodeVar, currentNodeVar, null), null)); } else { @@ -1669,7 +1749,7 @@ } if (current.isGeneric()) { builder.startReturn().tree(replace).string(".").startCall(EXECUTE_GENERIC_NAME); - addInternalValueParameterNames(builder, source, current, null, current.getNode().needsFrame(), true); + addInternalValueParameterNames(builder, source, current, null, current.getNode().needsFrame(), true, null); builder.end().end(); } else if (current.getMethod() == null) { if (replaceCall != null) { @@ -1696,7 +1776,19 @@ } else { replaceCall.startCall("replace"); } - replaceCall.startGroup().startNew(className).string(source).end().end(); + replaceCall.startGroup().startNew(className).string(source); + for (ActualParameter param : current.getParameters()) { + if (!param.getSpecification().isSignature()) { + continue; + } + NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); + List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (types.size() > 1) { + replaceCall.string(typeName(param)); + } + } + replaceCall.end().end(); + if (message == null) { replaceCall.string("message"); } else { @@ -1732,7 +1824,7 @@ builder.startReturn(); builder.startCall(currentNode + ".next0", executeCachedName(node.getGenericPolymorphicSpecialization())); - addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, true); + addInternalValueParameterNames(builder, node.getGenericSpecialization(), node.getGenericSpecialization(), null, true, true, null); builder.end(); builder.end(); @@ -1776,7 +1868,7 @@ executeParameterNames[i] = valueName(executeParameters.get(i)); } - builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null, true)); + builder.tree(createExecuteChildren(builder, executable, specialization, executeParameters, null)); CodeTree primaryExecuteCall = createTemplateMethodCall(builder, null, executable, castExecutable, null, executeParameterNames); if (needsTry) { @@ -1827,134 +1919,180 @@ return createCastType(node, sourceType, castedType.getType(), hasUnexpected, value); } - protected CodeTree createCastType(NodeData node, TypeData sourceType, TypeData targetType, boolean expect, CodeTree value) { - if (targetType == null) { - return value; - } else if (!sourceType.needsCastTo(getContext(), targetType)) { - return value; - } - - CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - String targetMethodName; - if (expect) { - targetMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetType); - } else { - targetMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetType); - } - startCallTypeSystemMethod(getContext(), builder, node, targetMethodName); - - builder.tree(value); - builder.end().end(); - return builder.getRoot(); - } - protected CodeTree createExecuteChildren(CodeTreeBuilder parent, ExecutableTypeData sourceExecutable, SpecializationData specialization, List<ActualParameter> targetParameters, - ActualParameter unexpectedParameter, boolean cast) { - NodeData sourceNode = specialization.getNode(); - - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - + ActualParameter unexpectedParameter) { + CodeTreeBuilder builder = parent.create(); + NodeData node = specialization.getNode(); for (ActualParameter targetParameter : targetParameters) { - NodeChildData field = sourceNode.findChild(targetParameter.getSpecification().getName()); + NodeChildData child = node.findChild(targetParameter.getSpecification().getName()); if (!targetParameter.getSpecification().isSignature()) { continue; } - TypeData targetType = targetParameter.getTypeSystemType(); ExecutableTypeData targetExecutable = null; - if (field != null) { - targetExecutable = field.findExecutableType(getContext(), targetType); + if (child != null) { + targetExecutable = child.findExecutableType(getContext(), targetType); + } + + if (targetExecutable == null) { + // TODO what to do? assertion? + continue; } - ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); - - String targetVariableName = valueName(targetParameter); - - CodeTree executionExpression = null; - if ((sourceParameter != null && cast) || sourceParameter != null) { - TypeData sourceType = sourceParameter.getTypeSystemType(); - if (targetExecutable == null || !sourceType.needsCastTo(getContext(), targetType)) { - if (field != null && field.isShortCircuit() && sourceParameter != null) { - builder.tree(createShortCircuitValue(builder, specialization, field, targetParameter.getPreviousParameter(), unexpectedParameter)); - } - builder.startStatement(); - builder.type(targetParameter.getType()).string(" "); - builder.string(targetVariableName).string(" = "); - builder.tree(CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter))); - builder.end(); - continue; + CodeTree executionExpressions = createExecutionExpresssions(builder, child, sourceExecutable, targetExecutable, targetParameter, unexpectedParameter); + + String targetVarName = valueName(targetParameter); + CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpressions, targetVarName, specialization, sourceExecutable, targetExecutable, targetParameter, + isShortCircuit(child)); + CodeTree shortCircuitTree = createShortCircuitTree(builder, unexpectedTree, targetVarName, specialization, targetParameter, unexpectedParameter); + + if (shortCircuitTree == executionExpressions) { + if (containsNewLine(executionExpressions)) { + builder.declaration(sourceExecutable.getType().getPrimitiveType(), targetVarName); + builder.tree(shortCircuitTree); } else { - CodeTree valueTree = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); - executionExpression = createExpectExecutableType(sourceNode, sourceType, targetExecutable, valueTree); + builder.startStatement().type(targetParameter.getType()).string(" ").tree(shortCircuitTree).end(); } - } else if (sourceParameter == null) { - executionExpression = createExecuteChildExpression(builder, field, targetParameter, unexpectedParameter); - } - - if (executionExpression != null) { - CodeTreeVariable executionVar = new CodeTreeVariable(); - CodeTree shortCircuitTree = createShortCircuitTree(builder, executionVar, targetVariableName, specialization, targetParameter, unexpectedParameter); - CodeTree unexpectedTree = createCatchUnexpectedTree(builder, executionExpression, targetVariableName, specialization, sourceExecutable, targetExecutable, targetParameter, - shortCircuitTree != executionVar); - - executionVar.set(unexpectedTree); + } else { builder.tree(shortCircuitTree); } + + } + return builder.getRoot(); + } + + private CodeTree createExecutionExpresssions(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, ActualParameter param, + ActualParameter unexpectedParameter) { + CodeTreeBuilder builder = parent.create(); + + TypeData type = param.getTypeSystemType(); + List<TypeData> targetTypes = child.getNodeData().getTypeSystem().lookupSourceTypes(type); + + if (targetTypes.size() > 1) { + boolean elseIf = false; + int index = 0; + for (TypeData typeData : targetTypes) { + if (index < targetTypes.size() - 1) { + elseIf = builder.startIf(elseIf); + builder.string(typeName(param)).string(" == ").typeLiteral(typeData.getPrimitiveType()); + builder.end(); + builder.startBlock(); + } else { + builder.startElseBlock(); + } + + ExecutableTypeData implictExecutableTypeData = child.getNodeData().findExecutableType(typeData, targetExecutable.getEvaluatedCount()); + ImplicitCastData cast = child.getNodeData().getTypeSystem().lookupCast(typeData, param.getTypeSystemType()); + CodeTree execute = createExecuteExpression(parent, child, sourceExecutable, implictExecutableTypeData, param, unexpectedParameter, cast); + builder.statement(execute); + builder.end(); + index++; + } + } else { + builder.tree(createExecuteExpression(parent, child, sourceExecutable, targetExecutable, param, unexpectedParameter, null)); } return builder.getRoot(); } + private CodeTree createExecuteExpression(CodeTreeBuilder parent, NodeChildData child, ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, + ActualParameter targetParameter, ActualParameter unexpectedParameter, ImplicitCastData cast) { + CodeTreeBuilder builder = parent.create(); + builder.string(valueName(targetParameter)); + builder.string(" = "); + if (cast != null) { + startCallTypeSystemMethod(getContext(), builder, child.getNodeData(), cast.getMethodName()); + } + + NodeData node = getModel().getNode(); + ActualParameter sourceParameter = sourceExecutable.findParameter(targetParameter.getLocalName()); + if (sourceParameter == null) { + builder.tree(createExecuteChildExpression(builder, child, targetParameter, targetExecutable, unexpectedParameter)); + } else { + CodeTree var = CodeTreeBuilder.singleString(valueNameEvaluated(targetParameter)); + builder.tree(createExpectExecutableType(node, sourceParameter.getTypeSystemType(), targetExecutable, var)); + } + if (cast != null) { + builder.end().end(); + } + + return builder.getRoot(); + } + + private boolean containsNewLine(CodeTree tree) { + if (tree.getCodeKind() == CodeTreeKind.NEW_LINE) { + return true; + } + + for (CodeTree codeTree : tree.getEnclosedElements()) { + if (containsNewLine(codeTree)) { + return true; + } + } + return false; + } + + private boolean hasUnexpected(ExecutableTypeData target, ActualParameter sourceParameter, ActualParameter targetParameter) { + List<TypeData> types = getModel().getNode().getTypeSystem().lookupSourceTypes(targetParameter.getTypeSystemType()); + NodeChildData child = getModel().getNode().findChild(targetParameter.getSpecification().getName()); + boolean hasUnexpected = false; + for (TypeData type : types) { + if (hasUnexpected) { + continue; + } + ExecutableTypeData execTarget = target; + if (type != execTarget.getType()) { + execTarget = child.findExecutableType(getContext(), type); + } + hasUnexpected = hasUnexpected || hasUnexpectedType(execTarget, sourceParameter, type); + } + return hasUnexpected; + } + + private boolean hasUnexpectedType(ExecutableTypeData target, ActualParameter sourceParameter, TypeData type) { + if (sourceParameter == null) { + return target.hasUnexpectedValue(getContext()); + } else { + if (sourceParameter.getTypeSystemType().needsCastTo(getContext(), type)) { + return target.hasUnexpectedValue(getContext()); + } + return false; + } + } + private CodeTree createCatchUnexpectedTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ExecutableTypeData currentExecutable, ExecutableTypeData targetExecutable, ActualParameter param, boolean shortCircuit) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); - boolean unexpected = targetExecutable.hasUnexpectedValue(getContext()); - boolean cast = false; - if (targetExecutable.getType().needsCastTo(getContext(), param.getTypeSystemType())) { - unexpected = true; - cast = true; + ActualParameter sourceParameter = currentExecutable.findParameter(param.getLocalName()); + boolean unexpected = hasUnexpected(targetExecutable, sourceParameter, param); + if (!unexpected) { + return body; } - builder.startStatement(); - if (!shortCircuit) { - builder.type(param.getType()).string(" ").string(targetVariableName); + builder.declaration(param.getType(), targetVariableName); } - - if (unexpected) { - if (!shortCircuit) { - builder.end(); - } - builder.startTryBlock(); - builder.startStatement(); - builder.string(targetVariableName); - } else if (shortCircuit) { - builder.startStatement(); - builder.string(targetVariableName); - } - builder.string(" = "); - if (cast) { - builder.tree(createCastType(specialization.getNode(), targetExecutable.getType(), param.getTypeSystemType(), true, body)); - } else { + builder.startTryBlock(); + + if (containsNewLine(body)) { builder.tree(body); + } else { + builder.statement(body); } - builder.end(); - - if (unexpected) { - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - SpecializationData generic = specialization.getNode().getGenericSpecialization(); - ActualParameter genericParameter = generic.findParameter(param.getLocalName()); - - List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); - builder.tree(createDeoptimize(builder)); - builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter, false)); - if (specialization.isPolymorphic()) { - builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); - } else { - builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization, param, - "Expected " + param.getLocalName() + " instanceof " + Utils.getSimpleName(param.getType()))); - } - builder.end(); // catch block + + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + SpecializationData generic = specialization.getNode().getGenericSpecialization(); + ActualParameter genericParameter = generic.findParameter(param.getLocalName()); + + List<ActualParameter> genericParameters = generic.getParametersAfter(genericParameter); + builder.tree(createDeoptimize(builder)); + builder.tree(createExecuteChildren(parent, currentExecutable, generic, genericParameters, genericParameter)); + if (specialization.isPolymorphic()) { + builder.tree(createReturnOptimizeTypes(builder, currentExecutable, specialization, param)); + } else { + builder.tree(createReturnExecuteAndSpecialize(builder, currentExecutable, specialization, param, + "Expected " + param.getLocalName() + " instanceof " + Utils.getSimpleName(param.getType()))); } + builder.end(); // catch block return builder.getRoot(); } @@ -1969,7 +2107,7 @@ CodeTreeBuilder execute = new CodeTreeBuilder(builder); execute.startCall("next0", executeCachedName(generic)); - addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true); + addInternalValueParameterNames(execute, specialization, generic, param.getLocalName(), true, true, null); execute.end(); TypeData sourceType = generic.getReturnType().getTypeSystemType(); @@ -1980,37 +2118,26 @@ return builder.getRoot(); } - private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetField, ActualParameter sourceParameter, ActualParameter unexpectedParameter) { - TypeData type = sourceParameter.getTypeSystemType(); - ExecutableTypeData execType = targetField.findExecutableType(getContext(), type); - + private CodeTree createExecuteChildExpression(CodeTreeBuilder parent, NodeChildData targetChild, ActualParameter targetParameter, ExecutableTypeData targetExecutable, + ActualParameter unexpectedParameter) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); - if (targetField != null) { - Element accessElement = targetField.getAccessElement(); - if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { - builder.string("this.").string(targetField.getName()); - } else if (accessElement.getKind() == ElementKind.FIELD) { - builder.string("this.").string(accessElement.getSimpleName().toString()); - } else { - throw new AssertionError(); - } - if (sourceParameter.getSpecification().isIndexed()) { - builder.string("[" + sourceParameter.getIndex() + "]"); - } + if (targetChild != null) { + builder.tree(createAccessChild(builder, targetChild, targetParameter)); builder.string("."); } - builder.startCall(execType.getMethodName()); - + builder.startCall(targetExecutable.getMethodName()); + + // TODO this should be merged with #createTemplateMethodCall int index = 0; - for (ActualParameter parameter : execType.getParameters()) { + for (ActualParameter parameter : targetExecutable.getParameters()) { if (!parameter.getSpecification().isSignature()) { builder.string(parameter.getLocalName()); } else { - if (index < targetField.getExecuteWith().size()) { - NodeChildData child = targetField.getExecuteWith().get(index); + if (index < targetChild.getExecuteWith().size()) { + NodeChildData child = targetChild.getExecuteWith().get(index); ParameterSpec spec = getModel().getSpecification().findParameterSpec(child.getName()); List<ActualParameter> specializationParams = getModel().findParameters(spec); @@ -2049,32 +2176,50 @@ return builder.getRoot(); } + private CodeTree createAccessChild(CodeTreeBuilder parent, NodeChildData targetChild, ActualParameter targetParameter) throws AssertionError { + CodeTreeBuilder builder = parent.create(); + Element accessElement = targetChild.getAccessElement(); + if (accessElement == null || accessElement.getKind() == ElementKind.METHOD) { + builder.string("this.").string(targetChild.getName()); + } else if (accessElement.getKind() == ElementKind.FIELD) { + builder.string("this.").string(accessElement.getSimpleName().toString()); + } else { + throw new AssertionError(); + } + if (targetParameter.getSpecification().isIndexed()) { + builder.string("[" + targetParameter.getIndex() + "]"); + } + return builder.getRoot(); + } + private CodeTree createShortCircuitTree(CodeTreeBuilder parent, CodeTree body, String targetVariableName, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { - CodeTreeBuilder builder = new CodeTreeBuilder(parent); - NodeChildData forField = specialization.getNode().findChild(parameter.getSpecification().getName()); - if (forField == null) { + if (!isShortCircuit(forField)) { return body; } - if (forField.getExecutionKind() != ExecutionKind.SHORT_CIRCUIT) { - return body; - } - + CodeTreeBuilder builder = new CodeTreeBuilder(parent); ActualParameter shortCircuitParam = specialization.getPreviousParam(parameter); - builder.tree(createShortCircuitValue(builder, specialization, forField, shortCircuitParam, exceptionParam)); - builder.declaration(parameter.getType(), targetVariableName, CodeTreeBuilder.createBuilder().defaultValue(parameter.getType())); builder.startIf().string(shortCircuitParam.getLocalName()).end(); builder.startBlock(); - builder.tree(body); + + if (containsNewLine(body)) { + builder.tree(body); + } else { + builder.statement(body); + } builder.end(); return builder.getRoot(); } + private boolean isShortCircuit(NodeChildData forField) { + return forField != null && forField.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT; + } + private CodeTree createShortCircuitValue(CodeTreeBuilder parent, SpecializationData specialization, NodeChildData forField, ActualParameter shortCircuitParam, ActualParameter exceptionParam) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); int shortCircuitIndex = 0; @@ -2109,7 +2254,7 @@ CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); specializeCall.string(String.valueOf(node.getSpecializations().indexOf(current))); - addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true); + addInternalValueParameterNames(specializeCall, generic, node.getGenericSpecialization(), exceptionParam != null ? exceptionParam.getLocalName() : null, true, true, null); specializeCall.doubleQuote(reason); specializeCall.end().end(); @@ -2199,6 +2344,233 @@ } } + private class BaseCastNodeFactory extends ClassElementFactory<NodeData> { + + protected final Set<TypeData> usedTargetTypes; + + public BaseCastNodeFactory(ProcessorContext context, Set<TypeData> usedTargetTypes) { + super(context); + this.usedTargetTypes = usedTargetTypes; + } + + @Override + protected CodeTypeElement create(NodeData m) { + CodeTypeElement type = createClass(m, modifiers(STATIC), nodeCastClassName(m, null), context.getTruffleTypes().getNode(), false); + + CodeVariableElement delegate = new CodeVariableElement(m.getNodeType(), "delegate"); + delegate.getModifiers().add(PROTECTED); + delegate.getAnnotationMirrors().add(new CodeAnnotationMirror(getContext().getTruffleTypes().getChildAnnotation())); + + type.add(delegate); + type.add(createConstructorUsingFields(modifiers(), type)); + return type; + } + + @Override + protected void createChildren(NodeData m) { + CodeTypeElement type = getElement(); + type.add(createExecute(EXECUTE_SPECIALIZE_NAME, true)); + type.add(createExecute(EXECUTE_GENERIC_NAME, false)); + + for (ExecutableTypeData targetExecutable : m.getExecutableTypes()) { + if (!usedTargetTypes.contains(targetExecutable.getType()) && targetExecutable.hasUnexpectedValue(getContext())) { + continue; + } + CodeExecutableElement execute = createCastExecute(targetExecutable, targetExecutable, false); + CodeExecutableElement expect = createCastExecute(targetExecutable, targetExecutable, true); + if (execute != null) { + getElement().add(execute); + } + if (expect != null) { + getElement().add(expect); + } + } + Set<TypeData> sourceTypes = new TreeSet<>(); + List<ImplicitCastData> casts = getModel().getTypeSystem().getImplicitCasts(); + for (ImplicitCastData cast : casts) { + sourceTypes.add(cast.getSourceType()); + } + + CodeTypeElement baseType = getElement(); + for (TypeData sourceType : sourceTypes) { + add(new SpecializedCastNodeFactory(context, baseType, sourceType, usedTargetTypes), getModel()); + } + } + + private CodeExecutableElement createExecute(String name, boolean specialize) { + NodeData node = getModel(); + TypeMirror objectType = node.getTypeSystem().getGenericType(); + CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), objectType, name, new CodeVariableElement(objectType, "value")); + if (specialize) { + method.getModifiers().add(FINAL); + } + CodeTreeBuilder builder = method.createBuilder(); + + List<ImplicitCastData> casts = node.getTypeSystem().getImplicitCasts(); + boolean elseIf = false; + for (ImplicitCastData cast : casts) { + elseIf = builder.startIf(elseIf); + startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.isTypeMethodName(cast.getSourceType())); + builder.string("value"); + builder.end().end(); + builder.end(); + builder.startBlock(); + + if (specialize) { + builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), cast.getSourceType())).string("delegate").end().doubleQuote("Added cast").end().end(); + } + builder.startReturn(); + + startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName()); + startCallTypeSystemMethod(context, builder, getModel(), TypeSystemCodeGenerator.asTypeMethodName(cast.getSourceType())); + builder.string("value"); + builder.end().end(); + builder.end().end(); + + builder.end(); + builder.end(); + } + + builder.startReturn().string("value").end(); + + return method; + } + + protected CodeExecutableElement createCastExecute(ExecutableTypeData sourceExecutable, ExecutableTypeData targetExecutable, boolean expect) { + ImplicitCastData cast = null; + if (!sourceExecutable.getType().equals(targetExecutable.getType())) { + cast = getModel().getTypeSystem().lookupCast(sourceExecutable.getType(), targetExecutable.getType()); + if (cast == null) { + return null; + } + } + + if (expect) { + if (targetExecutable.getEvaluatedCount() > 0) { + return null; + } else if (Utils.isObject(targetExecutable.getType().getPrimitiveType())) { + return null; + } + } + + boolean hasTargetUnexpected = targetExecutable.hasUnexpectedValue(getContext()); + boolean hasSourceUnexpected = sourceExecutable.hasUnexpectedValue(getContext()); + + CodeExecutableElement method = copyTemplateMethod(targetExecutable); + method.getModifiers().add(PUBLIC); + + CodeTreeBuilder builder = method.createBuilder(); + + if (hasSourceUnexpected && cast != null) { + builder.startTryBlock(); + } + + if (expect) { + method.getParameters().clear(); + String expectMethodName; + if (hasTargetUnexpected) { + expectMethodName = TypeSystemCodeGenerator.expectTypeMethodName(targetExecutable.getType()); + } else { + expectMethodName = TypeSystemCodeGenerator.asTypeMethodName(targetExecutable.getType()); + } + method.setSimpleName(CodeNames.of(expectMethodName)); + method.addParameter(new CodeVariableElement(getModel().getTypeSystem().getGenericType(), "value")); + } + + builder.startReturn(); + CodeTree executeCall; + if (expect) { + executeCall = createCastType(getModel(), getModel().getTypeSystem().getGenericTypeData(), sourceExecutable.getType(), hasSourceUnexpected, CodeTreeBuilder.singleString("value")); + } else { + executeCall = createTemplateMethodCall(builder, CodeTreeBuilder.singleString("delegate."), targetExecutable, sourceExecutable, null); + } + if (cast != null) { + startCallTypeSystemMethod(context, builder, getModel(), cast.getMethodName()); + builder.tree(executeCall); + builder.end().end(); + } else { + builder.tree(executeCall); + } + builder.end(); + + if (hasSourceUnexpected && cast != null) { + builder.end(); + builder.startCatchBlock(getContext().getTruffleTypes().getUnexpectedValueException(), "ex"); + builder.startStatement().startCall("replace").startNew(nodeCastClassName(getModel(), null)).string("delegate").end().doubleQuote("Removed cast").end().end(); + + if (hasTargetUnexpected) { + builder.startThrow().string("ex").end(); + } else { + builder.startThrow().startNew(getContext().getType(AssertionError.class)).end().end(); + } + builder.end(); + } + + return method; + } + + private CodeExecutableElement copyTemplateMethod(TemplateMethod targetExecutable) { + CodeExecutableElement method = CodeExecutableElement.clone(getContext().getEnvironment(), targetExecutable.getMethod()); + method.getModifiers().remove(ABSTRACT); + method.getAnnotationMirrors().clear(); + Modifier visibility = Utils.getVisibility(method.getModifiers()); + if (visibility != null) { + method.getModifiers().remove(visibility); + } + int index = 0; + for (ActualParameter parameter : targetExecutable.getParameters()) { + ((CodeVariableElement) method.getParameters().get(index)).setName(parameter.getLocalName()); + index++; + } + return method; + } + + } + + private class SpecializedCastNodeFactory extends BaseCastNodeFactory { + + private final CodeTypeElement baseType; + private final TypeData sourceType; + + public SpecializedCastNodeFactory(ProcessorContext context, CodeTypeElement baseType, TypeData type, Set<TypeData> usedTargetTypes) { + super(context, usedTargetTypes); + this.baseType = baseType; + this.sourceType = type; + } + + @Override + protected CodeTypeElement create(NodeData m) { + CodeTypeElement type = createClass(m, modifiers(PRIVATE, STATIC, FINAL), nodeCastClassName(m, sourceType), baseType.asType(), false); + type.add(createConstructorUsingFields(modifiers(), type)); + return type; + } + + @Override + protected void createChildren(NodeData node) { + for (TypeData targetType : usedTargetTypes) { + for (ExecutableTypeData targetExecutable : node.getExecutableTypes()) { + if (targetExecutable.getType().equals(targetType)) { + ExecutableTypeData sourceExecutable = node.findExecutableType(sourceType, targetExecutable.getEvaluatedCount()); + if (sourceExecutable == null) { + // TODO what if there is no evaluated version? + continue; + } + CodeExecutableElement execute = createCastExecute(sourceExecutable, targetExecutable, false); + CodeExecutableElement expect = createCastExecute(sourceExecutable, targetExecutable, true); + if (execute != null) { + getElement().add(execute); + } + if (expect != null) { + getElement().add(expect); + } + } + } + + } + } + + } + private class SpecializedNodeFactory extends NodeBaseFactory { protected final CodeTypeElement nodeGen; @@ -2277,15 +2649,31 @@ } CodeExecutableElement superConstructor = createSuperConstructor(clazz, constructor); + CodeTree body = superConstructor.getBodyTree(); + CodeTreeBuilder builder = superConstructor.createBuilder(); + builder.tree(body); if (superConstructor != null) { if (getModel().isGeneric() && node.isPolymorphic()) { - CodeTree body = superConstructor.getBodyTree(); - CodeTreeBuilder builder = superConstructor.createBuilder(); - builder.tree(body); builder.statement("this.next0 = null"); } + for (ActualParameter param : getModel().getParameters()) { + if (!param.getSpecification().isSignature()) { + continue; + } + NodeChildData child = getModel().getNode().findChild(param.getSpecification().getName()); + List<TypeData> types = child.getNodeData().getTypeSystem().lookupSourceTypes(param.getTypeSystemType()); + if (types.size() > 1) { + clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), getContext().getType(Class.class), typeName(param))); + superConstructor.getParameters().add(new CodeVariableElement(getContext().getType(Class.class), typeName(param))); + + builder.startStatement(); + builder.string("this.").string(typeName(param)).string(" = ").string(typeName(param)); + builder.end(); + } + } + clazz.add(superConstructor); } } @@ -2333,7 +2721,7 @@ } else { CodeTreeBuilder elseBuilder = new CodeTreeBuilder(builder); elseBuilder.startReturn().startCall("this.next0", executeCachedName(polymorphic)); - addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true); + addInternalValueParameterNames(elseBuilder, polymorphic, polymorphic, null, true, true, null); elseBuilder.end().end(); boolean forceElse = specialization.getExceptions().size() > 0; @@ -2375,7 +2763,7 @@ CodeTreeBuilder specializeCall = new CodeTreeBuilder(builder); specializeCall.startCall(EXECUTE_SPECIALIZE_NAME); specializeCall.string("0"); - addInternalValueParameterNames(specializeCall, specialization, node.getGenericSpecialization(), null, true, true); + addInternalValueParameterNames(specializeCall, specialization, node.getGenericSpecialization(), null, true, true, null); specializeCall.startGroup().doubleQuote("Uninitialized polymorphic (").string(" + depth + ").doubleQuote("/" + node.getPolymorphicDepth() + ")").end(); specializeCall.end().end(); @@ -2482,7 +2870,7 @@ builder.tree(createDeoptimize(builder)); } - builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null, false)); + builder.tree(createExecuteChildren(builder, executable, specialization, specialization.getParameters(), null)); CodeTree returnSpecialized = null; @@ -2519,26 +2907,25 @@ CodeTreeBuilder returnBuilder = new CodeTreeBuilder(parent); if (specialization.isPolymorphic()) { returnBuilder.startCall("next0", executeCachedName(specialization)); - addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true, null); returnBuilder.end(); } else if (specialization.isUninitialized()) { returnBuilder.startCall("super", EXECUTE_SPECIALIZE_NAME); returnBuilder.string("0"); - addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, true, true, null); returnBuilder.doubleQuote("Uninitialized monomorphic"); returnBuilder.end(); } else if (specialization.getMethod() == null && !node.needsRewrites(context)) { emitEncounteredSynthetic(builder, specialization); } else if (specialization.isGeneric()) { returnBuilder.startCall("super", EXECUTE_GENERIC_NAME); - addInternalValueParameterNames(returnBuilder, specialization, specialization, null, node.needsFrame(), true); + addInternalValueParameterNames(returnBuilder, specialization, specialization, null, node.needsFrame(), true, null); returnBuilder.end(); } else { returnBuilder.tree(createTemplateMethodCall(returnBuilder, null, specialization, specialization, null)); } if (!returnBuilder.isEmpty()) { - ExecutableTypeData sourceExecutableType = node.findExecutableType(specialization.getReturnType().getTypeSystemType(), 0); boolean sourceThrowsUnexpected = sourceExecutableType != null && sourceExecutableType.hasUnexpectedValue(getContext()); boolean targetSupportsUnexpected = executable.hasUnexpectedValue(getContext());