# HG changeset patch # User Christian Humer # Date 1363170763 -3600 # Node ID cb70ed101b5f419e73f30f2fe3d60572fb73b651 # Parent edc414f52e2b32179ab6fcaec8d791d70bbd29b4 Added automatic generation of generic specialization which throws unsupported operation if reached. diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java --- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/RuntimeStringTest.java Wed Mar 13 11:32:43 2013 +0100 @@ -28,6 +28,7 @@ import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.api.codegen.test.TypeSystemTest.TestRootNode; import com.oracle.truffle.api.codegen.test.TypeSystemTest.ValueNode; +import com.oracle.truffle.api.nodes.*; public class RuntimeStringTest { @@ -86,6 +87,7 @@ Object execute() { return arguments[index]; } + } abstract static class BuiltinNode extends ValueNode { diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Wed Mar 13 11:32:43 2013 +0100 @@ -748,7 +748,7 @@ return true; } - // search for any supertypes + // search for any super types TypeElement exceptionTypeElement = fromTypeMirror(exceptionType); List superTypes = getSuperTypes(exceptionTypeElement); for (TypeElement typeElement : superTypes) { @@ -777,7 +777,7 @@ Set typeSuperSet = new HashSet<>(getQualifiedSuperTypeNames(fromTypeMirror(type))); String typeName = getQualifiedName(type); if (!typeSuperSet.contains(Throwable.class.getCanonicalName()) && !typeName.equals(Throwable.class.getCanonicalName())) { - throw new IllegalArgumentException("Given does not extend Throwable."); + throw new IllegalArgumentException("Given type does not extend Throwable."); } return typeSuperSet.contains(RuntimeException.class.getCanonicalName()) || typeName.equals(RuntimeException.class.getCanonicalName()); } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Wed Mar 13 11:32:43 2013 +0100 @@ -62,7 +62,7 @@ @Override public SpecializationData create(TemplateMethod method) { - SpecializationData data = new SpecializationData(method, true, false); + SpecializationData data = new SpecializationData(method, true, false, false); data.setUseSpecializationsForGeneric(Utils.getAnnotationValueBoolean(data.getMarkerAnnotation(), "useSpecializations")); return data; } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Wed Mar 13 11:32:43 2013 +0100 @@ -34,7 +34,8 @@ import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.ast.*; -import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.ExecutionKind; +import com.oracle.truffle.codegen.processor.node.NodeFieldData.FieldKind; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.typesystem.*; @@ -145,7 +146,9 @@ private void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) { body.startGroup(); ExecutableElement method = templateMethod.getMethod(); - + if (method == null) { + throw new IllegalStateException("Cannot call synthtetic operation methods."); + } TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); NodeData node = (NodeData) templateMethod.getTemplate(); @@ -419,6 +422,10 @@ return builder.getRoot(); } + private void emitEncounteredSynthetic(CodeTreeBuilder builder) { + builder.startThrow().startNew(getContext().getType(UnsupportedOperationException.class)).end().end(); + } + @Override protected void createChildren(NodeData node) { Map> childTypes = new LinkedHashMap<>(); @@ -987,11 +994,15 @@ builder.startTryBlock(); } - builder.startReturn(); - startCallOperationMethod(builder, specialization, true); - addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false); - builder.end().end(); // start call operation - builder.end(); // return + if (specialization.isSynthetic()) { + emitEncounteredSynthetic(builder); + } else { + builder.startReturn(); + startCallOperationMethod(builder, specialization, true); + addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false); + builder.end().end(); // start call operation + builder.end(); // return + } if (!specialization.getExceptions().isEmpty()) { for (SpecializationThrowsData exception : specialization.getExceptions()) { @@ -1005,6 +1016,7 @@ builder.end(); } } + } private class SpecializedNodeFactory extends ClassElementFactory { @@ -1197,7 +1209,9 @@ builder.startTryBlock(); } - if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { + if (specialization.getMethod() == null) { + emitEncounteredSynthetic(builder); + } else if (specialization.isUninitialized() || specialization.isGeneric()) { builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); builder.string("this"); addValueParameterNames(builder, specialization, null, true, true); @@ -1205,12 +1219,9 @@ } else { builder.startReturn(); - if (specialization.isUninitialized()) { - startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false); - } else { - startCallOperationMethod(builder, specialization, false); - } + startCallOperationMethod(builder, specialization, false); addValueParameterNames(builder, specialization, null, false, false); + builder.end().end(); // operation call builder.end(); // return } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Mar 13 11:32:43 2013 +0100 @@ -68,14 +68,7 @@ this.guards = copy.guards; this.executableTypes = copy.executableTypes; this.shortCircuits = copy.shortCircuits; - - List fieldsCopy = new ArrayList<>(); - for (NodeFieldData field : copy.fields) { - NodeFieldData newField = new NodeFieldData(field); - newField.setNode(this); - fieldsCopy.add(newField); - } - this.fields = fieldsCopy; + this.fields = copy.fields; } public ParameterSpec getInstanceParameterSpec() { @@ -186,6 +179,14 @@ return null; } + public ExecutableTypeData findAnyGenericExecutableType(ProcessorContext context) { + List types = findGenericExecutableTypes(context); + if (!types.isEmpty()) { + return types.get(0); + } + return null; + } + public List findGenericExecutableTypes(ProcessorContext context) { List types = new ArrayList<>(); for (ExecutableTypeData type : executableTypes) { @@ -250,18 +251,13 @@ public boolean needsRewrites(ProcessorContext context) { boolean needsRewrites = false; - for (NodeFieldData field : getFields()) { - if (field.getExecutionKind() == ExecutionKind.DEFAULT || field.getExecutionKind() == ExecutionKind.SHORT_CIRCUIT) { - if (!field.getNodeData().hasUnexpectedExecutableTypes(context)) { - continue; - } + for (SpecializationData specialization : getSpecializations()) { + if (specialization.hasRewrite(context)) { needsRewrites = true; break; } } - - needsRewrites &= specializations.size() >= 2; return needsRewrites; } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Wed Mar 13 11:32:43 2013 +0100 @@ -103,7 +103,7 @@ @Override public String toString() { - return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + "]"; + return "NodeFieldData[name=" + getName() + ", kind=" + fieldKind + ", execution=" + executionKind + ", node=" + getNodeData().toString() + "]"; } } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Mar 13 11:32:43 2013 +0100 @@ -120,6 +120,10 @@ return null; // not a node } + if (type.getModifiers().contains(Modifier.PRIVATE)) { + return null; // not visible + } + TypeElement nodeType; boolean needsSplit; if (methodNodes != null) { @@ -130,10 +134,6 @@ nodeType = type; } - if (type.getModifiers().contains(Modifier.PRIVATE)) { - return null; // not visible - } - NodeData nodeData = parseNodeData(type, nodeType); if (nodeData == null) { return null; @@ -271,28 +271,63 @@ } } + if (generics.size() == 1 && specializations.size() == 1) { + for (SpecializationData generic : generics) { + log.error(generic.getMethod(), "@%s defined but no @%s.", Generic.class.getSimpleName(), Specialization.class.getSimpleName()); + } + } + SpecializationData genericSpecialization = null; if (generics.size() > 1) { for (SpecializationData generic : generics) { - log.error(generic.getMethod(), "Only one method with @%s is allowed per operation.", Generic.class.getSimpleName()); + log.error(generic.getMethod(), "Only @%s is allowed per operation.", Generic.class.getSimpleName()); } return false; } else if (generics.size() == 1) { genericSpecialization = generics.get(0); - } else { - // TODO support generation of generic if not ambiguous. - } + if (!node.needsRewrites(context)) { + log.error(genericSpecialization.getMethod(), "Generic specialization is not reachable.", Generic.class.getSimpleName()); + return false; + } + } else if (node.needsRewrites(context)) { + SpecializationData specialization = specializations.get(0); + GenericParser parser = new GenericParser(context, node); + MethodSpec specification = parser.createDefaultMethodSpec(specialization.getMethod(), null, null); + + ExecutableTypeData anyGenericReturnType = node.findAnyGenericExecutableType(context); + if (anyGenericReturnType == null) { + // TODO fail invalid executable type. should be validated by field. (assertion +// failure!?) + } - if (specializations.size() > 1 && genericSpecialization == null) { - log.error(node.getTemplateType(), "Need a @%s method.", Generic.class.getSimpleName()); - return false; + ActualParameter returnType = new ActualParameter(specification.getReturnType(), anyGenericReturnType.getType().getPrimitiveType(), 0, false); + List parameters = new ArrayList<>(); + for (ActualParameter specializationParameter : specialization.getParameters()) { + ParameterSpec parameterSpec = specification.findParameterSpec(specializationParameter.getSpecification().getName()); + NodeFieldData field = node.findField(parameterSpec.getName()); + TypeMirror actualType; + if (field == null) { + actualType = specializationParameter.getActualType(); + } else { + ExecutableTypeData paramType = field.getNodeData().findAnyGenericExecutableType(context); + if (paramType == null) { + // TODO fail + } + actualType = paramType.getType().getPrimitiveType(); + } + parameters.add(new ActualParameter(parameterSpec, actualType, specializationParameter.getIndex(), specializationParameter.isHidden())); + } + TemplateMethod genericMethod = new TemplateMethod("Generic", node, specification, null, null, returnType, parameters); + genericSpecialization = new SpecializationData(genericMethod, true, false, true); + + specializations.add(genericSpecialization); } if (genericSpecialization != null) { CodeExecutableElement uninitializedMethod = new CodeExecutableElement(Utils.modifiers(Modifier.PUBLIC), context.getType(void.class), "doUninitialized"); - TemplateMethod uninializedMethod = new TemplateMethod(genericSpecialization.getId(), node, genericSpecialization.getSpecification(), uninitializedMethod, - genericSpecialization.getMarkerAnnotation(), genericSpecialization.getReturnType(), genericSpecialization.getParameters()); - specializations.add(new SpecializationData(uninializedMethod, false, true)); + TemplateMethod uninializedMethod = new TemplateMethod("Uninitialized", node, genericSpecialization.getSpecification(), uninitializedMethod, genericSpecialization.getMarkerAnnotation(), + genericSpecialization.getReturnType(), genericSpecialization.getParameters()); + specializations.add(new SpecializationData(uninializedMethod, false, true, true)); } Collections.sort(specializations, new Comparator() { diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationData.java Wed Mar 13 11:32:43 2013 +0100 @@ -25,6 +25,7 @@ import java.util.*; import com.oracle.truffle.api.codegen.*; +import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; public class SpecializationData extends TemplateMethod { @@ -38,11 +39,14 @@ private boolean useSpecializationsForGeneric = true; private NodeData node; + private final boolean synthetic; + public SpecializationData(TemplateMethod template, int order, List exceptions) { super(template); this.order = order; this.generic = false; this.uninitialized = false; + this.synthetic = false; this.exceptions = exceptions; for (SpecializationThrowsData exception : exceptions) { @@ -50,13 +54,34 @@ } } - public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized) { + public SpecializationData(TemplateMethod template, boolean generic, boolean uninitialized, boolean synthetic) { super(template); this.order = Specialization.DEFAULT_ORDER; this.generic = generic; this.uninitialized = uninitialized; this.exceptions = Collections.emptyList(); this.guards = new SpecializationGuardData[0]; + this.synthetic = synthetic; + } + + public boolean hasRewrite(ProcessorContext context) { + if (getExceptions().size() > 0) { + return true; + } + if (getGuards().length > 0) { + return true; + } + for (ActualParameter parameter : getParameters()) { + NodeFieldData field = getNode().findField(parameter.getSpecification().getName()); + if (field == null) { + continue; + } + ExecutableTypeData type = field.getNodeData().findExecutableType(parameter.getActualTypeData(field.getNodeData().getTypeSystem())); + if (type.hasUnexpectedValue(context)) { + return true; + } + } + return false; } public NodeData getNode() { @@ -71,6 +96,10 @@ this.guards = guards; } + public boolean isSynthetic() { + return synthetic; + } + public int getOrder() { return order; } diff -r edc414f52e2b -r cb70ed101b5f graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java --- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Tue Mar 12 11:38:52 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Wed Mar 13 11:32:43 2013 +0100 @@ -119,7 +119,11 @@ } public String getMethodName() { - return getMethod().getSimpleName().toString(); + if (getMethod() != null) { + return getMethod().getSimpleName().toString(); + } else { + return "$synthetic"; + } } public AnnotationMirror getMarkerAnnotation() {