# HG changeset patch # User Christian Humer # Date 1420485802 -3600 # Node ID 93016f2f3f162748e2d011cf2c4d847db7155829 # Parent 3c7d543d758d7b1635c308a58aca485b7b0f5735 Truffle-DSL: optimize generated code for nodes with a single specialization. (GRAAL-602 #resolve) diff -r 3c7d543d758d -r 93016f2f3f16 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Mon Jan 05 20:23:22 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/ImplicitCastTest.java Mon Jan 05 20:23:22 2015 +0100 @@ -166,4 +166,15 @@ } + @TypeSystem({String.class, boolean.class}) + static class ImplicitCastError2 { + + @ImplicitCast + @ExpectError("Target type and source type of an @ImplicitCast must not be the same type.") + static String castInvalid(@SuppressWarnings("unused") String value) { + throw new AssertionError(); + } + + } + } diff -r 3c7d543d758d -r 93016f2f3f16 graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java --- a/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Mon Jan 05 20:23:22 2015 +0100 +++ b/graal/com.oracle.truffle.api.dsl.test/src/com/oracle/truffle/api/dsl/test/TypeSystemTest.java Mon Jan 05 20:23:22 2015 +0100 @@ -183,6 +183,7 @@ @Override public int executeInt(VirtualFrame frame) throws UnexpectedResultException { + invocationCount++; // avoid casts for some tests Object o = frame.getArguments()[index]; if (o instanceof Integer) { diff -r 3c7d543d758d -r 93016f2f3f16 graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java --- a/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Mon Jan 05 20:23:22 2015 +0100 +++ b/graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/generator/NodeGenFactory.java Mon Jan 05 20:23:22 2015 +0100 @@ -59,6 +59,7 @@ private final TypeSystemData typeSystem; private final TypeData genericType; private final DSLOptions options; + private final boolean singleSpecializable; public NodeGenFactory(ProcessorContext context, NodeData node) { this.context = context; @@ -66,6 +67,7 @@ this.typeSystem = node.getTypeSystem(); this.genericType = typeSystem.getGenericTypeData(); this.options = typeSystem.getOptions(); + this.singleSpecializable = isSingleSpecializableImpl(); } public static String nodeTypeName(NodeData node) { @@ -85,11 +87,17 @@ } private static String specializationTypeName(SpecializationData specialization) { - return specialization.getId() + "Node_"; + String id; + if (specialization == null) { + id = "Base"; + } else { + id = specialization.getId(); + } + return id + "Node_"; } - private static TypeMirror specializationType(SpecializationData specialization) { - return new GeneratedTypeMirror(ElementUtils.getPackageName(specialization.getNode().getTemplateType()) + "." + nodeTypeName(specialization.getNode()), specializationTypeName(specialization)); + private TypeMirror specializationType(SpecializationData specialization) { + return new GeneratedTypeMirror(ElementUtils.getPackageName(node.getTemplateType()) + "." + nodeTypeName(node), specializationTypeName(specialization)); } private static String polymorphicTypeProfileFieldName(NodeExecutionData execution) { @@ -160,10 +168,9 @@ } for (NodeExecutionData execution : node.getChildExecutions()) { - if (resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).isEmpty()) { - continue; + if (!resolvePolymorphicExecutables(execution).isEmpty()) { + clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class)); } - clazz.add(createNodeField(PRIVATE, getType(Class.class), polymorphicTypeProfileFieldName(execution), CompilationFinal.class)); } for (SpecializationData specialization : node.getSpecializations()) { @@ -172,7 +179,6 @@ } } - clazz.add(createNodeField(PRIVATE, TypeSystemNodeFactory.nodeType(node.getTypeSystem()), specializationStartFieldName(), Child.class)); clazz.add(createMethodGetSpecializationNode()); clazz.add(createDeepCopyMethod()); clazz.add(createGetCostMethod()); @@ -184,13 +190,16 @@ } } - SpecializationData initialSpecialization = createSpecializations(clazz); + SpecializationData specializationStart = createSpecializations(clazz); + SpecializationData finalSpecialization = singleSpecializable ? specializationStart : null; + + clazz.add(createNodeField(PRIVATE, specializationType(finalSpecialization), specializationStartFieldName(), Child.class)); for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) { CodeTreeBuilder builder = ((CodeExecutableElement) constructor).appendBuilder(); builder.startStatement(); builder.string("this.").string(specializationStartFieldName()); - builder.string(" = ").tree(createCallCreateMethod(initialSpecialization, "this", null)); + builder.string(" = ").tree(createCallCreateMethod(specializationStart, "this", null)); builder.end(); } @@ -269,7 +278,7 @@ private SpecializationData createSpecializations(CodeTypeElement clazz) { List reachableSpecializations = getReachableSpecializations(); - if (isSingleSpecializable(reachableSpecializations)) { + if (singleSpecializable) { SpecializationData single = reachableSpecializations.get(0); clazz.add(createSingleSpecialization(single)); return single; @@ -301,7 +310,7 @@ // create specialization private CodeTypeElement createBaseSpecialization() { - CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), "BaseNode_", TypeSystemNodeFactory.nodeType(typeSystem)); + CodeTypeElement clazz = createClass(node, null, modifiers(PRIVATE, ABSTRACT, STATIC), specializationTypeName(null), TypeSystemNodeFactory.nodeType(typeSystem)); clazz.addOptional(createSpecializationConstructor(clazz, null, null)); clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); @@ -336,13 +345,27 @@ clazz.add(new CodeVariableElement(modifiers(PROTECTED, FINAL), nodeType(node), "root")); TypeData returnType = specialization.getReturnType().getTypeSystemType(); Set evaluatedCount = getEvaluatedCounts(); + + TypeData specializedType = returnType; + if (!isTypeBoxingEliminated(specialization)) { + specializedType = genericType; + } + for (int evaluated : evaluatedCount) { - clazz.add(createFastPathExecuteMethod(specialization, null, evaluated)); + if (evaluated != 0) { + clazz.add(createFastPathExecuteMethod(specialization, null, evaluated)); + } } - if (isTypeBoxingEliminated(specialization)) { - clazz.add(createFastPathExecuteMethod(specialization, returnType, 0)); + + clazz.add(createFastPathExecuteMethod(specialization, specializedType, 0)); + if (!specializedType.isGeneric()) { + clazz.add(createFastPathWrapExecuteMethod(genericType, returnType)); } - clazz.add(createFastPathWrapExecuteMethod(genericType, null)); + + ExecutableTypeData voidExecutableType = node.findExecutableType(typeSystem.getVoidType(), 0); + if (voidExecutableType != null && isTypeBoxingOptimized(options.voidBoxingOptimization(), returnType)) { + clazz.add(createFastPathWrapVoidMethod(returnType)); + } clazz.addOptional(createUnsupported()); clazz.addOptional(createSpecializationCreateMethod(specialization, constructor)); @@ -695,11 +718,18 @@ return method; } - private boolean isSingleSpecializable(List reachableSpecializations) { + private boolean isSingleSpecializableImpl() { + List reachableSpecializations = getReachableSpecializations(); if (reachableSpecializations.size() != 1) { return false; } - return !reachableSpecializations.get(0).hasRewrite(context); + for (Parameter parameter : reachableSpecializations.get(0).getSignatureParameters()) { + TypeData type = parameter.getTypeSystemType(); + if (type != null && type.hasImplicitSourceTypes()) { + return false; + } + } + return true; } private List getReachableSpecializations() { @@ -1016,7 +1046,7 @@ CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); TypeMirror specializationType = specializationType(specialization); - if (options.useLazyClassLoading()) { + if (useLazyClassLoading()) { builder.startStaticCall(specializationType(specialization), "create"); } else { builder.startNew(specializationType); @@ -1041,20 +1071,17 @@ } private Element createSpecializationCreateMethod(SpecializationData specialization, CodeExecutableElement constructor) { - if (!options.useLazyClassLoading()) { + if (!useLazyClassLoading()) { return null; } CodeExecutableElement executable = CodeExecutableElement.clone(context.getEnvironment(), constructor); - - TypeMirror specializationType = specializationType(specialization); - - executable.setReturnType(TypeSystemNodeFactory.nodeType(typeSystem)); + executable.setReturnType(specializationType(null)); executable.setSimpleName(CodeNames.of("create")); executable.getModifiers().add(STATIC); CodeTreeBuilder builder = executable.createBuilder(); - builder.startReturn().startNew(specializationType); + builder.startReturn().startNew(specializationType(specialization)); for (VariableElement parameter : executable.getParameters()) { builder.string(parameter.getSimpleName().toString()); } @@ -1062,6 +1089,10 @@ return executable; } + private boolean useLazyClassLoading() { + return options.useLazyClassLoading() && !singleSpecializable; + } + private static String implicitClassFieldName(NodeExecutionData execution) { return execution.getName() + "ImplicitType"; } @@ -1133,18 +1164,32 @@ private CodeTree createCallNext(TypeData forType, LocalContext currentValues) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - builder.startCall("next", TypeSystemNodeFactory.executeName(null)); + if (singleSpecializable) { + builder.startCall("unsupported"); + } else { + builder.startCall("next", TypeSystemNodeFactory.executeName(null)); + } currentValues.addReferencesTo(builder, FRAME_VALUE); builder.end(); return TypeSystemCodeGenerator.expect(genericType, forType, builder.build()); } - private static CodeTree createCallDelegate(String methodName, String reason, TypeData forType, LocalContext currentValues) { + private CodeTree createCallRemove(String reason, TypeData forType, LocalContext currentValues) { + CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); + if (singleSpecializable) { + builder.startCall("unsupported"); + } else { + builder.startCall("remove"); + builder.doubleQuote(reason); + } + currentValues.addReferencesTo(builder, FRAME_VALUE); + builder.end(); + return TypeSystemCodeGenerator.expect(genericType, forType, builder.build()); + } + + private static CodeTree createCallDelegate(String methodName, TypeData forType, LocalContext currentValues) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); builder.startCall(methodName); - if (reason != null) { - builder.doubleQuote(reason); - } currentValues.addReferencesTo(builder, FRAME_VALUE); builder.end(); @@ -1211,11 +1256,11 @@ LocalContext originalValues = currentLocals.copy(); if (specialization == null) { - builder.startReturn().tree(createCallDelegate("acceptAndExecute", null, type, currentLocals)).end(); + builder.startReturn().tree(createCallDelegate("acceptAndExecute", type, currentLocals)).end(); } else if (specialization.isPolymorphic()) { builder.startReturn().tree(createCallNext(type, currentLocals)).end(); } else if (specialization.isUninitialized()) { - builder.startReturn().tree(createCallDelegate("uninitialized", null, type, currentLocals)).end(); + builder.startReturn().tree(createCallDelegate("uninitialized", type, currentLocals)).end(); } else { final TypeData finalType = type; SpecializationGroup group = SpecializationGroup.create(specialization); @@ -1482,10 +1527,7 @@ if (targetType.isVoid()) { return false; } else if (targetType.isGeneric()) { - if (isSingleSpecializable(getReachableSpecializations())) { - return false; - } - return resolveSpecializedExecutables(execution, node.findSpecializedTypes(execution), options.polymorphicTypeBoxingElimination()).size() >= 1; + return resolvePolymorphicExecutables(execution).size() >= 1; } else { if (!isTypeBoxingOptimized(options.monomorphicTypeBoxingOptimization(), targetType)) { return false; @@ -1523,11 +1565,16 @@ } builder.tree(createTryExecuteChild(targetValue, executeChild, shortCircuit == null, hasUnexpected)); + + if (shortCircuit != null) { + currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null)); + } + builder.end(); if (hasUnexpected) { builder.startCatchBlock(getType(UnexpectedResultException.class), "ex"); + LocalContext slowPathValues = currentValues.copy(); - LocalContext slowPathValues = currentValues.copy(); slowPathValues.setValue(execution, targetValue.makeGeneric().accessWith(CodeTreeBuilder.singleString("ex.getResult()"))); boolean found = false; for (NodeExecutionData otherExecution : node.getChildExecutions()) { @@ -1545,9 +1592,6 @@ builder.end(); } - if (shortCircuit != null) { - currentValues.setShortCircuitValue(execution, shortCircuit.accessWith(null)); - } return createShortCircuit(targetValue, shortCircuit, builder.build()); } @@ -1663,12 +1707,7 @@ throw new AssertionError("At least one generic executable method must be available."); } - Set specializedTypes = new HashSet<>(); - for (TypeData type : node.findSpecializedTypes(execution)) { - specializedTypes.addAll(type.getImplicitSourceTypes()); - } - - List specializedExecutables = resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); + List specializedExecutables = resolvePolymorphicExecutables(execution); Collections.sort(specializedExecutables, new Comparator() { public int compare(ExecutableTypeData o1, ExecutableTypeData o2) { return o1.getType().compareTo(o2.getType()); @@ -1679,7 +1718,7 @@ CodeTree executeGeneric = createSingleExecute(execution, target, currentValues, genericExecutableType); CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); - if (specializedExecutables.isEmpty() || isSingleSpecializable(getReachableSpecializations())) { + if (specializedExecutables.isEmpty()) { builder.tree(assignment); builder.tree(executeGeneric); } else { @@ -1747,6 +1786,17 @@ return builder.build(); } + private List resolvePolymorphicExecutables(NodeExecutionData execution) { + if (singleSpecializable) { + return Collections.emptyList(); + } + Set specializedTypes = new HashSet<>(); + for (TypeData type : node.findSpecializedTypes(execution)) { + specializedTypes.addAll(type.getImplicitSourceTypes()); + } + return resolveSpecializedExecutables(execution, specializedTypes, options.polymorphicTypeBoxingElimination()); + } + private static CodeTree createAssignmentStart(LocalVariable target, boolean shared) { CodeTreeBuilder builder = CodeTreeBuilder.createBuilder(); if (shared) { @@ -1804,7 +1854,7 @@ return builder.build(); } - private static CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) { + private CodeTree createFastPathTryCatchRewriteException(SpecializationData specialization, TypeData forType, LocalContext currentValues, CodeTree execution) { if (specialization.getExceptions().isEmpty()) { return execution; } @@ -1818,7 +1868,7 @@ builder.end().startCatchBlock(exceptionTypes, "ex"); builder.startStatement().tree(accessParent(excludedFieldName(specialization))).string(" = true").end(); builder.startReturn(); - builder.tree(createCallDelegate("remove", "threw rewrite exception", forType, currentValues)); + builder.tree(createCallRemove("threw rewrite exception", forType, currentValues)); builder.end(); builder.end(); return builder.build(); diff -r 3c7d543d758d -r 93016f2f3f16 graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java --- a/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Mon Jan 05 20:23:22 2015 +0100 +++ b/graal/com.oracle.truffle.sl/src/com/oracle/truffle/sl/nodes/expression/SLLogicalOrNode.java Mon Jan 05 20:23:22 2015 +0100 @@ -23,6 +23,7 @@ package com.oracle.truffle.sl.nodes.expression; import com.oracle.truffle.api.dsl.*; +import com.oracle.truffle.api.frame.*; import com.oracle.truffle.api.nodes.*; import com.oracle.truffle.api.source.*; import com.oracle.truffle.sl.nodes.*; @@ -48,7 +49,7 @@ return left instanceof Boolean && needsRightNode(((Boolean) left).booleanValue()); } - @Specialization + @Specialization(rewriteOn = RuntimeException.class) protected boolean doBoolean(boolean left, boolean hasRight, boolean right) { return left || right; }