OpenJDK / graal / graal-jvmci-8
changeset 8245:703c09f8640c
Implemented support for @NodeClass annotation to support builtins.
line wrap: on
line diff
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/SimpleTypes.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/SimpleTypes.java Wed Mar 06 18:32:33 2013 +0100 @@ -24,6 +24,6 @@ import com.oracle.truffle.api.codegen.*; -@TypeSystem({int.class, String.class}) +@TypeSystem({int.class, RuntimeString.class}) class SimpleTypes { }
--- a/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.api.codegen.test/src/com/oracle/truffle/api/codegen/test/package-info.java Wed Mar 06 18:32:33 2013 +0100 @@ -36,8 +36,11 @@ * <p> * This introduction to Codegen contains items in the following recommended order: * + * Prerequisites: + * + * * <ul> - * <li>How would you generate builtin functions? {@link com.oracle.truffle.api.codegen.test.BuiltinFunctionTest}</li> + * <li>How would you generate function nodes for runtime objects? {@link com.oracle.truffle.api.codegen.test.RuntimeString}</li> * </ul> * </p> *
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/Utils.java Wed Mar 06 18:32:33 2013 +0100 @@ -167,6 +167,46 @@ return new LinkedHashSet<>(Arrays.asList(modifier)); } + public static String getTypeId(TypeMirror mirror) { + switch (mirror.getKind()) { + case BOOLEAN: + return "Boolean"; + case BYTE: + return "Byte"; + case CHAR: + return "Char"; + case DOUBLE: + return "Double"; + case FLOAT: + return "Float"; + case SHORT: + return "Short"; + case INT: + return "Int"; + case LONG: + return "Long"; + case DECLARED: + return ((DeclaredType) mirror).asElement().getSimpleName().toString(); + case ARRAY: + return getTypeId(((ArrayType) mirror).getComponentType()) + "Array"; + case VOID: + return "Void"; + case WILDCARD: + StringBuilder b = new StringBuilder(); + WildcardType type = (WildcardType) mirror; + if (type.getExtendsBound() != null) { + b.append("Extends").append(getTypeId(type.getExtendsBound())); + } else if (type.getSuperBound() != null) { + b.append("Super").append(getTypeId(type.getExtendsBound())); + } + return b.toString(); + case TYPEVAR: + return "Any"; + default: + throw new RuntimeException("Unknown type specified " + mirror.getKind() + " mirror: " + mirror); + } + } + public static String getSimpleName(TypeElement element) { return getSimpleName(element.asType()); }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ExecutableTypeMethodParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -51,7 +51,7 @@ List<ParameterSpec> parameters = new ArrayList<>(); parameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); - return new MethodSpec(returnTypeSpec, parameters); + return new MethodSpec(new ArrayList<TypeMirror>(), returnTypeSpec, parameters); } @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/GenericParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -41,7 +41,7 @@ @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return createDefaultMethodSpec(null); + return createDefaultMethodSpec(method, mirror, null); } @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/MethodParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -25,6 +25,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.node.NodeFieldData.*; @@ -54,12 +55,20 @@ return Utils.findAnnotationMirror(getContext().getEnvironment(), method, getAnnotationType()) != null; } - protected final MethodSpec createDefaultMethodSpec(String shortCircuitName) { + @SuppressWarnings("unused") + protected final MethodSpec createDefaultMethodSpec(ExecutableElement method, AnnotationMirror mirror, String shortCircuitName) { List<ParameterSpec> defaultParameters = new ArrayList<>(); if (getNode().supportsFrame()) { - ParameterSpec frameSpec = new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true); - defaultParameters.add(frameSpec); + defaultParameters.add(new ParameterSpec("frame", getContext().getTruffleTypes().getFrame(), true)); + } + + TypeMirror declaredType = Utils.findNearestEnclosingType(method).asType(); + + List<TypeMirror> prefixTypes = new ArrayList<>(); + + if (!method.getModifiers().contains(Modifier.STATIC) && !Utils.isAssignable(declaredType, template.getNodeType())) { + prefixTypes.add(getNode().getTemplateType().asType()); } for (NodeFieldData field : getNode().getFields()) { @@ -87,7 +96,7 @@ } } - return new MethodSpec(createReturnParameterSpec(), defaultParameters); + return new MethodSpec(prefixTypes, createReturnParameterSpec(), defaultParameters); } private static String shortCircuitValueName(String valueName) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeCodeGenerator.java Wed Mar 06 18:32:33 2013 +0100 @@ -51,32 +51,18 @@ } private static String factoryClassName(NodeData node) { - return nodeClassName(node) + "Factory"; - } - - private static String nodeClassName(NodeData node) { - return Utils.getSimpleName(node.getTemplateType().asType()); + return node.getNodeId() + "Factory"; } - private static String nodeClassName(SpecializationData specialization) { - String name = specializationId(specialization); - name += nodeClassName(specialization.getNode()); - if (name.equals(Utils.getSimpleName(specialization.getNode().getNodeType())) || name.equals(Utils.getSimpleName(specialization.getNode().getTemplateType()))) { - name = name + "Impl"; + 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); } - return name; - } - - private static String specializationId(SpecializationData specialization) { - String name = ""; - NodeData node = specialization.getNode(); - if (node.getSpecializations().size() > 1) { - name = specialization.getMethodName(); - if (name.startsWith("do")) { - name = name.substring(2); - } - } + String name = Utils.firstLetterUpperCase(nodeid); + name += Utils.firstLetterUpperCase(specialization.getId()); + name += "Node"; return name; } @@ -88,7 +74,7 @@ return valueName(parameter) + "Cast"; } - private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame) { + private void addValueParameters(CodeExecutableElement method, TemplateMethod specialization, boolean forceFrame, boolean includeHidden) { if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { method.addParameter(new CodeVariableElement(getContext().getTruffleTypes().getFrame(), "frameValue")); } @@ -97,11 +83,15 @@ if (forceFrame && spec.getName().equals("frame")) { continue; } + if (!includeHidden && parameter.isHidden()) { + continue; + } + method.addParameter(new CodeVariableElement(parameter.getActualType(), valueName(parameter))); } } - private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame) { + private static void addValueParameterNames(CodeTreeBuilder builder, TemplateMethod specialization, String unexpectedValueName, boolean forceFrame, boolean includeHidden) { if (forceFrame && specialization.getSpecification().findParameterSpec("frame") != null) { builder.string("frameValue"); } @@ -111,6 +101,10 @@ continue; } + if (!includeHidden && parameter.isHidden()) { + continue; + } + if (unexpectedValueName != null && parameter.getName().equals(unexpectedValueName)) { builder.string("ex.getResult()"); } else { @@ -119,7 +113,7 @@ } } - private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization) { + private static void addValueParameterNamesWithCasts(CodeTreeBuilder body, SpecializationData valueSpecialization, SpecializationData targetSpecialization, boolean includeHidden) { NodeData node = targetSpecialization.getNode(); TypeSystemData typeSystem = node.getTypeSystem(); @@ -127,6 +121,10 @@ ActualParameter valueParameter = valueSpecialization.findParameter(targetParameter.getName()); TypeData targetType = targetParameter.getActualTypeData(typeSystem); + if (!includeHidden && (targetParameter.isHidden() || valueParameter.isHidden())) { + continue; + } + TypeData valueType = null; if (valueParameter != null) { valueType = valueParameter.getActualTypeData(typeSystem); @@ -144,15 +142,34 @@ return getSimpleName(operation.getTemplateType()) + "Gen"; } - private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod method) { + private static void startCallOperationMethod(CodeTreeBuilder body, TemplateMethod templateMethod, boolean castedValues) { body.startGroup(); - if (body.findMethod().getModifiers().contains(STATIC)) { - body.string(THIS_NODE_LOCAL_VAR_NAME); + ExecutableElement method = templateMethod.getMethod(); + + TypeElement targetClass = Utils.findNearestEnclosingType(method.getEnclosingElement()); + NodeData node = (NodeData) templateMethod.getTemplate(); + + boolean accessible = templateMethod.canBeAccessedByInstanceOf(node.getNodeType()); + if (accessible) { + if (body.findMethod().getModifiers().contains(STATIC)) { + body.string(THIS_NODE_LOCAL_VAR_NAME); + } else { + body.string("super"); + } } else { - body.string("super"); + if (method.getModifiers().contains(STATIC)) { + body.type(targetClass.asType()); + } else { + ActualParameter parameter = templateMethod.getParameters().get(0); + if (castedValues) { + body.string(castValueName(parameter)); + } else { + body.string(valueName(parameter)); + } + } } body.string("."); - body.startCall(method.getMethodName()); + body.startCall(method.getSimpleName().toString()); } private static String generatedGenericMethodName(SpecializationData specialization) { @@ -168,7 +185,7 @@ if (prev == null || prev.isUninitialized()) { return prefix; } else { - return prefix + specializationId(current); + return prefix + current.getId(); } } prev = current; @@ -249,8 +266,8 @@ if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { builder.string(andOperator); - startCallOperationMethod(builder, guard.getGuardDeclaration()); - addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization); + startCallOperationMethod(builder, guard.getGuardDeclaration(), true); + addValueParameterNamesWithCasts(builder, valueSpecialization, guardedSpecialization, false); builder.end().end(); // call andOperator = " && "; @@ -705,15 +722,21 @@ } List<TypeMirror> nodeTypesList = new ArrayList<>(); + TypeMirror prev = null; + boolean allSame = true; for (NodeData child : children) { - nodeTypesList.add(child.getTemplateType().asType()); + nodeTypesList.add(child.getNodeType()); + if (prev != null && !Utils.typeEquals(child.getNodeType(), prev)) { + allSame = false; + } + prev = child.getNodeType(); } TypeMirror commonNodeSuperType = Utils.getCommonSuperType(getContext(), nodeTypesList.toArray(new TypeMirror[nodeTypesList.size()])); Types types = getContext().getEnvironment().getTypeUtils(); TypeMirror factoryType = getContext().getType(NodeFactory.class); TypeMirror baseType; - if (children.size() == 1) { + if (allSame) { baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), commonNodeSuperType); } else { baseType = types.getDeclaredType(Utils.fromTypeMirror(factoryType), types.getWildcardType(commonNodeSuperType, null)); @@ -784,7 +807,7 @@ if (node.getSpecializations().isEmpty()) { body.null_(); } else { - body.startNew(nodeClassName(node.getSpecializations().get(0))); + body.startNew(nodeSpecializationClassName(node.getSpecializations().get(0))); for (VariableElement var : method.getParameters()) { body.string(var.getSimpleName().toString()); } @@ -816,14 +839,14 @@ body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); - body.startReturn().startNew(nodeClassName(specialization)); + body.startReturn().startNew(nodeSpecializationClassName(specialization)); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); // new, return body.end(); // if } } - body.startReturn().startNew(nodeClassName(node.getGenericSpecialization())); + body.startReturn().startNew(nodeSpecializationClassName(node.getGenericSpecialization())); body.string(THIS_NODE_LOCAL_VAR_NAME); body.end().end(); return method; @@ -833,17 +856,17 @@ CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), node.getNodeType(), "specialize"); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); - addValueParameters(method, node.getGenericSpecialization(), false); + addValueParameters(method, node.getGenericSpecialization(), false, true); CodeTreeBuilder body = method.createBuilder(); - body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(node.getSpecializations().get(0))).string(".class)").end(); + body.startStatement().string("boolean allowed = (minimumState == ").string(nodeSpecializationClassName(node.getSpecializations().get(0))).string(".class)").end(); for (int i = 1; i < node.getSpecializations().size(); i++) { SpecializationData specialization = node.getSpecializations().get(i); - body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); + body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeSpecializationClassName(specialization)).string(".class)").end(); CodeTreeBuilder guarded = new CodeTreeBuilder(body); - guarded.startReturn().startNew(nodeClassName(specialization)); + guarded.startReturn().startNew(nodeSpecializationClassName(specialization)); guarded.string(THIS_NODE_LOCAL_VAR_NAME); guarded.end().end(); @@ -871,7 +894,7 @@ String methodName = generatedGenericMethodName(current); CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, methodName); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addValueParameters(method, node.getGenericSpecialization(), true, true); emitGeneratedGenericSpecialization(method.createBuilder(), current, next); @@ -884,7 +907,7 @@ } else { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE, STATIC), genericReturnType, generatedGenericMethodName(null)); method.addParameter(new CodeVariableElement(node.getNodeType(), THIS_NODE_LOCAL_VAR_NAME)); - addValueParameters(method, node.getGenericSpecialization(), true); + addValueParameters(method, node.getGenericSpecialization(), true, true); emitInvokeDoMethod(method.createBuilder(), node.getGenericSpecialization(), 0); return Arrays.asList(method); } @@ -906,7 +929,7 @@ builder.startReturn().startCall(generatedGenericMethodName(next)); builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, next, null, true); + addValueParameterNames(builder, next, null, true, true); builder.end().end(); } } @@ -917,8 +940,8 @@ } builder.startReturn(); - startCallOperationMethod(builder, specialization); - addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization); + startCallOperationMethod(builder, specialization, true); + addValueParameterNamesWithCasts(builder, specialization.getNode().getGenericSpecialization(), specialization, false); builder.end().end(); // start call operation builder.end(); // return @@ -928,7 +951,7 @@ builder.startReturn().startCall(generatedGenericMethodName(exception.getTransitionTo())); builder.string(THIS_NODE_LOCAL_VAR_NAME); - addValueParameterNames(builder, exception.getTransitionTo(), null, true); + addValueParameterNames(builder, exception.getTransitionTo(), null, true, true); builder.end().end(); } builder.end(); @@ -945,7 +968,7 @@ @Override public CodeTypeElement create(SpecializationData specialization) { NodeData node = specialization.getNode(); - CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), node.getNodeType(), false); + CodeTypeElement clazz = createClass(node, modifiers(PRIVATE, STATIC, FINAL), nodeSpecializationClassName(specialization), node.getNodeType(), false); return clazz; } @@ -1110,7 +1133,7 @@ builder.startCall(factoryClassName(node), "specialize"); builder.string("this"); builder.typeLiteral(builder.findMethod().getEnclosingElement().asType()); - addValueParameterNames(builder, specialization, null, false); + addValueParameterNames(builder, specialization, null, false, true); builder.end(); // call replace, call specialize } else { builder.startCall(factoryClassName(node), "createSpecialized").string("this").string("null").end(); @@ -1129,17 +1152,17 @@ if ((specialization.isUninitialized() || specialization.isGeneric()) && node.needsRewrites(getContext())) { builder.startReturn().startCall(factoryClassName(node), generatedGenericMethodName(null)); builder.string("this"); - addValueParameterNames(builder, specialization, null, true); + addValueParameterNames(builder, specialization, null, true, true); builder.end().end(); } else { builder.startReturn(); if (specialization.isUninitialized()) { - startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization()); + startCallOperationMethod(builder, specialization.getNode().getGenericSpecialization(), false); } else { - startCallOperationMethod(builder, specialization); + startCallOperationMethod(builder, specialization, false); } - addValueParameterNames(builder, specialization, null, false); + addValueParameterNames(builder, specialization, null, false, false); builder.end().end(); // operation call builder.end(); // return } @@ -1156,17 +1179,14 @@ private CodeTree createExecuteChildren(CodeTreeBuilder parent, SpecializationData specialization) { CodeTreeBuilder builder = new CodeTreeBuilder(parent); + for (ActualParameter parameter : specialization.getParameters()) { NodeFieldData field = specialization.getNode().findField(parameter.getSpecification().getName()); if (field == null) { continue; } - if (parameter.getActualTypeData(specialization.getNode().getTypeSystem()).isGeneric()) { - buildGenericValueExecute(builder, specialization, parameter, field, null); - } else { - buildSpecializedValueExecute(builder, specialization, parameter, field); - } + buildFieldExecute(builder, specialization, parameter, field, null); } return builder.getRoot(); } @@ -1174,33 +1194,55 @@ private void emitSpecializationListeners(CodeTreeBuilder builder, NodeData node) { for (TemplateMethod listener : node.getSpecializationListeners()) { builder.startStatement(); - startCallOperationMethod(builder, listener); - addValueParameterNames(builder, listener, null, false); + startCallOperationMethod(builder, listener, false); + addValueParameterNames(builder, listener, null, false, false); builder.end().end(); builder.end(); // statement } } - private void buildGenericValueExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) { - NodeData node = specialization.getNode(); + private void buildFieldExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field, ActualParameter exceptionParam) { boolean shortCircuit = startShortCircuit(builder, specialization, param, exceptionParam); + ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); + boolean unexpected = execType.hasUnexpectedValue(getContext()); - builder.startStatement(); - if (!shortCircuit) { - builder.type(specialization.getNode().getTypeSystem().getGenericType()); - builder.string(" "); + if (!shortCircuit && unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); + } + + if (unexpected) { + builder.startTryBlock(); } - builder.string(valueName(param)); - builder.string(" = "); - ExecutableTypeData genericExecutableType = field.getNodeData().findGenericExecutableType(getContext(), param.getActualTypeData(node.getTypeSystem())); - if (genericExecutableType == null) { - throw new AssertionError("Must have generic executable type. Parser validation most likely failed. " + (field.getNodeData().getExecutableTypes())); + if (!shortCircuit && !unexpected) { + builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).string(" = "); + } else { + builder.startStatement().string(valueName(param)).string(" = "); } - buildExecute(builder, param, field, genericExecutableType); + buildExecute(builder, param, field, execType); builder.end(); + if (unexpected) { + builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); + SpecializationData generic = specialization.getNode().getGenericSpecialization(); + boolean execute = false; + for (ActualParameter exParam : generic.getParameters()) { + NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName()); + if (exField == null) { + continue; + } + if (execute) { + buildFieldExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param); + } else if (exParam.getName().equals(param.getName())) { + execute = true; + } + } + builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param)); + builder.end(); // catch block + } + endShortCircuit(builder, shortCircuit); + builder.newLine(); } private void buildExecute(CodeTreeBuilder builder, ActualParameter parameter, NodeFieldData field, ExecutableTypeData execType) { @@ -1219,52 +1261,12 @@ builder.string("."); } builder.startCall(execType.getMethodName()); - if (execType.getParameters().length == 1) { + if (execType.getParameters().size() == 1) { builder.string("frameValue"); } builder.end(); } - private void buildSpecializedValueExecute(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter param, NodeFieldData field) { - boolean shortCircuit = startShortCircuit(builder, specialization, param, null); - - if (!shortCircuit) { - builder.startStatement().type(param.getActualType()).string(" ").string(valueName(param)).end(); - } - - ExecutableTypeData execType = field.getNodeData().findExecutableType(param.getActualTypeData(field.getNodeData().getTypeSystem())); - - if (execType.hasUnexpectedValue(getContext())) { - builder.startTryBlock(); - } - - builder.startStatement().string(valueName(param)).string(" = "); - buildExecute(builder, param, field, execType); - builder.end(); - - if (execType.hasUnexpectedValue(getContext())) { - builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); - SpecializationData generic = specialization.getNode().getGenericSpecialization(); - boolean execute = false; - for (ActualParameter exParam : generic.getParameters()) { - NodeFieldData exField = generic.getNode().findField(exParam.getSpecification().getName()); - if (exField == null) { - continue; - } - if (execute) { - buildGenericValueExecute(builder, specialization.getNode().getGenericSpecialization(), exParam, exField, param); - } else if (exParam.getName().equals(param.getName())) { - execute = true; - } - } - builder.tree(createReturnSpecializeAndExecute(builder, specialization.findNextSpecialization(), param)); - builder.end(); // catch block - } - - endShortCircuit(builder, shortCircuit); - builder.newLine(); - } - private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter parameter, ActualParameter exceptionParam) { NodeFieldData forField = specialization.getNode().findField(parameter.getSpecification().getName()); if (forField == null) { @@ -1290,8 +1292,8 @@ builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(valueName(shortCircuitParam)).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; - startCallOperationMethod(builder, shortCircuitData); - addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false); + startCallOperationMethod(builder, shortCircuitData, false); + addValueParameterNames(builder, shortCircuitData, exceptionParam != null ? exceptionParam.getName() : null, false, false); builder.end().end(); // call operation builder.end(); // statement @@ -1312,8 +1314,8 @@ private CodeTree createReturnSpecializeAndExecute(CodeTreeBuilder parent, SpecializationData nextSpecialization, ActualParameter exceptionParam) { CodeTreeBuilder specializeCall = new CodeTreeBuilder(parent); specializeCall.startCall("specializeAndExecute"); - specializeCall.string(nodeClassName(nextSpecialization) + ".class"); - addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true); + specializeCall.string(nodeSpecializationClassName(nextSpecialization) + ".class"); + addValueParameterNames(specializeCall, nextSpecialization.getNode().getGenericSpecialization(), exceptionParam != null ? exceptionParam.getName() : null, true, true); specializeCall.end().end(); CodeTreeBuilder builder = new CodeTreeBuilder(parent); @@ -1334,7 +1336,7 @@ if (canThrowUnexpected) { method.addThrownType(getUnexpectedValueException()); } - addValueParameters(method, specialization.getNode().getGenericSpecialization(), true); + addValueParameters(method, specialization.getNode().getGenericSpecialization(), true, true); clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); @@ -1345,7 +1347,7 @@ builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(specialization.getNode()), "specialize").string("this").string("minimumState"); - addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false); + addValueParameterNames(builder, specialization.getNode().getGenericSpecialization(), null, false, true); builder.end(); builder.end(); // call replace builder.end(); // statement @@ -1356,7 +1358,7 @@ CodeTreeBuilder genericExecute = CodeTreeBuilder.createBuilder(); genericExecute.startCall(factoryClassName(specialization.getNode()), generatedMethodName); genericExecute.string("this"); - addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true); + addValueParameterNames(genericExecute, specialization.getNode().getGenericSpecialization(), null, true, true); genericExecute.end(); // call generated generic CodeTree genericInvocation = createExpectType(node, returnExecutableType, genericExecute.getRoot());
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeData.java Wed Mar 06 18:32:33 2013 +0100 @@ -35,12 +35,14 @@ public class NodeData extends Template { + private final String nodeId; private NodeData declaringNode; - private List<NodeData> declaredChildren; + private List<NodeData> declaredChildren = new ArrayList<>(); private final TypeSystemData typeSystem; private List<NodeFieldData> fields; private TypeMirror nodeType; + private ParameterSpec instanceParameterSpec; private List<SpecializationData> specializations; private List<SpecializationListenerData> specializationListeners; @@ -48,11 +50,46 @@ private List<ExecutableTypeData> executableTypes; private List<ShortCircuitData> shortCircuits; - public NodeData(TypeElement type, TypeSystemData typeSystem) { + public NodeData(TypeElement type, TypeSystemData typeSystem, String id) { super(type, null); + this.nodeId = id; this.typeSystem = typeSystem; } + public NodeData(NodeData copy, String nodeId) { + super(copy.getTemplateType(), null); + this.nodeId = nodeId; + this.declaringNode = copy.declaringNode; + this.declaredChildren = copy.declaredChildren; + this.typeSystem = copy.typeSystem; + this.nodeType = copy.nodeType; + this.specializations = copy.specializations; + this.specializationListeners = copy.specializationListeners; + this.guards = copy.guards; + this.executableTypes = copy.executableTypes; + this.shortCircuits = copy.shortCircuits; + + List<NodeFieldData> fieldsCopy = new ArrayList<>(); + for (NodeFieldData field : copy.fields) { + NodeFieldData newField = new NodeFieldData(field); + newField.setNode(this); + fieldsCopy.add(newField); + } + this.fields = fieldsCopy; + } + + public ParameterSpec getInstanceParameterSpec() { + return instanceParameterSpec; + } + + public void setInstanceParameterSpec(ParameterSpec instanceParameter) { + this.instanceParameterSpec = instanceParameter; + } + + public String getNodeId() { + return nodeId; + } + public TypeMirror getNodeType() { if (nodeType != null) { return nodeType; @@ -247,8 +284,9 @@ public String dump() { StringBuilder b = new StringBuilder(); - b.append(String.format("[name = %s\n" + " typeSystem = %s\n" + " fields = %s\n" + " types = %s\n" + " specializations = %s\n" + " guards = %s\n" + "]", - Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards))); + b.append(String.format("[id = %s, name = %s\n typeSystem = %s\n fields = %s\n types = %s\n specializations = %s\n guards = %s\n enclosing = %s\n enclosed = %s\n]", getNodeId(), + Utils.getQualifiedName(getTemplateType()), getTypeSystem(), dumpList(fields), dumpList(getExecutableTypes()), dumpList(getSpecializations()), dumpList(guards), + dumpList(getDeclaredChildren()), getParent())); return b.toString(); } @@ -287,7 +325,21 @@ } public List<SpecializationData> getSpecializations() { - return specializations; + return getSpecializations(false); + } + + public List<SpecializationData> getSpecializations(boolean userDefinedOnly) { + if (userDefinedOnly) { + List<SpecializationData> specs = new ArrayList<>(); + for (SpecializationData spec : specializations) { + if (spec.getMethod() != null) { + specs.add(spec); + } + } + return specs; + } else { + return specializations; + } } public List<SpecializationListenerData> getSpecializationListeners() { @@ -308,8 +360,10 @@ void setSpecializations(List<SpecializationData> specializations) { this.specializations = specializations; - for (SpecializationData specialization : specializations) { - specialization.setNode(this); + if (this.specializations != null) { + for (SpecializationData specialization : specializations) { + specialization.setNode(this); + } } } @@ -329,4 +383,9 @@ this.shortCircuits = shortCircuits; } + @Override + public String toString() { + return getClass().getSimpleName() + "[" + getNodeId() + "]"; + } + }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeFieldData.java Wed Mar 06 18:32:33 2013 +0100 @@ -41,7 +41,7 @@ private final FieldKind fieldKind; private final ExecutionKind executionKind; - private final NodeData nodeData; + private NodeData nodeData; public NodeFieldData(NodeData typeNodeData, VariableElement fieldElement, Element accessElement, AnnotationMirror childAnnotationMirror, FieldKind fieldKind, ExecutionKind executionKind) { this.fieldElement = fieldElement; @@ -52,10 +52,23 @@ this.executionKind = executionKind; } + NodeFieldData(NodeFieldData field) { + this.fieldElement = field.fieldElement; + this.accessElement = field.accessElement; + this.childAnnotationMirror = field.childAnnotationMirror; + this.fieldKind = field.fieldKind; + this.executionKind = field.executionKind; + this.nodeData = field.nodeData; + } + public boolean isShortCircuit() { return executionKind == ExecutionKind.SHORT_CIRCUIT; } + void setNode(NodeData nodeData) { + this.nodeData = nodeData; + } + public VariableElement getFieldElement() { return fieldElement; }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/NodeParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -44,7 +44,6 @@ public static final List<Class<? extends Annotation>> ANNOTATIONS = Arrays.asList(Generic.class, TypeSystemReference.class, ShortCircuit.class, Specialization.class, SpecializationListener.class); private Map<String, NodeData> parsedNodes; - private TypeElement originalType; public NodeParser(ProcessorContext c) { super(c); @@ -53,23 +52,14 @@ @Override protected NodeData parse(Element element, AnnotationMirror mirror) { assert element instanceof TypeElement; + NodeData node = null; try { parsedNodes = new HashMap<>(); - originalType = (TypeElement) element; - - return parseInnerClassHierarchy((TypeElement) element); + node = parseInnerClassHierarchy((TypeElement) element); } finally { - if (Log.DEBUG) { - NodeData parsed = parsedNodes.get(Utils.getQualifiedName(originalType)); - if (parsed != null) { - String dump = parsed.dump(); - log.error("Node parsed: %s", dump); - System.out.println("Parsed: " + dump); - } - } parsedNodes = null; - originalType = null; } + return node; } @Override @@ -88,9 +78,10 @@ } NodeData rootNode = resolveNode(rootType); if (rootNode == null && children.size() > 0) { - rootNode = new NodeData(rootType, null); + rootNode = new NodeData(rootType, null, rootType.getSimpleName().toString()); } if (rootNode != null) { + children.addAll(rootNode.getDeclaredChildren()); rootNode.setDeclaredChildren(children); } @@ -104,6 +95,18 @@ if (node != null) { parsedNodes.put(typeName, node); } + + if (Log.DEBUG) { + NodeData parsed = parsedNodes.get(Utils.getQualifiedName(currentType)); + if (parsed != null) { + String dump = parsed.dump(); + String valid = node != null ? "" : " failed"; + String msg = String.format("Node parsing %s : %s", valid, dump); + log.error(msg); + System.out.println(msg); + } + } + return node; } return parsedNodes.get(typeName); @@ -121,13 +124,22 @@ return null; // not a node } + TypeElement nodeType; + boolean needsSplit; + if (methodNodes != null) { + needsSplit = methodNodes != null; + nodeType = Utils.fromTypeMirror(Utils.getAnnotationValueType(methodNodes, "value")); + } else { + needsSplit = false; + nodeType = type; + } + if (type.getModifiers().contains(Modifier.PRIVATE)) { return null; // not visible } - final NodeData nodeData = parseNodeData(type); + NodeData nodeData = parseNodeData(type, nodeType); if (nodeData == null) { - // TODO error message for instanceBaseClass? return null; } @@ -140,17 +152,96 @@ if (!parseMethods(nodeData, elements)) { return null; } - // TODO split - if (!finalizeSpecializations(nodeData)) { + List<NodeData> nodes; + if (needsSplit) { + nodes = splitNodeData(nodeData); + if (nodes == null) { + return null; + } + } else { + nodes = new ArrayList<>(); + nodes.add(nodeData); + } + + boolean valid = true; + for (NodeData splittedNode : nodes) { + if (!finalizeSpecializations(splittedNode)) { + valid = false; + } + if (!verifyNode(splittedNode)) { + valid = false; + } + } + if (!valid) { return null; } - if (!verifyNode(nodeData)) { - return null; + if (needsSplit) { + nodeData.setDeclaredChildren(nodes); + nodeData.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); + nodeData.setSpecializations(new ArrayList<SpecializationData>()); + return nodeData; + } else { + return nodeData; + } + } + + private static List<NodeData> splitNodeData(NodeData node) { + SortedMap<String, List<SpecializationData>> groupedSpecializations = groupByNodeId(node.getSpecializations()); + SortedMap<String, List<SpecializationListenerData>> groupedListeners = groupByNodeId(node.getSpecializationListeners()); + + Set<String> ids = new TreeSet<>(); + ids.addAll(groupedSpecializations.keySet()); + ids.addAll(groupedListeners.keySet()); + + List<NodeData> splitted = new ArrayList<>(); + for (String id : ids) { + List<SpecializationData> specializations = groupedSpecializations.get(id); + List<SpecializationListenerData> listeners = groupedListeners.get(id); + + if (specializations == null) { + specializations = new ArrayList<>(); + } + + if (listeners == null) { + listeners = new ArrayList<>(); + } + + String nodeId = node.getNodeId(); + if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { + nodeId = nodeId.substring(0, nodeId.length() - 4); + } + String newNodeId = nodeId + Utils.firstLetterUpperCase(id); + NodeData copy = new NodeData(node, newNodeId); + + copy.setSpecializations(specializations); + copy.setSpecializationListeners(listeners); + + splitted.add(copy); } - return nodeData; + if (splitted.isEmpty()) { + splitted.add(node); + } + + node.setSpecializations(new ArrayList<SpecializationData>()); + node.setSpecializationListeners(new ArrayList<SpecializationListenerData>()); + + return splitted; + } + + private static <M extends TemplateMethod> SortedMap<String, List<M>> groupByNodeId(List<M> methods) { + SortedMap<String, List<M>> grouped = new TreeMap<>(); + for (M m : methods) { + List<M> list = grouped.get(m.getId()); + if (list == null) { + list = new ArrayList<>(); + grouped.put(m.getId(), list); + } + list.add(m); + } + return grouped; } private boolean parseMethods(final NodeData node, List<Element> elements) { @@ -176,6 +267,10 @@ private boolean finalizeSpecializations(final NodeData node) { List<SpecializationData> specializations = new ArrayList<>(node.getSpecializations()); + if (specializations.isEmpty()) { + return true; + } + List<SpecializationData> generics = new ArrayList<>(); for (SpecializationData spec : specializations) { if (spec.isGeneric()) { @@ -191,6 +286,8 @@ return false; } else if (generics.size() == 1) { genericSpecialization = generics.get(0); + } else { + // TODO support generation of generic if not ambiguous. } if (specializations.size() > 1 && genericSpecialization == null) { @@ -215,9 +312,101 @@ node.setSpecializations(specializations); + for (SpecializationData specialization : specializations) { + specialization.setId(findUniqueSpecializationId(specialization)); + } + return true; } + private static String findUniqueSpecializationId(SpecializationData specialization) { + + String name; + if (specialization.isGeneric()) { + name = "Generic"; + } else if (specialization.isUninitialized()) { + name = "Uninitialized"; + } else { + List<SpecializationData> specializations = new ArrayList<>(specialization.getNode().getSpecializations()); + for (ListIterator<SpecializationData> iterator = specializations.listIterator(); iterator.hasNext();) { + SpecializationData data = iterator.next(); + if (data.isGeneric() || data.isUninitialized()) { + iterator.remove(); + } + } + + Map<ParameterSpec, Set<String>> usedIds = new HashMap<>(); + for (SpecializationData other : specializations) { + for (ActualParameter param : other.getReturnTypeAndParameters()) { + if (other.getNode().findField(param.getSpecification().getName()) == null) { + continue; + } + + Set<String> types = usedIds.get(param.getSpecification()); + if (types == null) { + types = new HashSet<>(); + usedIds.put(param.getSpecification(), types); + } + types.add(Utils.getTypeId(param.getActualType())); + } + } + + List<ParameterSpec> ambiguousSpecs = new ArrayList<>(); + for (ActualParameter param : specialization.getReturnTypeAndParameters()) { + Set<String> ids = usedIds.get(param.getSpecification()); + if (ids != null && ids.size() > 1) { + ambiguousSpecs.add(param.getSpecification()); + } + } + + String specializationId = findSpecializationId(specialization, ambiguousSpecs); + int specializationIndex = 0; + int totalIndex = 0; + + for (SpecializationData other : specializations) { + String id = findSpecializationId(other, ambiguousSpecs); + if (id.equals(specializationId)) { + totalIndex++; + if (specialization == other) { + specializationIndex = totalIndex; + } + } + } + + if (specializationIndex != totalIndex) { + name = specializationId + specializationIndex; + } else { + name = specializationId; + } + } + return name; + } + + private static String findSpecializationId(SpecializationData specialization, List<ParameterSpec> specs) { + boolean allSame = true; + ActualParameter prevParam = specialization.getReturnType(); + for (ParameterSpec spec : specs) { + ActualParameter param = specialization.findParameter(spec); + if (!Utils.typeEquals(prevParam.getActualType(), param.getActualType())) { + allSame = false; + break; + } + prevParam = param; + } + + if (allSame) { + return Utils.getTypeId(prevParam.getActualType()); + } else { + StringBuilder nameBuilder = new StringBuilder(); + nameBuilder.append(Utils.getTypeId(prevParam.getActualType())); + for (ParameterSpec spec : specs) { + ActualParameter param = specialization.findParameter(spec); + nameBuilder.append(Utils.getTypeId(param.getActualType())); + } + return nameBuilder.toString(); + } + } + private boolean verifyNode(NodeData nodeData) { // verify specialization parameter length if (!verifySpecializationParameters(nodeData)) { @@ -260,37 +449,49 @@ return true; } - private NodeData parseNodeData(TypeElement type) { - List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(type)); - List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), type); + private NodeData parseNodeData(TypeElement templateType, TypeElement nodeType) { + List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(nodeType)); + List<TypeElement> typeHierarchy = findSuperClasses(new ArrayList<TypeElement>(), nodeType); Collections.reverse(typeHierarchy); AnnotationMirror typeSystemMirror = findFirstAnnotation(typeHierarchy, TypeSystemReference.class); if (typeSystemMirror == null) { - log.error(type, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), type.getQualifiedName().toString()); + log.error(templateType, "No @%s annotation found in type hierarchy of %s.", TypeSystemReference.class.getSimpleName(), nodeType.getQualifiedName().toString()); return null; } TypeMirror typeSytemType = Utils.getAnnotationValueType(typeSystemMirror, "value"); final TypeSystemData typeSystem = (TypeSystemData) context.getTemplate(typeSytemType, true); if (typeSystem == null) { - log.error(type, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); + log.error(templateType, "The used type system '%s' is invalid.", Utils.getQualifiedName(typeSytemType)); return null; } - NodeData nodeData = new NodeData(type, typeSystem); + String nodeId = templateType.getSimpleName().toString(); + if (nodeId.endsWith("Node") && !nodeId.equals("Node")) { + nodeId = nodeId.substring(0, nodeId.length() - 4); + } + + NodeData nodeData = new NodeData(templateType, typeSystem, templateType.getSimpleName().toString()); + nodeData.setNodeType(nodeType.asType()); List<ExecutableTypeData> executableTypes = filterExecutableTypes(new ExecutableTypeMethodParser(context, nodeData).parse(elements)); nodeData.setExecutableTypes(executableTypes); - parsedNodes.put(Utils.getQualifiedName(type), nodeData); + parsedNodes.put(Utils.getQualifiedName(nodeType), nodeData); List<NodeFieldData> fields = parseFields(nodeData, elements, typeHierarchy); if (fields == null) { return null; } nodeData.setFields(fields); + + if (!Utils.isAssignable(templateType.asType(), nodeType.asType())) { +// nodeData.setInstanceParameterSpec(new ParameterSpec("instance", templateType.asType(), false, +// true)); + } + return nodeData; } @@ -669,6 +870,7 @@ return valid; } + @SuppressWarnings("unused") private boolean verifyNamesUnique(List<? extends TemplateMethod> methods) { boolean valid = true; for (int i = 0; i < methods.size(); i++) { @@ -770,8 +972,6 @@ } private boolean verifySpecializationThrows(NodeData node) { - TypeSystemData typeSystem = node.getTypeSystem(); - Map<String, SpecializationData> specializationMap = new HashMap<>(); for (SpecializationData spec : node.getSpecializations()) { specializationMap.put(spec.getMethodName(), spec);
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/ShortCircuitParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -55,7 +55,7 @@ return null; } - return createDefaultMethodSpec(shortCircuitValue); + return createDefaultMethodSpec(method, mirror, shortCircuitValue); } @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationListenerParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -32,16 +32,13 @@ public class SpecializationListenerParser extends MethodParser<SpecializationListenerData> { - private final MethodSpec specification; - public SpecializationListenerParser(ProcessorContext context, NodeData node) { super(context, node); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/node/SpecializationMethodParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -35,16 +35,13 @@ public class SpecializationMethodParser extends MethodParser<SpecializationData> { - private final MethodSpec specification; - public SpecializationMethodParser(ProcessorContext context, NodeData operation) { super(context, operation); - this.specification = createDefaultMethodSpec(null); } @Override public MethodSpec createSpecification(ExecutableElement method, AnnotationMirror mirror) { - return specification; + return createDefaultMethodSpec(method, mirror, null); } @Override @@ -148,7 +145,7 @@ } private static boolean isGuardCompatible(SpecializationData specialization, GuardData guard) { - Iterator<ActualParameter> guardParameters = Arrays.asList(guard.getParameters()).iterator(); + Iterator<ActualParameter> guardParameters = guard.getParameters().iterator(); for (ActualParameter param : specialization.getParameters()) { if (param.getSpecification().isOptional()) { continue;
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/ActualParameter.java Wed Mar 06 18:32:33 2013 +0100 @@ -33,12 +33,14 @@ private TemplateMethod method; private final String name; private final int index; + private final boolean hidden; - public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index) { + public ActualParameter(ParameterSpec specification, TypeMirror actualType, int index, boolean hidden) { this.specification = specification; this.actualType = actualType; this.index = index; + this.hidden = hidden; String valueName = specification.getName() + "Value"; if (specification.isIndexed()) { valueName = valueName + index; @@ -46,6 +48,10 @@ this.name = valueName; } + public boolean isHidden() { + return hidden; + } + public int getIndex() { return index; }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/MethodSpec.java Wed Mar 06 18:32:33 2013 +0100 @@ -24,16 +24,25 @@ import java.util.*; +import javax.lang.model.type.*; + public class MethodSpec { + private final List<TypeMirror> implicitTypes; + private final ParameterSpec returnType; private final List<ParameterSpec> parameters; - public MethodSpec(ParameterSpec returnType, List<ParameterSpec> parameters) { + public MethodSpec(List<TypeMirror> prefixTypes, ParameterSpec returnType, List<ParameterSpec> parameters) { + this.implicitTypes = prefixTypes; this.returnType = returnType; this.parameters = parameters; } + public List<TypeMirror> getImplicitTypes() { + return implicitTypes; + } + public ParameterSpec getReturnType() { return returnType; }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethod.java Wed Mar 06 18:32:33 2013 +0100 @@ -22,19 +22,25 @@ */ package com.oracle.truffle.codegen.processor.template; +import java.util.*; + import javax.lang.model.element.*; +import javax.lang.model.type.*; + +import com.oracle.truffle.codegen.processor.*; public class TemplateMethod { - private final String id; + private String id; private final Template template; private final MethodSpec specification; private final ExecutableElement method; private final AnnotationMirror markerAnnotation; private final ActualParameter returnType; - private final ActualParameter[] parameters; + private final List<ActualParameter> parameters; - public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, ActualParameter[] parameters) { + public TemplateMethod(String id, Template template, MethodSpec specification, ExecutableElement method, AnnotationMirror markerAnnotation, ActualParameter returnType, + List<ActualParameter> parameters) { this.template = template; this.specification = specification; this.method = method; @@ -54,6 +60,10 @@ this(method.id, method.template, method.specification, method.method, method.markerAnnotation, method.returnType, method.parameters); } + public void setId(String id) { + this.id = id; + } + public String getId() { return id; } @@ -70,7 +80,7 @@ return returnType; } - public ActualParameter[] getParameters() { + public List<ActualParameter> getParameters() { return parameters; } @@ -83,15 +93,27 @@ return null; } + public List<ActualParameter> getReturnTypeAndParameters() { + List<ActualParameter> allParameters = new ArrayList<>(getParameters().size() + 1); + allParameters.add(getReturnType()); + allParameters.addAll(getParameters()); + return Collections.unmodifiableList(allParameters); + } + public ActualParameter findParameter(ParameterSpec spec) { for (ActualParameter param : getParameters()) { - if (param.getSpecification() == spec) { + if (param.getSpecification().getName().equals(spec.getName())) { return param; } } return null; } + public boolean canBeAccessedByInstanceOf(TypeMirror type) { + TypeMirror methodType = Utils.findNearestEnclosingType(getMethod()).asType(); + return Utils.isAssignable(type, methodType) || Utils.isAssignable(methodType, type); + } + public ExecutableElement getMethod() { return method; } @@ -106,7 +128,7 @@ @Override public String toString() { - return getClass().getSimpleName() + " [method = " + method + "]"; + return "id = " + getId() + ", " + getClass().getSimpleName() + " [method = " + getMethod() + "]"; } public ActualParameter getPreviousParam(ActualParameter searchParam) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/template/TemplateMethodParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -102,7 +102,7 @@ continue; } - E parsedMethod = parseNew(method, mirror); + E parsedMethod = parse(method, mirror); if (parsedMethod != null) { parsedMethods.add(parsedMethod); } else { @@ -115,7 +115,7 @@ return parsedMethods; } - private E parseNew(ExecutableElement method, AnnotationMirror annotation) { + private E parse(ExecutableElement method, AnnotationMirror annotation) { MethodSpec methodSpecification = createSpecification(method, annotation); if (methodSpecification == null) { return null; @@ -127,7 +127,7 @@ List<ParameterSpec> parameterSpecs = new ArrayList<>(); parameterSpecs.addAll(methodSpecification.getParameters()); - ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0); + ActualParameter returnTypeMirror = matchParameter(returnTypeSpec, method.getReturnType(), template, 0, false); if (returnTypeMirror == null) { if (isEmitErrors()) { String expectedReturnType = createTypeSignature(returnTypeSpec, typeDefs, true); @@ -141,10 +141,16 @@ return null; } - List<ActualParameter> parameters = parseParameters(method, parameterSpecs); + List<TypeMirror> parameterTypes = new ArrayList<>(); + parameterTypes.addAll(methodSpecification.getImplicitTypes()); + for (VariableElement var : method.getParameters()) { + parameterTypes.add(var.asType()); + } + + List<ActualParameter> parameters = parseParameters(parameterTypes, parameterSpecs, methodSpecification.getImplicitTypes().size()); if (parameters == null) { if (isEmitErrors()) { - String message = String.format("Method signature mismatch. Expected signature: \n%s", + String message = String.format("Method signature %s does not match to the expected signature: \n%s", createActualSignature(methodSpecification, method), createExpectedSignature(method.getSimpleName().toString(), returnTypeSpec, parameterSpecs, typeDefs)); context.getLog().error(method, annotation, message); } @@ -157,35 +163,56 @@ id = Utils.getAnnotationValueString(idAnnotation, "value"); } - ActualParameter[] paramMirrors = parameters.toArray(new ActualParameter[parameters.size()]); - return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, paramMirrors)); + return create(new TemplateMethod(id, template, methodSpecification, method, annotation, returnTypeMirror, parameters)); } - private List<ActualParameter> parseParameters(ExecutableElement method, List<ParameterSpec> parameterSpecs) { - Iterator<? extends VariableElement> parameterIterator = method.getParameters().iterator(); + private static String createActualSignature(MethodSpec spec, ExecutableElement method) { + List<String> types = new ArrayList<>(); + for (TypeMirror implicitType : spec.getImplicitTypes()) { + types.add("implicit " + Utils.getSimpleName(implicitType)); + } + for (VariableElement var : method.getParameters()) { + types.add(Utils.getSimpleName(var.asType())); + } + + StringBuilder b = new StringBuilder("("); + for (Iterator<String> iterator = types.iterator(); iterator.hasNext();) { + b.append(iterator.next()); + if (iterator.hasNext()) { + b.append(", "); + } + } + b.append(")"); + return b.toString(); + } + + private List<ActualParameter> parseParameters(List<TypeMirror> types, List<ParameterSpec> parameterSpecs, int hiddenCount) { + Iterator<? extends TypeMirror> parameterIterator = types.iterator(); Iterator<? extends ParameterSpec> specificationIterator = parameterSpecs.iterator(); - VariableElement parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; + TypeMirror parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; ParameterSpec specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - int specificationIndex = 0; + int globalParameterIndex = 0; + int specificationParameterIndex = 0; List<ActualParameter> resolvedParameters = new ArrayList<>(); while (parameter != null || specification != null) { if (parameter == null || specification == null) { if (specification != null && (specification.isOptional() || specification.getCardinality() == Cardinality.MULTIPLE)) { specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - specificationIndex = 0; + specificationParameterIndex = 0; continue; } return null; } - ActualParameter resolvedParameter = matchParameter(specification, parameter.asType(), template, specificationIndex); + boolean hidden = globalParameterIndex < hiddenCount; + ActualParameter resolvedParameter = matchParameter(specification, parameter, template, specificationParameterIndex, hidden); if (resolvedParameter == null) { // mismatch if (specification.isOptional()) { specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - specificationIndex = 0; + specificationParameterIndex = 0; } else { return null; } @@ -196,17 +223,19 @@ if (specification.getCardinality() == Cardinality.ONE) { parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; specification = specificationIterator.hasNext() ? specificationIterator.next() : null; - specificationIndex = 0; + globalParameterIndex++; + specificationParameterIndex = 0; } else if (specification.getCardinality() == Cardinality.MULTIPLE) { parameter = parameterIterator.hasNext() ? parameterIterator.next() : null; - specificationIndex++; + globalParameterIndex++; + specificationParameterIndex++; } } } return resolvedParameters; } - private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index) { + private ActualParameter matchParameter(ParameterSpec specification, TypeMirror mirror, Template typeSystem, int index, boolean hidden) { TypeMirror resolvedType = mirror; if (hasError(resolvedType)) { resolvedType = context.resolveNotYetCompiledType(mirror, typeSystem); @@ -215,7 +244,7 @@ if (!specification.matches(resolvedType)) { return null; } - return new ActualParameter(specification, resolvedType, index); + return new ActualParameter(specification, resolvedType, index, hidden); } protected List<TypeDef> createTypeDefinitions(ParameterSpec returnType, List<? extends ParameterSpec> parameters) {
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardData.java Wed Mar 06 18:32:33 2013 +0100 @@ -26,15 +26,8 @@ public class GuardData extends TemplateMethod { - private final Template origin; - - public GuardData(TemplateMethod method, Template origin) { + public GuardData(TemplateMethod method) { super(method); - this.origin = origin; - } - - public Template getOrigin() { - return origin; } }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/GuardParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.codegen.processor.*; import com.oracle.truffle.codegen.processor.template.*; @@ -47,7 +48,7 @@ List<ParameterSpec> specs = new ArrayList<>(); specs.add(new ParameterSpec("valueN", typeSystem, false, Cardinality.MULTIPLE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - return new MethodSpec(returnTypeSpec, specs); + return new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs); } @Override @@ -57,7 +58,7 @@ @Override public GuardData create(TemplateMethod method) { - return new GuardData(method, template); + return new GuardData(method); } @Override
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCastParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -47,7 +48,7 @@ List<ParameterSpec> specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", targetType.getPrimitiveType(), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs); return spec; }
--- a/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Wed Mar 06 18:27:57 2013 +0100 +++ b/graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/typesystem/TypeCheckParser.java Wed Mar 06 18:32:33 2013 +0100 @@ -26,6 +26,7 @@ import java.util.*; import javax.lang.model.element.*; +import javax.lang.model.type.*; import com.oracle.truffle.api.codegen.*; import com.oracle.truffle.codegen.processor.*; @@ -47,7 +48,7 @@ List<ParameterSpec> specs = new ArrayList<>(); specs.add(new ParameterSpec("value", getTypeSystem(), false, Cardinality.ONE)); ParameterSpec returnTypeSpec = new ParameterSpec("returnType", getContext().getType(boolean.class), false); - MethodSpec spec = new MethodSpec(returnTypeSpec, specs); + MethodSpec spec = new MethodSpec(Collections.<TypeMirror> emptyList(), returnTypeSpec, specs); return spec; }