Mercurial > hg > graal-jvmci-8
view graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/operation/OperationCodeGenerator.java @ 7291:a748e4d44694
Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process
author | Christian Humer <christian.humer@gmail.com> |
---|---|
date | Fri, 21 Dec 2012 10:44:31 -0800 |
parents | |
children |
line wrap: on
line source
/* * Copyright (c) 2012, 2012, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.oracle.truffle.codegen.processor.operation; import static com.oracle.truffle.codegen.processor.Utils.*; import static javax.lang.model.element.Modifier.*; 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.ast.*; import com.oracle.truffle.codegen.processor.template.*; import com.oracle.truffle.codegen.processor.template.ParameterSpec.Kind; import com.oracle.truffle.codegen.processor.typesystem.*; public class OperationCodeGenerator extends CompilationUnitFactory<OperationData> { private static final String OPERATION_FIELD_NAME = "operation"; public OperationCodeGenerator(ProcessorContext context) { super(context); } private TypeMirror getUnexpectedValueException() { return getContext().getTruffleTypes().getUnexpectedValueException(); } private static String operationClassName(OperationData operation) { return Utils.getSimpleName(operation.getTemplateType().asType()); } private static String factoryClassName(OperationData operation) { return operationClassName(operation) + "Factory"; } private static String nodeClassName(OperationData operation) { String name = operationClassName(operation); if (name.length() > 2 && name.endsWith("Op")) { name = name.substring(0, name.length() - 2); } return name + "Node"; } private static String nodeClassName(SpecializationData specialization) { String name = ""; if (specialization.getOperation().getAllMethods().length > 1) { name = specialization.getMethodName(); if (name.startsWith("do")) { name = name.substring(2); } } return name + nodeClassName(specialization.getOperation()); } private static String nodeVariableName(ParameterSpec spec) { if (spec.getKind() == Kind.EXECUTE) { return spec.getName() + "Node"; } return spec.getName(); } private static String nodeVariableName(ActualParameter param) { return nodeVariableName(param.getSpecification()); } private static String valueVariableName(ParameterSpec spec) { if (spec.getKind() == Kind.EXECUTE) { return spec.getName() + "Value"; } return spec.getName(); } private static String valueVariableName(ActualParameter param) { return valueVariableName(param.getSpecification()); } public static String executeMethodName(TypeData type) { if (type.isGeneric()) { return "executeGeneric"; } return "execute" + Utils.getSimpleName(type.getBoxedType()); } private static EnumSet<Kind> kinds(Kind... values) { EnumSet<Kind> result = EnumSet.noneOf(Kind.class); for (Kind value : values) { result.add(value); } return result; } private static void addNodeParameters(CodeExecutableElement method, OperationData operation, EnumSet<Kind> included) { for (ParameterSpec spec : operation.getSpecification().getParameters()) { if (included.contains(spec.getKind())) { if (spec.getKind() == Kind.EXECUTE) { method.addParameter(new CodeVariableElement(operation.getTypeSystem().getNodeType(), nodeVariableName(spec))); } else { method.addParameter(new CodeVariableElement(spec.getValueType(), nodeVariableName(spec))); } } } if (included.contains(Kind.CONSTRUCTOR_FIELD)) { for (OperationFieldData field : operation.getConstructorFields()) { method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); } } } private static void addValueParameters(CodeExecutableElement method, OperationData operation, EnumSet<Kind> included) { for (ParameterSpec spec : operation.getSpecification().getParameters()) { if (included.contains(spec.getKind())) { method.addParameter(new CodeVariableElement(spec.getValueType(), valueVariableName(spec))); } } if (included.contains(Kind.CONSTRUCTOR_FIELD)) { for (OperationFieldData field : operation.getConstructorFields()) { method.addParameter(new CodeVariableElement(field.getJavaClass(), field.getName())); } } } private static void addOperationFieldName(CodeTreeBuilder body, OperationData operation) { if (!operation.isUseSingleton()) { body.string(OPERATION_FIELD_NAME); } } private static void addOperationVariable(Set<Modifier> modifiers, Element element, OperationData operation, CodeTypeElement operationGen) { if (!operation.isUseSingleton()) { TypeMirror type = findOperationType(operation, operationGen); if (element instanceof CodeExecutableElement) { ((CodeExecutableElement) element).addParameter(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); } else if (element instanceof CodeTypeElement) { ((CodeTypeElement) element).add(new CodeVariableElement(modifiers, type, OPERATION_FIELD_NAME)); } } } private static void addNodeNames(CodeTreeBuilder body, OperationData operation, EnumSet<Kind> included) { for (ParameterSpec spec : operation.getSpecification().getParameters()) { if (included.contains(spec.getKind())) { body.string(nodeVariableName(spec)); } } if (included.contains(Kind.CONSTRUCTOR_FIELD)) { for (OperationFieldData field : operation.getConstructorFields()) { body.string(field.getName()); } } } private static void addValueNames(CodeTreeBuilder body, OperationData operation, EnumSet<Kind> included) { for (ParameterSpec spec : operation.getSpecification().getParameters()) { if (included.contains(spec.getKind())) { body.string(valueVariableName(spec)); } } if (included.contains(Kind.CONSTRUCTOR_FIELD)) { for (OperationFieldData field : operation.getConstructorFields()) { body.string(field.getName()); } } } private static void addValueNamesWithCasts(ProcessorContext context, CodeTreeBuilder body, SpecializationData specialization, EnumSet<Kind> included) { for (ActualParameter spec : specialization.getParameters()) { if (included.contains(spec.getSpecification().getKind())) { TypeData typeData = spec.getActualTypeData(specialization.getOperation().getTypeSystem()); if (typeData.isGeneric()) { body.string(valueVariableName(spec)); } else { String methodName = TypeSystemCodeGenerator.asTypeMethodName(typeData); startCallTypeSystemMethod(context, body, specialization.getOperation(), methodName); body.string(valueVariableName(spec)); body.end().end(); } } } } public static VariableElement findSingleton(ProcessorContext context, OperationData operation) { TypeMirror type = context.findGeneratedClassBySimpleName(OperationCodeGenerator.genClassName(operation), operation); return Utils.findDeclaredField(type, OperationCodeGenerator.singletonName(operation)); } private static TypeMirror findOperationType(OperationData operation, CodeTypeElement operationGen) { if (operation.hasExtensions()) { // return generated type return operationGen.asType(); } else { // return default type return operation.getTemplateType().asType(); } } private static String genClassName(OperationData operation) { String name = getSimpleName(operation.getTemplateType()); return name + "Gen"; } private static String singletonName(OperationData operation) { return createConstantName(getSimpleName(operation.getTemplateType().asType())); } private static void startCallOperationMethod(CodeTreeBuilder body, OperationData operation, TemplateMethod method) { body.startGroup(); if (operation.isUseSingleton()) { body.string(singletonName(operation)); body.string(".").startCall(method.getMethodName()); } else { body.string(OPERATION_FIELD_NAME); body.string("."); body.startCall(method.getMethodName()); } } private static void startCallTypeSystemMethod(ProcessorContext context, CodeTreeBuilder body, OperationData operation, String methodName) { VariableElement singleton = TypeSystemCodeGenerator.findSingleton(context, operation.getTypeSystem()); assert singleton != null; body.startGroup(); body.staticReference(singleton.getEnclosingElement().asType(), singleton.getSimpleName().toString()); body.string(".").startCall(methodName); } private static void emitGuards(ProcessorContext context, CodeTreeBuilder body, String prefix, SpecializationData specialization, boolean onSpecialization, boolean needsCast) { // Implict guards based on method signature String andOperator = prefix; for (ActualParameter param : specialization.getParameters()) { if (param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric()) { body.string(andOperator); startCallTypeSystemMethod(context, body, specialization.getOperation(), TypeSystemCodeGenerator.isTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); body.string(valueVariableName(param)); body.end().end(); // call andOperator = " && "; } } if (specialization.getGuards().length > 0) { // Explicitly specified guards for (SpecializationGuardData guard : specialization.getGuards()) { if ((guard.isOnSpecialization() && onSpecialization) || (guard.isOnExecution() && !onSpecialization)) { body.string(andOperator); if (guard.getGuardDeclaration().getOrigin() == specialization.getOperation()) { startCallOperationMethod(body, specialization.getOperation(), guard.getGuardDeclaration()); } else { startCallTypeSystemMethod(context, body, specialization.getOperation(), guard.getGuardMethod()); } if (needsCast) { addValueNamesWithCasts(context, body, specialization, kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); } else { addValueNames(body, specialization.getOperation(), kinds(Kind.EXECUTE, Kind.SHORT_CIRCUIT)); } body.end().end(); // call andOperator = " && "; } } } } @Override protected void createChildren(OperationData m) { CodeTypeElement operationGen = null; if (m.hasExtensions()) { OperationGenFactory factory = new OperationGenFactory(context); add(factory, m); operationGen = (CodeTypeElement) factory.getElement(); } if (m.generateFactory) { add(new OperationNodeFactory(context, operationGen), m); } } protected class OperationGenFactory extends ClassElementFactory<OperationData> { public OperationGenFactory(ProcessorContext context) { super(context); } @Override protected CodeTypeElement create(OperationData operation) { CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC), genClassName(operation), operation.getTemplateType().asType(), false); clazz.add(createConstructorUsingFields(modifiers(PUBLIC), clazz)); if (operation.getExtensionElements() != null) { clazz.getEnclosedElements().addAll(operation.getExtensionElements()); } return clazz; } } protected class OperationNodeFactory extends ClassElementFactory<OperationData> { private final CodeTypeElement operationGen; public OperationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { super(context); this.operationGen = operationGen; } @Override protected CodeTypeElement create(OperationData operation) { CodeTypeElement clazz = createClass(operation, modifiers(PUBLIC, FINAL), factoryClassName(operation), null, false); if (operation.isUseSingleton()) { TypeMirror type = findOperationType(operation, operationGen); CodeVariableElement singleton = new CodeVariableElement(modifiers(PRIVATE, STATIC, FINAL), type, singletonName(operation)); clazz.add(singleton); CodeTreeBuilder singletonInit = singleton.createInitBuilder(); singletonInit.startNew(type).end(); } clazz.add(createConstructorUsingFields(modifiers(PRIVATE), clazz)); clazz.add(createCreateMethod(operation)); if (operation.getAllMethods().length > 1) { clazz.add(createCreateSpecializedMethod(operation)); } if (operation.needsRewrites()) { clazz.add(createSpecializeMethod(operation)); clazz.add(createGeneratedGenericMethod(operation)); } return clazz; } @Override protected void createChildren(OperationData operation) { for (SpecializationData specialization : operation.getAllMethods()) { add(new SpecializationNodeFactory(context, operationGen), specialization); } } private CodeExecutableElement createCreateMethod(OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC, STATIC), operation.getNodeType(), "create"); addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE, Kind.CONSTRUCTOR_FIELD)); CodeTreeBuilder body = method.createBuilder(); body.startReturn(); if (operation.getAllMethods().length == 0) { body.null_(); } else { body.startNew(nodeClassName(operation.getAllMethods()[0])); emitNewOperation(body, operation); addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); body.end(); } body.end(); return method; } private void emitNewOperation(CodeTreeBuilder body, OperationData operation) { if (!operation.isUseSingleton()) { body.startGroup(); if (operation.hasExtensions()) { body.startNew(genClassName(operation)); } else { body.startNew(operation.getTemplateType().asType()); } addNodeNames(body, operation, kinds(Kind.CONSTRUCTOR_FIELD)); body.end(); body.end(); } } private CodeExecutableElement createCreateSpecializedMethod(OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "createSpecialized"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); addOperationVariable(modifiers(), method, operation, operationGen); addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); CodeTreeBuilder body = method.createBuilder(); boolean first = true; for (TypeData type : operation.getTypeSystem().getTypes()) { SpecializationData specialization = operation.findUniqueSpecialization(type); if (specialization != null && !type.isGeneric()) { if (first) { body.startIf(); first = false; } else { body.startElseIf(); } body.string("specializationClass == ").type(type.getBoxedType()).string(".class").end().startBlock(); body.startReturn().startNew(nodeClassName(specialization)); addOperationFieldName(body, operation); addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); body.end().end(); body.end(); } } body.startReturn().startNew(nodeClassName(operation.getGenericSpecialization())); addOperationFieldName(body, operation); addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); body.end().end(); return method; } private CodeExecutableElement createSpecializeMethod(OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getNodeType(), "specialize"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); addOperationVariable(modifiers(), method, operation, operationGen); addValueParameters(method, operation, kinds(Kind.EXECUTE)); addNodeParameters(method, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); CodeTreeBuilder body = method.createBuilder(); body.startStatement().string("boolean allowed = (minimumState == ").string(nodeClassName(operation.getAllMethods()[0])).string(".class)").end(); for (int i = 1; i < operation.getAllMethods().length; i++) { SpecializationData specialization = operation.getAllMethods()[i]; body.startStatement().string("allowed = allowed || (minimumState == ").string(nodeClassName(specialization)).string(".class)").end(); if (specialization.isGeneric()) { body.startIf().string("allowed").end().startBlock(); } else { body.startIf().string("allowed"); emitGuards(getContext(), body, " && ", specialization, true, true); body.end().startBlock(); } body.startReturn().startNew(nodeClassName(specialization)); addOperationFieldName(body, operation); addNodeNames(body, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); body.end().end(); body.end(); // block } body.startThrow().startNew(getContext().getType(IllegalArgumentException.class)).end().end(); return method; } private void emitInvokeDoMethod(CodeTreeBuilder builder, SpecializationData specialization) { if (specialization.getExceptions().length > 0) { builder.startTryBlock(); } builder.startReturn(); startCallOperationMethod(builder, specialization.getOperation(), specialization); for (ActualParameter param : specialization.getParameters()) { boolean needsCast = param.getSpecification().getKind() == Kind.EXECUTE && !param.getActualTypeData(specialization.getOperation().getTypeSystem()).isGeneric(); if (needsCast) { startCallTypeSystemMethod(getContext(), builder, specialization.getOperation(), TypeSystemCodeGenerator.asTypeMethodName(param.getActualTypeData(specialization.getOperation().getTypeSystem()))); } builder.string(valueVariableName(param)); if (needsCast) { builder.end().end(); } } builder.end().end(); // start call operation builder.end(); // return if (specialization.getExceptions().length > 0) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); emitInvokeDoMethod(builder, exception.getTransitionTo()); } builder.end(); } } private CodeExecutableElement createGeneratedGenericMethod(OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED, STATIC), operation.getGenericSpecialization().getReturnType().getActualType(), "generatedGeneric"); addOperationVariable(modifiers(), method, operation, operationGen); addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); CodeTreeBuilder builder = method.createBuilder(); boolean ifStarted = false; for (int i = 0; i < operation.getSpecializations().length; i++) { SpecializationData specialization = operation.getSpecializations()[i]; if (specialization.isUninitialized()) { continue; } if (!specialization.isGeneric()) { if (!ifStarted) { builder.startIf(); ifStarted = true; } else { builder.startElseIf(); } emitGuards(getContext(), builder, "", specialization, false, true); builder.end().startBlock(); } else { builder.startElseBlock(); } emitInvokeDoMethod(builder, specialization); builder.end(); } return method; } } protected class SpecializationNodeFactory extends ClassElementFactory<SpecializationData> { private CodeTypeElement operationGen; public SpecializationNodeFactory(ProcessorContext context, CodeTypeElement operationGen) { super(context); this.operationGen = operationGen; } @Override public CodeTypeElement create(SpecializationData specialization) { OperationData operation = specialization.getOperation(); CodeTypeElement clazz = createClass(operation, modifiers(PRIVATE, STATIC, FINAL), nodeClassName(specialization), operation.getNodeType(), false); CodeExecutableElement constructor = new CodeExecutableElement(modifiers(PROTECTED), null, clazz.getSimpleName().toString()); clazz.add(constructor); CodeTreeBuilder builder = constructor.createBuilder(); builder.startStatement().startSuperCall(); addNodeNames(builder, operation, kinds(Kind.SUPER_ATTRIBUTE)); builder.end().end(); if (!operation.isUseSingleton()) { addOperationVariable(modifiers(), constructor, operation, operationGen); addOperationVariable(modifiers(PRIVATE, FINAL), clazz, operation, operationGen); builder.startStatement(); builder.string("this."); addOperationFieldName(builder, operation); builder.string(" = "); addOperationFieldName(builder, operation); builder.end(); } addNodeParameters(constructor, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); for (ParameterSpec spec : operation.getSpecification().getParameters()) { String name = nodeVariableName(spec); boolean isNodeAttribute = spec.getKind() == Kind.ATTRIBUTE && getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNode()); boolean isNodeArrayAttribute = spec.getKind() == Kind.ATTRIBUTE && getContext().getEnvironment().getTypeUtils().isAssignable(spec.getValueType(), getContext().getTruffleTypes().getNodeArray()); if (spec.getKind() == Kind.EXECUTE || isNodeAttribute || isNodeArrayAttribute) { CodeVariableElement field = new CodeVariableElement(modifiers(PRIVATE), operation.getTypeSystem().getNodeType(), name); clazz.add(field); field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getStableAnnotation())); if (isNodeArrayAttribute) { field.addAnnotationMirror(new CodeAnnotationMirror((DeclaredType) getContext().getTruffleTypes().getContentStableAnnotation())); } builder.startStatement().string("this.").string(name).string(" = adoptChild(").string(name).string(")").end(); } else if (spec.getKind() == Kind.ATTRIBUTE) { clazz.add(new CodeVariableElement(modifiers(PRIVATE, FINAL), spec.getValueType(), name)); builder.startStatement().string("this.").string(name).string(" = ").string(name).end(); } } TypeSystemData typeSystem = operation.getTypeSystem(); for (TypeData type : typeSystem.getTypes()) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), type.getPrimitiveType(), executeMethodName(type)); clazz.add(method); addValueParameters(method, operation, kinds(Kind.SIGNATURE)); if (!type.isGeneric()) { method.addThrownType(getUnexpectedValueException()); } if (specialization.getReturnType().getActualTypeData(typeSystem) == type) { buildFunctionalExecuteMethod(method.createBuilder(), operation, specialization); } else { buildCastingExecuteMethod(method.createBuilder(), operation, specialization, type); } } if (typeSystem.getVoidType() != null) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PUBLIC), typeSystem.getVoidType().getPrimitiveType(), executeMethodName(typeSystem.getVoidType())); addValueParameters(method, operation, kinds(Kind.SIGNATURE)); buildCastingExecuteMethod(method.createBuilder(), operation, specialization, typeSystem.getVoidType()); clazz.add(method); } if (operation.needsRewrites() && !specialization.isGeneric() && !specialization.isUninitialized()) { buildSpecializeStateMethod(clazz, operation); } buildSpecializeClassMethod(clazz, operation); return clazz; } private void buildCastingExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, TypeData type) { if (!type.isVoid()) { builder.startStatement().type(specialization.getReturnType().getActualType()).string(" result").end(); } boolean needsTry = !specialization.getReturnType().getActualTypeData(operation.getTypeSystem()).isGeneric(); if (needsTry) { builder.startTryBlock(); } builder.startStatement(); if (!type.isVoid()) { builder.string("result = "); } builder.startCall(executeMethodName(specialization.getReturnType().getActualTypeData(operation.getTypeSystem()))).string("frame").end(); builder.end(); // statement if (needsTry) { builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); if (!type.isVoid()) { builder.startReturn(); if (!type.isGeneric()) { startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); } builder.string("ex.getResult()"); if (!type.isGeneric()) { builder.end().end(); } builder.end(); // return } else { builder.string("// ignore").newLine(); } } builder.end(); // try/catch if (!type.isVoid()) { builder.startReturn(); if (!type.isGeneric()) { startCallTypeSystemMethod(getContext(), builder, operation, TypeSystemCodeGenerator.expectTypeMethodName(type)); } builder.string("result"); if (!type.isGeneric()) { builder.end().end(); } builder.end(); // return } } private void buildFunctionalExecuteMethod(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization) { ActualParameter previousShortCircuitParameter = null; for (ActualParameter param : specialization.getParameters()) { if (param.getSpecification().getKind() != Kind.EXECUTE) { // Nothing to do. } else if (param.getActualTypeData(operation.getTypeSystem()).isGeneric()) { buildGenericValueExecute(builder, operation, param, null); } else { buildSpecializedValueExecute(builder, operation, specialization, param); } assert param.getSpecification().getKind() == Kind.SHORT_CIRCUIT || previousShortCircuitParameter == null; } if (specialization.hasDynamicGuards()) { builder.startIf(); emitGuards(getContext(), builder, "", specialization, false, false); builder.end().startBlock(); } if (specialization.getExceptions().length > 0) { builder.startTryBlock(); } if (specialization.isUninitialized() && operation.needsRewrites()) { for (TemplateMethod listener : operation.getSpecializationListeners()) { builder.startStatement(); startCallOperationMethod(builder, operation, listener); for (ActualParameter param : listener.getParameters()) { builder.string(valueVariableName(param)); } builder.end().end(); builder.end(); // statement } builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(operation), "specialize"); builder.typeLiteral(builder.getRoot().getEnclosingClass().asType()); addOperationFieldName(builder, operation); addValueNames(builder, operation, kinds(Kind.EXECUTE)); addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); builder.end().end().end(); } if ((specialization.isUninitialized() || specialization.isGeneric()) && operation.needsRewrites()) { builder.startReturn().startCall(factoryClassName(specialization.getOperation()), "generatedGeneric"); addOperationFieldName(builder, operation); addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); builder.end().end(); } else { builder.startReturn(); if (specialization.isUninitialized()) { startCallOperationMethod(builder, specialization.getOperation(), specialization.getOperation().getGenericSpecialization()); } else { startCallOperationMethod(builder, specialization.getOperation(), specialization); } for (ActualParameter param : specialization.getParameters()) { builder.string(valueVariableName(param)); } builder.end().end(); // operation call builder.end(); // return } if (specialization.getExceptions().length > 0) { for (SpecializationThrowsData exception : specialization.getExceptions()) { builder.end().startCatchBlock(exception.getJavaClass(), "ex"); buildThrowSpecialize(builder, operation, exception.getTransitionTo(), null); } builder.end(); } if (specialization.hasDynamicGuards()) { builder.end().startElseBlock(); buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), null); builder.end(); } } private void buildGenericValueExecute(CodeTreeBuilder builder, OperationData operation, ActualParameter param, ParameterSpec exceptionSpec) { boolean shortCircuit = startShortCircuit(builder, operation.getGenericSpecialization(), operation.getGenericSpecialization().findParameter(param.getSpecification().getName()), exceptionSpec); builder.startStatement(); if (!shortCircuit) { builder.type(operation.getTypeSystem().getGenericType()); builder.string(" "); } builder.string(valueVariableName(param)); builder.string(" = ").startCall(nodeVariableName(param), executeMethodName(operation.getTypeSystem().getGenericTypeData())).string("frame").end(); builder.end(); endShortCircuit(builder, shortCircuit); } private boolean startShortCircuit(CodeTreeBuilder builder, SpecializationData specialization, ActualParameter forParam, ParameterSpec exceptionParam) { ActualParameter shortCircuitParam = specialization.getPreviousParam(forParam); if (shortCircuitParam == null || shortCircuitParam.getSpecification().getKind() != Kind.SHORT_CIRCUIT) { return false; } int shortCircuitIndex = 0; for (ActualParameter parameter : specialization.getParameters()) { if (parameter.getSpecification().getKind() == Kind.SHORT_CIRCUIT) { if (parameter == shortCircuitParam) { break; } shortCircuitIndex++; } } builder.startStatement().type(shortCircuitParam.getActualType()).string(" ").string(shortCircuitParam.getSpecification().getName()).string(" = "); ShortCircuitData shortCircuitData = specialization.getShortCircuits()[shortCircuitIndex]; startCallOperationMethod(builder, specialization.getOperation(), shortCircuitData); for (ActualParameter callParam : shortCircuitData.getParameters()) { ParameterSpec spec = callParam.getSpecification(); if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT || spec.getKind() == Kind.SIGNATURE) { if (exceptionParam != null && callParam.getSpecification().getName().equals(exceptionParam.getName())) { builder.string("ex.getResult()"); } else { builder.string(valueVariableName(spec)); } } } builder.end().end(); // call operation builder.end(); // statement builder.declaration(forParam.getActualType(), valueVariableName(forParam), CodeTreeBuilder.createBuilder().defaultValue(forParam.getActualType())); builder.startIf().string(valueVariableName(shortCircuitParam)).end(); builder.startBlock(); return true; } private void endShortCircuit(CodeTreeBuilder builder, boolean shortCircuit) { if (shortCircuit) { builder.end(); } } private void buildSpecializedValueExecute(CodeTreeBuilder builder, OperationData operation, SpecializationData specialization, ActualParameter param) { boolean shortCircuit = startShortCircuit(builder, specialization, param, null); if (!shortCircuit) { builder.startStatement().type(param.getActualType()).string(" ").string(valueVariableName(param)).end(); } builder.startTryBlock(); builder.startStatement().string(valueVariableName(param)).string(" = "); builder.startCall(nodeVariableName(param), executeMethodName(param.getActualTypeData(operation.getTypeSystem()))).string("frame").end(); builder.end(); builder.end().startCatchBlock(getUnexpectedValueException(), "ex"); boolean execute = false; for (ActualParameter exParam : specialization.getParameters()) { if (exParam.getSpecification().getKind() != Kind.EXECUTE) { // Nothing to do. } else if (execute) { buildGenericValueExecute(builder, operation, exParam, param.getSpecification()); } else if (exParam == param) { execute = true; } } buildThrowSpecialize(builder, operation, specialization.findNextSpecialization(), param.getSpecification()); builder.end(); // catch block endShortCircuit(builder, shortCircuit); builder.newLine(); } private void buildThrowSpecialize(CodeTreeBuilder builder, OperationData operation, SpecializationData nextSpecialization, ParameterSpec exceptionSpec) { builder.startThrow().startCall("specialize"); builder.string(nodeClassName(nextSpecialization) + ".class"); addValueNames(builder, operation, kinds(Kind.SIGNATURE)); for (ParameterSpec spec : operation.getSpecification().getParameters()) { if (spec.getKind() == Kind.EXECUTE || spec.getKind() == Kind.SHORT_CIRCUIT) { if (spec == exceptionSpec) { builder.string("ex.getResult()"); } else { builder.string(valueVariableName(spec)); } } } builder.end().end(); } private void buildSpecializeStateMethod(CodeTypeElement clazz, OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PRIVATE), getUnexpectedValueException(), "specialize"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "minimumState")); addValueParameters(method, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT)); clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); for (TemplateMethod listener : operation.getSpecializationListeners()) { builder.startStatement(); startCallOperationMethod(builder, operation, listener); for (ActualParameter param : listener.getParameters()) { builder.string(valueVariableName(param)); } builder.end().end(); builder.end(); // statement } builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(operation), "specialize").string("minimumState"); addOperationFieldName(builder, operation); addValueNames(builder, operation, kinds(Kind.EXECUTE)); addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); builder.end().end().end(); builder.startReturn().startNew(getUnexpectedValueException()).startCall(factoryClassName(operation), "generatedGeneric"); addOperationFieldName(builder, operation); addValueNames(builder, operation, kinds(Kind.SIGNATURE, Kind.EXECUTE, Kind.SHORT_CIRCUIT, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); builder.end().end().end(); } private void buildSpecializeClassMethod(CodeTypeElement clazz, OperationData operation) { CodeExecutableElement method = new CodeExecutableElement(modifiers(PROTECTED), getContext().getType(void.class), "specialize"); method.addParameter(new CodeVariableElement(getContext().getType(Class.class), "specializationClass")); if (!isDeclaredMethodInSuperType(clazz, method.getSimpleName().toString(), method.getParameterTypes())) { return; } clazz.add(method); CodeTreeBuilder builder = method.createBuilder(); builder.startStatement(); builder.startCall("replace"); builder.startCall(factoryClassName(operation), "createSpecialized").string("specializationClass"); addOperationFieldName(builder, operation); addNodeNames(builder, operation, kinds(Kind.EXECUTE, Kind.ATTRIBUTE, Kind.SUPER_ATTRIBUTE)); builder.end().end().end(); } } }