Mercurial > hg > truffle
view graal/com.oracle.max.asmdis/src/com/sun/max/asm/gen/AssemblerGenerator.java @ 4205:2af849af1723
moved graphbuilder into the graal.java project.
author | Thomas Wuerthinger <thomas.wuerthinger@oracle.com> |
---|---|
date | Tue, 03 Jan 2012 18:22:10 +0100 |
parents | bc8527f3071c |
children |
line wrap: on
line source
/* * Copyright (c) 2007, 2011, 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.sun.max.asm.gen; import static com.sun.max.lang.Classes.*; import java.io.*; import java.lang.reflect.*; import java.util.*; import com.sun.max.*; import com.sun.max.asm.*; import com.sun.max.asm.dis.*; import com.sun.max.ide.*; import com.sun.max.io.*; import com.sun.max.lang.*; import com.sun.max.program.*; import com.sun.max.program.option.*; /** * Source code generator for raw and label assembler methods derived from an ISA specification. */ public abstract class AssemblerGenerator<Template_Type extends Template> { protected OptionSet options = new OptionSet(); public final Option<File> outputDirectoryOption = options.newFileOption("d", JavaProject.findSourceDirectory(AssemblerGenerator.class), "Source directory of the class(es) containing the for generated assembler methods."); public final Option<String> assemblerInterfaceNameOption = options.newStringOption("i", null, "Interface used to constrain which assembler methods will be generated. " + "If absent, an assembler method is generated for each template in the specification."); public final Option<String> rawAssemblerClassNameOption = options.newStringOption("r", null, "Class containing the generated raw assembler methods."); public final Option<String> labelAssemblerClassNameOption = options.newStringOption("l", null, "Class containing the generated label assembler methods."); public final Option<Boolean> generateRedundantInstructionsOption = options.newBooleanOption("redundant", true, "Generate assembler methods for redundant templates. Two templates are redundant if they " + "both have the same name and operands. Redundant pairs of instructions are assumed to " + "implement the same machine instruction semantics but may have different encodings."); private final Assembly<Template_Type> assembly; private final boolean sortAssemblerMethods; private List<Template_Type> templates; private List<Template_Type> labelTemplates; protected AssemblerGenerator(Assembly<Template_Type> assembly, boolean sortAssemblerMethods) { Trace.addTo(options); this.assembly = assembly; final String isa = assembly.isa().name(); final String defaultOutputPackage = getPackageName(Assembler.class) + "." + isa.toLowerCase() + ".complete"; this.rawAssemblerClassNameOption.setDefaultValue(defaultOutputPackage + "." + isa + "RawAssembler"); this.labelAssemblerClassNameOption.setDefaultValue(defaultOutputPackage + "." + isa + "LabelAssembler"); this.sortAssemblerMethods = sortAssemblerMethods; } public Assembly<Template_Type> assembly() { return assembly; } static class MethodKey { final String name; final Class[] parameterTypes; MethodKey(Method method) { name = method.getName(); parameterTypes = method.getParameterTypes(); } MethodKey(Template template, boolean asLabelTemplate) { name = template.assemblerMethodName(); parameterTypes = template.parameterTypes(); if (asLabelTemplate) { final int labelParameterIndex = template.labelParameterIndex(); assert labelParameterIndex != -1; parameterTypes[labelParameterIndex] = Label.class; } } @Override public boolean equals(Object object) { if (object instanceof MethodKey) { final MethodKey other = (MethodKey) object; return other.name.equals(name) && Arrays.equals(parameterTypes, other.parameterTypes); } return false; } @Override public int hashCode() { return name.hashCode() ^ parameterTypes.length; } @Override public String toString() { final String paramTypes = Arrays.toString(this.parameterTypes); return name + "(" + paramTypes.substring(1, paramTypes.length() - 1) + ")"; } } private List<Template_Type> filterTemplates(List<Template_Type> templateList) { if (!generateRedundantInstructionsOption.getValue()) { final List<Template_Type> result = new LinkedList<>(); for (Template_Type template : templateList) { if (!template.isRedundant()) { result.add(template); } } return result; } return templateList; } /** * Initializes the set of label and raw templates that will be generated as assembler methods. * This includes doing any filtering out of templates based on an {@linkplain #assemblerInterfaceNameOption assembler interface}. */ private void initTemplates() { assert (labelTemplates == null) == (templates == null); if (templates == null) { final String assemblerInterfaceName = assemblerInterfaceNameOption.getValue(); if (assemblerInterfaceName == null) { templates = filterTemplates(assembly().templates()); labelTemplates = filterTemplates(assembly().labelTemplates()); } else { final List<Template_Type> newTemplates = new ArrayList<>(); final List<Template_Type> newLabelTemplates = new ArrayList<>(); Class assemberInterface = null; try { assemberInterface = Class.forName(assemblerInterfaceName); ProgramError.check(assemberInterface.isInterface(), "The class " + assemblerInterfaceName + " is not an interface"); } catch (ClassNotFoundException e) { throw ProgramError.unexpected("The assembler interface class " + assemblerInterfaceName + " must be on the class path"); } final Set<MethodKey> assemblerInterfaceMethods = new HashSet<>(); for (Method assemblerInterfaceMethod : assemberInterface.getDeclaredMethods()) { assemblerInterfaceMethods.add(new MethodKey(assemblerInterfaceMethod)); } for (Template_Type labelTemplate : assembly().labelTemplates()) { if (assemblerInterfaceMethods.contains(new MethodKey(labelTemplate, true))) { assert labelTemplate.labelParameterIndex() != -1; newLabelTemplates.add(labelTemplate); } } for (Template_Type template : assembly().templates()) { if (template.labelParameterIndex() != -1 && assemblerInterfaceMethods.contains(new MethodKey(template, true))) { newTemplates.add(template); } else if (assemblerInterfaceMethods.contains(new MethodKey(template, false))) { newTemplates.add(template); } } this.templates = newTemplates; this.labelTemplates = newLabelTemplates; Trace.line(1, "Based on " + assemberInterface + ", " + (assembly().templates().size() - newTemplates.size()) + " (of " + assembly().templates().size() + ") raw templates and " + (assembly().labelTemplates().size() - newLabelTemplates.size()) + " (of " + assembly().labelTemplates().size() + ") label templates will be omitted from generated assembler methods"); } if (sortAssemblerMethods) { Class<Template_Type[]> type = null; Template_Type[] sortedTemplates = Utils.cast(type, Array.newInstance(assembly().templateType(), templates.size())); Template_Type[] sortedLabelTemplates = Utils.cast(type, Array.newInstance(assembly().templateType(), labelTemplates.size())); templates.toArray(sortedTemplates); Arrays.sort(sortedTemplates); templates = Arrays.asList(sortedTemplates); labelTemplates.toArray(sortedLabelTemplates); Arrays.sort(sortedLabelTemplates); labelTemplates = Arrays.asList(sortedLabelTemplates); } } } protected final List<Template_Type> templates() { initTemplates(); return templates; } protected final List<Template_Type> labelTemplates() { initTemplates(); return labelTemplates; } /** * Gets the absolute path to the source file that will updated to include the generated assembler methods. * * @param className the name of the Java class that contains the generated assembler methods */ private File getSourceFileFor(String className) { return new File(outputDirectoryOption.getValue(), className.replace('.', File.separatorChar) + ".java").getAbsoluteFile(); } protected static final String formatParameterList(String separator, List<? extends Parameter> parameters, boolean typesOnly) { String sep = separator; final StringBuilder sb = new StringBuilder(); for (Parameter parameter : parameters) { sb.append(sep); sb.append(Classes.getSimpleName(parameter.type(), true)); if (!typesOnly) { sb.append(" "); sb.append(parameter.variableName()); } if (!sep.startsWith(", ")) { sep = ", " + sep; } } return sb.toString(); } /** * Prints the source code for the raw assembler method for to a given template. * * @return the number of source code lines printed */ protected abstract int printMethod(IndentWriter writer, Template_Type template); /** * Prints the source code for support methods that are used by the methods printed by {@link #printMethod(IndentWriter, Template)}. * @param writer * * @return the number of subroutines printed */ protected int printSubroutines(IndentWriter writer) { return 0; } /** * Gets the set of packages that must be imported for the generated code to compile successfully. * * @param className the name of the Java class that contains the assembler methods generated from {@code templates} * @param templateList the list of templates for which code is being generated * @return a set of packages sorted by name */ public Set<String> getImportPackages(String className, Iterable<Template_Type> templateList) { final String outputPackage = getPackageName(className); final Set<String> packages = new TreeSet<>(); packages.add(getPackageName(AssemblyException.class)); packages.add(getPackageName(Label.class)); for (Template_Type template : templateList) { for (Parameter parameter : template.parameters()) { final Class type = parameter.type(); if (!type.isPrimitive()) { final String p = getPackageName(type); if (!p.equals(outputPackage)) { packages.add(p); } } } } return packages; } /** * Prints the Javadoc comment for a template followed by a C++ style comment stating the template's number (it's * position in the order of emitted assembler methods) and its serial (a unique identifier given to every template). */ protected void printMethodComment(IndentWriter writer, Template_Type template, int number, boolean forLabelAssemblerMethod) { printMethodJavadoc(writer, template, forLabelAssemblerMethod); writer.println("// Template#: " + number + ", Serial#: " + template.serial()); } /** * Determines if a given label template should be omitted from assembler method generation. * This method is overridden by subclasses that may generate the code for 2 related label templates * in a single assembler method. For example, on X86 most branch instructions can take offsets of variable bit widths * and the logic for decoding the bit width of a {@link Label} value may be generated in a single assembler method. * <p> * The default implementation of this method returns {@code false}. * @param labelTemplate */ protected boolean omitLabelTemplate(Template_Type labelTemplate) { return false; } /** * Gets a reference to the architecture manual section describing the given template. The * returned string should conform to the format of the {@code @see} Javadoc tag. * @param template */ protected String getJavadocManualReference(Template_Type template) { return null; } /** * Allows subclasses to print ISA specific details for a template. For example, RISC synthetic instructions * print what raw instruction they are derived from. * * @param extraLinks * a sequence to which extra javadoc links should be appended */ @SuppressWarnings("unused") protected void printExtraMethodJavadoc(IndentWriter writer, Template_Type template, List<String> extraLinks, boolean forLabelAssemblerMethod) { } private boolean seenNoSuchAssemblerMethodError; /** * Writes the Javadoc comment for an assembler method. * * @param template the template from which the assembler method is generated */ protected void printMethodJavadoc(IndentWriter writer, Template_Type template, boolean forLabelAssemblerMethod) { final List<String> extraLinks = new LinkedList<>(); final List<? extends Parameter> parameters = getParameters(template, forLabelAssemblerMethod); writer.println("/**"); writer.println(" * Pseudo-external assembler syntax: {@code " + template.externalName() + externalMnemonicSuffixes(parameters) + " }" + externalParameters(parameters)); final boolean printExampleInstruction = true; if (printExampleInstruction) { final List<Argument> arguments = new ArrayList<>(); final AddressMapper addressMapper = new AddressMapper(); for (Parameter p : template.parameters()) { final Argument exampleArg = p.getExampleArgument(); if (exampleArg != null) { arguments.add(exampleArg); } else { break; } } if (arguments.size() == template.parameters().size()) { try { final DisassembledInstruction instruction = generateExampleInstruction(template, arguments); final ImmediateArgument targetAddress = instruction.targetAddress(); if (targetAddress != null) { addressMapper.add(targetAddress, "L1"); } final String exampleInstruction = instruction.toString(addressMapper); writer.println(" * Example disassembly syntax: {@code " + exampleInstruction + "}"); } catch (NoSuchAssemblerMethodError e) { if (!seenNoSuchAssemblerMethodError) { seenNoSuchAssemblerMethodError = true; ProgramWarning.message("Once generated assembler has been compiled, re-generate it you want a usage example " + "in the Javadoc for every generated assembler method"); } } catch (AssemblyException e) { ProgramWarning.message("Error generating example instruction: " + e); } } } printExtraMethodJavadoc(writer, template, extraLinks, forLabelAssemblerMethod); final List<InstructionConstraint> constraints = new ArrayList<>(template.instructionDescription().specifications().size()); for (Object s : template.instructionDescription().specifications()) { if (s instanceof InstructionConstraint) { constraints.add((InstructionConstraint) s); } } if (!constraints.isEmpty()) { writer.println(" * <p>"); for (InstructionConstraint constraint : constraints) { final Method predicateMethod = constraint.predicateMethod(); if (predicateMethod != null) { extraLinks.add(predicateMethod.getDeclaringClass().getName() + "#" + predicateMethod.getName()); } writer.println(" * Constraint: {@code " + constraint.asJavaExpression() + "}<br />"); } } if (!extraLinks.isEmpty()) { writer.println(" *"); for (String link : extraLinks) { writer.println(" * @see " + link); } } final String ref = getJavadocManualReference(template); if (ref != null) { writer.println(" *"); writer.println(" * @see " + ref); } writer.println(" */"); } protected abstract DisassembledInstruction generateExampleInstruction(Template_Type template, List<Argument> arguments) throws AssemblyException; private static String externalParameters(List< ? extends Parameter> parameters) { final StringBuilder sb = new StringBuilder(); boolean first = true; for (Parameter parameter : parameters) { if (!ExternalMnemonicSuffixArgument.class.isAssignableFrom(parameter.type())) { if (!first) { sb.append(", "); } sb.append("<i>").append(parameter.variableName()).append("</i>"); first = false; } } return sb.toString(); } private static String externalMnemonicSuffixes(List< ? extends Parameter> parameters) { final StringBuilder sb = new StringBuilder(); for (Parameter parameter : parameters) { if (ExternalMnemonicSuffixArgument.class.isAssignableFrom(parameter.type())) { boolean first = true; String close = "]"; for (Argument argument : parameter.getLegalTestArguments()) { final String externalValue = argument.externalValue(); if (externalValue.length() != 0) { if (!first) { sb.append("|"); } else { if (((ExternalMnemonicSuffixArgument) argument).isOptional()) { sb.append("{"); close = "}"; } else { sb.append("["); } } sb.append(externalValue); first = false; } } sb.append(close); } } return sb.toString(); } private boolean generateRawAssemblerMethods(String rawAssemblerClassName) throws IOException { Trace.line(1, "Generating raw assembler methods"); final List<Template_Type> templateList = templates(); final File sourceFile = getSourceFileFor(rawAssemblerClassName); ProgramError.check(sourceFile.exists(), "Source file for class containing raw assembler methods does not exist: " + sourceFile); final CharArraySource charArrayWriter = new CharArraySource((int) sourceFile.length()); final IndentWriter writer = new IndentWriter(new PrintWriter(charArrayWriter)); writer.indent(); int codeLineCount = 0; final Map<InstructionDescription, Integer> instructionDescriptions = new HashMap<>(); int maxTemplatesPerDescription = 0; int i = 0; for (Template_Type template : templateList) { printMethodComment(writer, template, i + 1, false); codeLineCount += printMethod(writer, template); writer.println(); Integer count = instructionDescriptions.get(template.instructionDescription()); if (count == null) { count = 1; } else { count = count + 1; } if (count > maxTemplatesPerDescription) { maxTemplatesPerDescription = count; } instructionDescriptions.put(template.instructionDescription(), count); i++; } final int subroutineCount = printSubroutines(writer); writer.outdent(); writer.close(); Trace.line(1, "Generated raw assembler methods" + " [code line count=" + codeLineCount + ", total line count=" + writer.lineCount() + ", method count=" + (templateList.size() + subroutineCount) + ", instruction templates=" + templateList.size() + ", max templates per description=" + maxTemplatesPerDescription + "]"); return Files.updateGeneratedContent(sourceFile, charArrayWriter, "// START GENERATED RAW ASSEMBLER METHODS", "// END GENERATED RAW ASSEMBLER METHODS", false); } /** * Gets the parameters for a template. * * @param forLabelAssemblerMethod * if true and template contains a label parameter, then this parameter is represented as a * {@link LabelParameter} object in the returned sequence */ protected static List<Parameter> getParameters(Template template, boolean forLabelAssemblerMethod) { if (!forLabelAssemblerMethod || template.labelParameterIndex() == -1) { final Class<List<Parameter>> type = null; return Utils.cast(type, template.parameters()); } final List<Parameter> parameters = new ArrayList<>(template.parameters()); parameters.set(template.labelParameterIndex(), LabelParameter.LABEL); return parameters; } protected void printLabelMethodHead(IndentWriter writer, Template_Type template, List<Parameter> parameters) { writer.print("public void " + template.assemblerMethodName() + "("); writer.print(formatParameterList("final ", parameters, false)); writer.println(") {"); writer.indent(); } /** * Prints an assembler method for a template that refers to an address via a {@linkplain Label label}. * * @param writer the writer to which code will be printed * @param labelTemplate a template that has a label parameter (i.e. its {@linkplain Template#labelParameterIndex() * label parameter index} is not -1) * @param assemblerClassName the name of the class enclosing the assembler method declaration */ protected abstract void printLabelMethod(IndentWriter writer, Template_Type labelTemplate, String assemblerClassName); /** * Mechanism that writes the body of the {@link MutableAssembledObject#assemble} method in a generated label method helper class. */ public class InstructionWithLabelSubclass { final Class<? extends InstructionWithLabel> superClass; final String name; final String extraConstructorArguments; final String labelArgumentPrefix; public InstructionWithLabelSubclass(Template template, Class<? extends InstructionWithLabel> superClass, String extraConstructorArguments) { this.superClass = superClass; this.name = template.assemblerMethodName() + "_" + template.serial(); this.extraConstructorArguments = extraConstructorArguments; final String labelType; if (superClass == InstructionWithAddress.class) { labelType = "address"; } else if (superClass == InstructionWithOffset.class) { labelType = "offset"; } else { throw ProgramError.unexpected("Unknown instruction with label type: " + superClass); } this.labelArgumentPrefix = labelType + "As"; } /** * Prints the body of the {@link MutableAssembledObject#assemble} method in a label method helper class being * generated by a call to {@link AssemblerGenerator#printLabelMethodHelper}. * <p> * The default implementation generates a call to the raw assembler method generated for {@code template} * * @param writer * @param template */ protected void printAssembleMethodBody(IndentWriter writer, Template template) { writer.print(template.assemblerMethodName() + "("); final List<? extends Parameter> parameters = template.parameters(); String separator = ""; int index = 0; final int labelParameterIndex = template.labelParameterIndex(); final String labelArgument = labelArgumentPrefix + Strings.firstCharToUpperCase(parameters.get(labelParameterIndex).type().getName()) + "()"; for (Parameter parameter : parameters) { writer.print(separator); if (index == labelParameterIndex) { writer.print(labelArgument); } else { writer.print(parameter.variableName()); } separator = ", "; index++; } writer.println(");"); } @Override public String toString() { return name; } } /** * Prints the code that emits the place holder bytes for a label instruction before a value has been bound to the * label. * * @param writer * @param template * @param placeholderInstructionSize the number of place holder bytes written to the instruction stream before the * label's value has been determined. If this value is -1, then the size depends on the arguments to the * method and so a call to the raw assembler method is made to determine the size. * @return an expression denoting the number of place holder bytes emitted */ private String printPlaceholderBytes(IndentWriter writer, Template_Type template, int placeholderInstructionSize) { if (placeholderInstructionSize == -1) { writer.println("final " + template.parameters().get(template.labelParameterIndex()).type() + " placeHolder = 0;"); writer.print(template.assemblerMethodName() + "("); String separator = ""; for (int i = 0; i < template.parameters().size(); i++) { writer.print(separator); if (i == template.labelParameterIndex()) { writer.print("placeHolder"); } else { writer.print(template.parameters().get(i).variableName()); } separator = ", "; } writer.println(");"); return "currentPosition() - startPosition"; } if (placeholderInstructionSize == 2) { writer.println("emitShort(0);"); } else if (placeholderInstructionSize == 4) { writer.println("emitInt(0);"); } else if (placeholderInstructionSize == 8) { writer.println("emitLong(0);"); } else { writer.println("emitZeroes(" + placeholderInstructionSize + ");"); } return String.valueOf(placeholderInstructionSize); } /** * Handles most of the work of {@link #printLabelMethod(IndentWriter, Template, String)}. * * @param writer the writer to which code will be printed * @param template a template that has a label parameter (i.e. its {@linkplain Template#labelParameterIndex() label * parameter index} is not -1) * @param parameters the parameters of the template with the label parameter represented as a {@link LabelParameter} * object * @param placeholderInstructionSize the number of place holder bytes written to the instruction stream before the * label's value has been determined. If this value is -1, then the size depends on the arguments to the * method and so a call to the raw assembler method is made to determine the size. * @param assemblerClassName the name of the class in which the assembler methods will be declared * @param labelInstructionSubclassGenerator the object that writes the body of the * {@link MutableAssembledObject#assemble} method in a generated label method helper class */ protected final void printLabelMethodHelper(IndentWriter writer, Template_Type template, List<Parameter> parameters, int placeholderInstructionSize, String assemblerClassName, InstructionWithLabelSubclass labelInstructionSubclassGenerator) { assert template.labelParameterIndex() != -1; printLabelMethodHead(writer, template, parameters); writer.println("final int startPosition = currentPosition();"); final String size = printPlaceholderBytes(writer, template, placeholderInstructionSize); writer.print("new " + labelInstructionSubclassGenerator.name + "(startPosition, " + size + ", "); for (Parameter parameter : parameters) { if (!(parameter instanceof LabelParameter)) { writer.print(parameter.variableName() + ", "); } } writer.println("label);"); writer.outdent(); writer.println("}"); writer.println(); final StringWriter stringWriter = new StringWriter(); final IndentWriter indentWriter = new IndentWriter(new PrintWriter(stringWriter)); indentWriter.indent(); printLabelMethodHelperClass( indentWriter, template, parameters, assemblerClassName, labelInstructionSubclassGenerator); labelMethodHelperClasses.add(stringWriter.toString()); } private final List<String> labelMethodHelperClasses = new ArrayList<>(); private void printLabelMethodHelperClass( IndentWriter writer, Template_Type template, List<Parameter> parameters, String assemblerClassName, InstructionWithLabelSubclass labelInstructionSubclass) { final String simpleAssemblerClassName = assemblerClassName.substring(assemblerClassName.lastIndexOf('.') + 1); writer.println("class " + labelInstructionSubclass + " extends " + labelInstructionSubclass.superClass.getSimpleName() + " {"); writer.indent(); String parametersDecl = ""; for (Parameter parameter : parameters) { if (!(parameter instanceof LabelParameter)) { final Class parameterType = parameter.type(); final String typeName = Classes.getSimpleName(parameterType, true); final String variableName = parameter.variableName(); writer.println("private final " + typeName + " " + variableName + ";"); parametersDecl = parametersDecl + typeName + " " + variableName + ", "; } } writer.println(labelInstructionSubclass + "(int startPosition, int endPosition, " + parametersDecl + "Label label) {"); writer.indent(); writer.println("super(" + simpleAssemblerClassName + ".this, startPosition, currentPosition(), label" + labelInstructionSubclass.extraConstructorArguments + ");"); for (Parameter parameter : parameters) { if (!(parameter instanceof LabelParameter)) { final String variableName = parameter.variableName(); writer.println("this." + variableName + " = " + variableName + ";"); } } writer.outdent(); writer.println("}"); writer.println("@Override"); writer.println("protected void assemble() throws AssemblyException {"); writer.indent(); labelInstructionSubclass.printAssembleMethodBody(writer, template); writer.outdent(); writer.println("}"); writer.outdent(); writer.println("}"); writer.println(); } private boolean generateLabelAssemblerMethods(String labelAssemblerClassName) throws IOException { Trace.line(1, "Generating label assembler methods"); final List<Template_Type> labelTemplateList = labelTemplates(); final File sourceFile = getSourceFileFor(labelAssemblerClassName); ProgramError.check(sourceFile.exists(), "Source file for class containing label assembler methods does not exist: " + sourceFile); final CharArraySource charArrayWriter = new CharArraySource((int) sourceFile.length()); final IndentWriter writer = new IndentWriter(new PrintWriter(charArrayWriter)); writer.indent(); int codeLineCount = 0; int i = 0; for (Template_Type labelTemplate : labelTemplateList) { if (!omitLabelTemplate(labelTemplate)) { printMethodComment(writer, labelTemplate, i + 1, true); final int startLineCount = writer.lineCount(); printLabelMethod(writer, labelTemplate, labelAssemblerClassName); codeLineCount += writer.lineCount() - startLineCount; i++; } } writer.outdent(); for (String labelMethodHelperClass : labelMethodHelperClasses) { writer.print(labelMethodHelperClass); } writer.close(); Trace.line(1, "Generated label assembler methods" + " [code line count=" + codeLineCount + ", total line count=" + writer.lineCount() + ", method count=" + templates().size() + ")"); return Files.updateGeneratedContent(sourceFile, charArrayWriter, "// START GENERATED LABEL ASSEMBLER METHODS", "// END GENERATED LABEL ASSEMBLER METHODS", false); } protected void emitByte(IndentWriter writer, String byteValue) { writer.print("emitByte(" + byteValue + ");"); } protected void emitByte(IndentWriter writer, byte value) { emitByte(writer, "((byte) " + Bytes.toHexLiteral(value) + ")"); } protected void generate() { try { final String rawAssemblerClassName = rawAssemblerClassNameOption.getValue(); final String labelAssemblerClassName = labelAssemblerClassNameOption.getValue(); final boolean rawAssemblerMethodsUpdated = generateRawAssemblerMethods(rawAssemblerClassName); final boolean labelAssemblerMethodsUpdated = generateLabelAssemblerMethods(labelAssemblerClassName); if (rawAssemblerClassName.equals(labelAssemblerClassName)) { if (rawAssemblerMethodsUpdated || labelAssemblerMethodsUpdated) { System.out.println("modified: " + getSourceFileFor(rawAssemblerClassName)); if (!ToolChain.compile(AssemblerGenerator.class, rawAssemblerClassName)) { List<Template_Type> allTemplates = new ArrayList<>(templates()); allTemplates.addAll(labelTemplates()); throw ProgramError.unexpected("compilation failed for: " + rawAssemblerClassName + "[Maybe missing an import statement for one of the following packages: " + getImportPackages(rawAssemblerClassName, allTemplates)); } } else { System.out.println("unmodified: " + getSourceFileFor(rawAssemblerClassName)); } } else { if (rawAssemblerMethodsUpdated) { System.out.println("modified: " + getSourceFileFor(rawAssemblerClassName)); if (!ToolChain.compile(AssemblerGenerator.class, rawAssemblerClassName)) { throw ProgramError.unexpected("compilation failed for: " + rawAssemblerClassName + "[Maybe missing an import statement for one of the following packages: " + getImportPackages(rawAssemblerClassName, templates())); } } else { System.out.println("unmodified: " + getSourceFileFor(rawAssemblerClassName)); } if (labelAssemblerMethodsUpdated) { System.out.println("modified: " + getSourceFileFor(labelAssemblerClassName)); if (!ToolChain.compile(AssemblerGenerator.class, labelAssemblerClassName)) { throw ProgramError.unexpected("compilation failed for: " + labelAssemblerClassName + "[Maybe missing an import statement for one of the following packages: " + getImportPackages(labelAssemblerClassName, labelTemplates())); } } else { System.out.println("unmodified: " + getSourceFileFor(labelAssemblerClassName)); } } Trace.line(1, "done"); } catch (Throwable throwable) { throwable.printStackTrace(); System.err.println("something went wrong: " + throwable + ": " + throwable.getMessage()); } } }