comparison graal/com.oracle.max.asmdis/src/com/sun/max/asm/gen/AssemblerGenerator.java @ 3733:e233f5660da4

Added Java files from Maxine project.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sat, 17 Dec 2011 19:59:18 +0100
parents
children bc8527f3071c
comparison
equal deleted inserted replaced
3732:3e2e8b8abdaf 3733:e233f5660da4
1 /*
2 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23 package com.sun.max.asm.gen;
24
25 import static com.sun.max.lang.Classes.*;
26
27 import java.io.*;
28 import java.lang.reflect.*;
29 import java.util.*;
30
31 import com.sun.max.*;
32 import com.sun.max.asm.*;
33 import com.sun.max.asm.dis.*;
34 import com.sun.max.ide.*;
35 import com.sun.max.io.*;
36 import com.sun.max.lang.*;
37 import com.sun.max.program.*;
38 import com.sun.max.program.option.*;
39
40 /**
41 * Source code generator for raw and label assembler methods derived from an ISA specification.
42 */
43 public abstract class AssemblerGenerator<Template_Type extends Template> {
44
45 protected OptionSet options = new OptionSet();
46
47 public final Option<File> outputDirectoryOption = options.newFileOption("d", JavaProject.findSourceDirectory(AssemblerGenerator.class),
48 "Source directory of the class(es) containing the for generated assembler methods.");
49 public final Option<String> assemblerInterfaceNameOption = options.newStringOption("i", null,
50 "Interface used to constrain which assembler methods will be generated. " +
51 "If absent, an assembler method is generated for each template in the specification.");
52 public final Option<String> rawAssemblerClassNameOption = options.newStringOption("r", null,
53 "Class containing the generated raw assembler methods.");
54 public final Option<String> labelAssemblerClassNameOption = options.newStringOption("l", null,
55 "Class containing the generated label assembler methods.");
56 public final Option<Boolean> generateRedundantInstructionsOption = options.newBooleanOption("redundant", true,
57 "Generate assembler methods for redundant templates. Two templates are redundant if they " +
58 "both have the same name and operands. Redundant pairs of instructions are assumed to " +
59 "implement the same machine instruction semantics but may have different encodings.");
60
61 private final Assembly<Template_Type> assembly;
62 private final boolean sortAssemblerMethods;
63 private List<Template_Type> templates;
64 private List<Template_Type> labelTemplates;
65
66 protected AssemblerGenerator(Assembly<Template_Type> assembly, boolean sortAssemblerMethods) {
67 Trace.addTo(options);
68 this.assembly = assembly;
69 final String isa = assembly.isa().name();
70 final String defaultOutputPackage = getPackageName(Assembler.class) + "." + isa.toLowerCase() + ".complete";
71 this.rawAssemblerClassNameOption.setDefaultValue(defaultOutputPackage + "." + isa + "RawAssembler");
72 this.labelAssemblerClassNameOption.setDefaultValue(defaultOutputPackage + "." + isa + "LabelAssembler");
73 this.sortAssemblerMethods = sortAssemblerMethods;
74 }
75
76 public Assembly<Template_Type> assembly() {
77 return assembly;
78 }
79
80 static class MethodKey {
81 final String name;
82 final Class[] parameterTypes;
83
84 MethodKey(Method method) {
85 name = method.getName();
86 parameterTypes = method.getParameterTypes();
87 }
88
89 MethodKey(Template template, boolean asLabelTemplate) {
90 name = template.assemblerMethodName();
91 parameterTypes = template.parameterTypes();
92 if (asLabelTemplate) {
93 final int labelParameterIndex = template.labelParameterIndex();
94 assert labelParameterIndex != -1;
95 parameterTypes[labelParameterIndex] = Label.class;
96 }
97 }
98
99 @Override
100 public boolean equals(Object object) {
101 if (object instanceof MethodKey) {
102 final MethodKey other = (MethodKey) object;
103 return other.name.equals(name) && Arrays.equals(parameterTypes, other.parameterTypes);
104 }
105 return false;
106 }
107
108 @Override
109 public int hashCode() {
110 return name.hashCode() ^ parameterTypes.length;
111 }
112
113 @Override
114 public String toString() {
115 final String paramTypes = Arrays.toString(this.parameterTypes);
116 return name + "(" + paramTypes.substring(1, paramTypes.length() - 1) + ")";
117 }
118
119 }
120
121 private List<Template_Type> filterTemplates(List<Template_Type> templates) {
122 if (!generateRedundantInstructionsOption.getValue()) {
123 final List<Template_Type> result = new LinkedList<Template_Type>();
124 for (Template_Type template : templates) {
125 if (!template.isRedundant()) {
126 result.add(template);
127 }
128 }
129 return result;
130 }
131 return templates;
132 }
133
134 /**
135 * Initializes the set of label and raw templates that will be generated as assembler methods.
136 * This includes doing any filtering out of templates based on an {@linkplain #assemblerInterfaceNameOption assembler interface}.
137 */
138 private void initTemplates() {
139 assert (labelTemplates == null) == (templates == null);
140 if (templates == null) {
141 final String assemblerInterfaceName = assemblerInterfaceNameOption.getValue();
142 if (assemblerInterfaceName == null) {
143 templates = filterTemplates(assembly().templates());
144 labelTemplates = filterTemplates(assembly().labelTemplates());
145 } else {
146 final List<Template_Type> newTemplates = new ArrayList<Template_Type>();
147 final List<Template_Type> newLabelTemplates = new ArrayList<Template_Type>();
148
149 Class assemberInterface = null;
150 try {
151 assemberInterface = Class.forName(assemblerInterfaceName);
152 ProgramError.check(assemberInterface.isInterface(), "The class " + assemblerInterfaceName + " is not an interface");
153 } catch (ClassNotFoundException e) {
154 throw ProgramError.unexpected("The assembler interface class " + assemblerInterfaceName + " must be on the class path");
155 }
156 final Set<MethodKey> assemblerInterfaceMethods = new HashSet<MethodKey>();
157 for (Method assemblerInterfaceMethod : assemberInterface.getDeclaredMethods()) {
158 assemblerInterfaceMethods.add(new MethodKey(assemblerInterfaceMethod));
159 }
160
161 for (Template_Type labelTemplate : assembly().labelTemplates()) {
162 if (assemblerInterfaceMethods.contains(new MethodKey(labelTemplate, true))) {
163 assert labelTemplate.labelParameterIndex() != -1;
164 newLabelTemplates.add(labelTemplate);
165 }
166 }
167
168 for (Template_Type template : assembly().templates()) {
169 if (template.labelParameterIndex() != -1 && assemblerInterfaceMethods.contains(new MethodKey(template, true))) {
170 newTemplates.add(template);
171 } else if (assemblerInterfaceMethods.contains(new MethodKey(template, false))) {
172 newTemplates.add(template);
173 }
174 }
175
176 this.templates = newTemplates;
177 this.labelTemplates = newLabelTemplates;
178
179 Trace.line(1, "Based on " + assemberInterface + ", " + (assembly().templates().size() - newTemplates.size()) + " (of " + assembly().templates().size() + ") raw templates and " +
180 (assembly().labelTemplates().size() - newLabelTemplates.size()) + " (of " + assembly().labelTemplates().size() + ") label templates will be omitted from generated assembler methods");
181 }
182
183 if (sortAssemblerMethods) {
184 Class<Template_Type[]> type = null;
185 Template_Type[] sortedTemplates = Utils.cast(type, Array.newInstance(assembly().templateType(), templates.size()));
186 Template_Type[] sortedLabelTemplates = Utils.cast(type, Array.newInstance(assembly().templateType(), labelTemplates.size()));
187 templates.toArray(sortedTemplates);
188 Arrays.sort(sortedTemplates);
189 templates = Arrays.asList(sortedTemplates);
190 labelTemplates.toArray(sortedLabelTemplates);
191 Arrays.sort(sortedLabelTemplates);
192 labelTemplates = Arrays.asList(sortedLabelTemplates);
193 }
194 }
195 }
196
197 protected final List<Template_Type> templates() {
198 initTemplates();
199 return templates;
200 }
201
202 protected final List<Template_Type> labelTemplates() {
203 initTemplates();
204 return labelTemplates;
205 }
206
207 /**
208 * Gets the absolute path to the source file that will updated to include the generated assembler methods.
209 *
210 * @param className the name of the Java class that contains the generated assembler methods
211 */
212 private File getSourceFileFor(String className) {
213 return new File(outputDirectoryOption.getValue(), className.replace('.', File.separatorChar) + ".java").getAbsoluteFile();
214 }
215
216 protected final String formatParameterList(String separator, List<? extends Parameter> parameters, boolean typesOnly) {
217 String sep = separator;
218 final StringBuilder sb = new StringBuilder();
219 for (Parameter parameter : parameters) {
220 sb.append(sep);
221 sb.append(Classes.getSimpleName(parameter.type(), true));
222 if (!typesOnly) {
223 sb.append(" ");
224 sb.append(parameter.variableName());
225 }
226 if (!sep.startsWith(", ")) {
227 sep = ", " + sep;
228 }
229 }
230 return sb.toString();
231 }
232
233 /**
234 * Prints the source code for the raw assembler method for to a given template.
235 *
236 * @return the number of source code lines printed
237 */
238 protected abstract int printMethod(IndentWriter writer, Template_Type template);
239
240 /**
241 * Prints the source code for support methods that are used by the methods printed by {@link #printMethod(IndentWriter, Template)}.
242 *
243 * @return the number of subroutines printed
244 */
245 protected int printSubroutines(IndentWriter writer) {
246 return 0;
247 }
248
249 /**
250 * Gets the set of packages that must be imported for the generated code to compile successfully.
251 *
252 * @param className the name of the Java class that contains the assembler methods generated from {@code templates}
253 * @param templateList the list of templates for which code is being generated
254 * @return a set of packages sorted by name
255 */
256 public Set<String> getImportPackages(String className, Iterable<Template_Type> templateList) {
257 final String outputPackage = getPackageName(className);
258 final Set<String> packages = new TreeSet<String>();
259 packages.add(getPackageName(AssemblyException.class));
260 packages.add(getPackageName(Label.class));
261 for (Template_Type template : templateList) {
262 for (Parameter parameter : template.parameters()) {
263 final Class type = parameter.type();
264 if (!type.isPrimitive()) {
265 final String p = getPackageName(type);
266 if (!p.equals(outputPackage)) {
267 packages.add(p);
268 }
269 }
270 }
271 }
272 return packages;
273 }
274
275 /**
276 * Prints the Javadoc comment for a template followed by a C++ style comment stating the template's number (it's
277 * position in the order of emitted assembler methods) and its serial (a unique identifier given to every template).
278 */
279 protected void printMethodComment(IndentWriter writer, Template_Type template, int number, boolean forLabelAssemblerMethod) {
280 printMethodJavadoc(writer, template, forLabelAssemblerMethod);
281 writer.println("// Template#: " + number + ", Serial#: " + template.serial());
282 }
283
284 /**
285 * Determines if a given label template should be omitted from assembler method generation.
286 * This method is overridden by subclasses that may generate the code for 2 related label templates
287 * in a single assembler method. For example, on X86 most branch instructions can take offsets of variable bit widths
288 * and the logic for decoding the bit width of a {@link Label} value may be generated in a single assembler method.
289 * <p>
290 * The default implementation of this method returns {@code false}.
291 */
292 protected boolean omitLabelTemplate(Template_Type labelTemplate) {
293 return false;
294 }
295
296 /**
297 * Gets a reference to the architecture manual section describing the given template. The
298 * returned string should conform to the format of the {@code @see} Javadoc tag.
299 */
300 protected String getJavadocManualReference(Template_Type template) {
301 return null;
302 }
303
304 /**
305 * Allows subclasses to print ISA specific details for a template. For example, RISC synthetic instructions
306 * print what raw instruction they are derived from.
307 *
308 * @param extraLinks
309 * a sequence to which extra javadoc links should be appended
310 */
311 protected void printExtraMethodJavadoc(IndentWriter writer, Template_Type template, List<String> extraLinks, boolean forLabelAssemblerMethod) {
312 }
313
314 private boolean seenNoSuchAssemblerMethodError;
315
316 /**
317 * Writes the Javadoc comment for an assembler method.
318 *
319 * @param template the template from which the assembler method is generated
320 */
321 protected void printMethodJavadoc(IndentWriter writer, Template_Type template, boolean forLabelAssemblerMethod) {
322 final List<String> extraLinks = new LinkedList<String>();
323 final List<? extends Parameter> parameters = getParameters(template, forLabelAssemblerMethod);
324 writer.println("/**");
325 writer.println(" * Pseudo-external assembler syntax: {@code " + template.externalName() + externalMnemonicSuffixes(parameters) + " }" + externalParameters(parameters));
326
327 final boolean printExampleInstruction = true;
328 if (printExampleInstruction) {
329
330 final List<Argument> arguments = new ArrayList<Argument>();
331 final AddressMapper addressMapper = new AddressMapper();
332 for (Parameter p : template.parameters()) {
333 final Argument exampleArg = p.getExampleArgument();
334 if (exampleArg != null) {
335 arguments.add(exampleArg);
336 } else {
337 break;
338 }
339 }
340 if (arguments.size() == template.parameters().size()) {
341 try {
342 final DisassembledInstruction instruction = generateExampleInstruction(template, arguments);
343 final ImmediateArgument targetAddress = instruction.targetAddress();
344
345 if (targetAddress != null) {
346 addressMapper.add(targetAddress, "L1");
347 }
348 final String exampleInstruction = instruction.toString(addressMapper);
349 writer.println(" * Example disassembly syntax: {@code " + exampleInstruction + "}");
350 } catch (NoSuchAssemblerMethodError e) {
351 if (!seenNoSuchAssemblerMethodError) {
352 seenNoSuchAssemblerMethodError = true;
353 ProgramWarning.message("Once generated assembler has been compiled, re-generate it you want a usage example " +
354 "in the Javadoc for every generated assembler method");
355 }
356 } catch (AssemblyException e) {
357 ProgramWarning.message("Error generating example instruction: " + e);
358 }
359 }
360 }
361
362 printExtraMethodJavadoc(writer, template, extraLinks, forLabelAssemblerMethod);
363 final List<InstructionConstraint> constraints = new ArrayList<InstructionConstraint>(template.instructionDescription().specifications().size());
364 for (Object s : template.instructionDescription().specifications()) {
365 if (s instanceof InstructionConstraint) {
366 constraints.add((InstructionConstraint) s);
367 }
368 }
369 if (!constraints.isEmpty()) {
370 writer.println(" * <p>");
371 for (InstructionConstraint constraint : constraints) {
372 final Method predicateMethod = constraint.predicateMethod();
373 if (predicateMethod != null) {
374 extraLinks.add(predicateMethod.getDeclaringClass().getName() + "#" + predicateMethod.getName());
375 }
376 writer.println(" * Constraint: {@code " + constraint.asJavaExpression() + "}<br />");
377 }
378 }
379
380 if (!extraLinks.isEmpty()) {
381 writer.println(" *");
382 for (String link : extraLinks) {
383 writer.println(" * @see " + link);
384 }
385 }
386
387 final String ref = getJavadocManualReference(template);
388 if (ref != null) {
389 writer.println(" *");
390 writer.println(" * @see " + ref);
391 }
392 writer.println(" */");
393 }
394
395 protected abstract DisassembledInstruction generateExampleInstruction(Template_Type template, List<Argument> arguments) throws AssemblyException;
396
397 private String externalParameters(List< ? extends Parameter> parameters) {
398 final StringBuilder sb = new StringBuilder();
399 boolean first = true;
400 for (Parameter parameter : parameters) {
401 if (!ExternalMnemonicSuffixArgument.class.isAssignableFrom(parameter.type())) {
402 if (!first) {
403 sb.append(", ");
404 }
405 sb.append("<i>").append(parameter.variableName()).append("</i>");
406 first = false;
407 }
408 }
409 return sb.toString();
410 }
411
412 private String externalMnemonicSuffixes(List< ? extends Parameter> parameters) {
413 final StringBuilder sb = new StringBuilder();
414 for (Parameter parameter : parameters) {
415 if (ExternalMnemonicSuffixArgument.class.isAssignableFrom(parameter.type())) {
416 boolean first = true;
417 String close = "]";
418 for (Argument argument : parameter.getLegalTestArguments()) {
419 final String externalValue = argument.externalValue();
420 if (externalValue.length() != 0) {
421 if (!first) {
422 sb.append("|");
423 } else {
424 if (((ExternalMnemonicSuffixArgument) argument).isOptional()) {
425 sb.append("{");
426 close = "}";
427 } else {
428 sb.append("[");
429 }
430 }
431 sb.append(externalValue);
432 first = false;
433 }
434 }
435 sb.append(close);
436 }
437 }
438 return sb.toString();
439 }
440
441 private boolean generateRawAssemblerMethods(String rawAssemblerClassName) throws IOException {
442 Trace.line(1, "Generating raw assembler methods");
443 final List<Template_Type> templateList = templates();
444 final File sourceFile = getSourceFileFor(rawAssemblerClassName);
445 ProgramError.check(sourceFile.exists(), "Source file for class containing raw assembler methods does not exist: " + sourceFile);
446 final CharArraySource charArrayWriter = new CharArraySource((int) sourceFile.length());
447 final IndentWriter writer = new IndentWriter(new PrintWriter(charArrayWriter));
448 writer.indent();
449
450 int codeLineCount = 0;
451 final Map<InstructionDescription, Integer> instructionDescriptions = new HashMap<InstructionDescription, Integer>();
452 int maxTemplatesPerDescription = 0;
453 int i = 0;
454 for (Template_Type template : templateList) {
455 printMethodComment(writer, template, i + 1, false);
456 codeLineCount += printMethod(writer, template);
457 writer.println();
458
459 Integer count = instructionDescriptions.get(template.instructionDescription());
460 if (count == null) {
461 count = 1;
462 } else {
463 count = count + 1;
464 }
465 if (count > maxTemplatesPerDescription) {
466 maxTemplatesPerDescription = count;
467 }
468 instructionDescriptions.put(template.instructionDescription(), count);
469 i++;
470 }
471 final int subroutineCount = printSubroutines(writer);
472
473 writer.outdent();
474 writer.close();
475
476 Trace.line(1, "Generated raw assembler methods" +
477 " [code line count=" + codeLineCount + ", total line count=" + writer.lineCount() +
478 ", method count=" + (templateList.size() + subroutineCount) +
479 ", instruction templates=" + templateList.size() + ", max templates per description=" + maxTemplatesPerDescription +
480 "]");
481
482 return Files.updateGeneratedContent(sourceFile, charArrayWriter, "// START GENERATED RAW ASSEMBLER METHODS", "// END GENERATED RAW ASSEMBLER METHODS", false);
483 }
484
485 /**
486 * Gets the parameters for a template.
487 *
488 * @param forLabelAssemblerMethod
489 * if true and template contains a label parameter, then this parameter is represented as a
490 * {@link LabelParameter} object in the returned sequence
491 */
492 protected static List<Parameter> getParameters(Template template, boolean forLabelAssemblerMethod) {
493 if (!forLabelAssemblerMethod || template.labelParameterIndex() == -1) {
494 final Class<List<Parameter>> type = null;
495 return Utils.cast(type, template.parameters());
496 }
497 final List<Parameter> parameters = new ArrayList<Parameter>(template.parameters());
498 parameters.set(template.labelParameterIndex(), LabelParameter.LABEL);
499 return parameters;
500 }
501
502 protected void printLabelMethodHead(IndentWriter writer, Template_Type template, List<Parameter> parameters) {
503 writer.print("public void " + template.assemblerMethodName() + "(");
504 writer.print(formatParameterList("final ", parameters, false));
505 writer.println(") {");
506 writer.indent();
507 }
508
509 /**
510 * Prints an assembler method for a template that refers to an address via a {@linkplain Label label}.
511 *
512 * @param writer the writer to which code will be printed
513 * @param labelTemplate a template that has a label parameter (i.e. its {@linkplain Template#labelParameterIndex()
514 * label parameter index} is not -1)
515 * @param assemblerClassName the name of the class enclosing the assembler method declaration
516 */
517 protected abstract void printLabelMethod(IndentWriter writer, Template_Type labelTemplate, String assemblerClassName);
518
519 /**
520 * Mechanism that writes the body of the {@link MutableAssembledObject#assemble} method in a generated label method helper class.
521 */
522 public class InstructionWithLabelSubclass {
523
524 final Class<? extends InstructionWithLabel> superClass;
525 final String name;
526 final String extraConstructorArguments;
527 final String labelArgumentPrefix;
528
529 public InstructionWithLabelSubclass(Template template, Class<? extends InstructionWithLabel> superClass, String extraConstructorArguments) {
530 this.superClass = superClass;
531 this.name = template.assemblerMethodName() + "_" + template.serial();
532 this.extraConstructorArguments = extraConstructorArguments;
533 final String labelType;
534 if (superClass == InstructionWithAddress.class) {
535 labelType = "address";
536 } else if (superClass == InstructionWithOffset.class) {
537 labelType = "offset";
538 } else {
539 throw ProgramError.unexpected("Unknown instruction with label type: " + superClass);
540 }
541 this.labelArgumentPrefix = labelType + "As";
542 }
543
544 /**
545 * Prints the body of the {@link MutableAssembledObject#assemble} method in a label method helper class being
546 * generated by a call to {@link AssemblerGenerator#printLabelMethodHelper}.
547 * <p>
548 * The default implementation generates a call to the raw assembler method generated for {@code template}
549 *
550 * @param writer
551 * @param template
552 */
553 protected void printAssembleMethodBody(IndentWriter writer, Template template) {
554 writer.print(template.assemblerMethodName() + "(");
555 final List<? extends Parameter> parameters = template.parameters();
556 String separator = "";
557 int index = 0;
558 final int labelParameterIndex = template.labelParameterIndex();
559 final String labelArgument = labelArgumentPrefix + Strings.firstCharToUpperCase(parameters.get(labelParameterIndex).type().getName()) + "()";
560 for (Parameter parameter : parameters) {
561 writer.print(separator);
562 if (index == labelParameterIndex) {
563 writer.print(labelArgument);
564 } else {
565 writer.print(parameter.variableName());
566 }
567 separator = ", ";
568 index++;
569 }
570 writer.println(");");
571 }
572
573 @Override
574 public String toString() {
575 return name;
576 }
577 }
578
579 /**
580 * Prints the code that emits the place holder bytes for a label instruction before a value has been bound to the
581 * label.
582 *
583 * @param writer
584 * @param template
585 * @param placeholderInstructionSize the number of place holder bytes written to the instruction stream before the
586 * label's value has been determined. If this value is -1, then the size depends on the arguments to the
587 * method and so a call to the raw assembler method is made to determine the size.
588 * @return an expression denoting the number of place holder bytes emitted
589 */
590 private String printPlaceholderBytes(IndentWriter writer, Template_Type template, int placeholderInstructionSize) {
591 if (placeholderInstructionSize == -1) {
592 writer.println("final " + template.parameters().get(template.labelParameterIndex()).type() + " placeHolder = 0;");
593 writer.print(template.assemblerMethodName() + "(");
594 String separator = "";
595 for (int i = 0; i < template.parameters().size(); i++) {
596 writer.print(separator);
597 if (i == template.labelParameterIndex()) {
598 writer.print("placeHolder");
599 } else {
600 writer.print(template.parameters().get(i).variableName());
601 }
602 separator = ", ";
603 }
604 writer.println(");");
605 return "currentPosition() - startPosition";
606 }
607
608 if (placeholderInstructionSize == 2) {
609 writer.println("emitShort(0);");
610 } else if (placeholderInstructionSize == 4) {
611 writer.println("emitInt(0);");
612 } else if (placeholderInstructionSize == 8) {
613 writer.println("emitLong(0);");
614 } else {
615 writer.println("emitZeroes(" + placeholderInstructionSize + ");");
616 }
617 return String.valueOf(placeholderInstructionSize);
618 }
619
620 /**
621 * Handles most of the work of {@link #printLabelMethod(IndentWriter, Template, String)}.
622 *
623 * @param writer the writer to which code will be printed
624 * @param template a template that has a label parameter (i.e. its {@linkplain Template#labelParameterIndex() label
625 * parameter index} is not -1)
626 * @param parameters the parameters of the template with the label parameter represented as a {@link LabelParameter}
627 * object
628 * @param placeholderInstructionSize the number of place holder bytes written to the instruction stream before the
629 * label's value has been determined. If this value is -1, then the size depends on the arguments to the
630 * method and so a call to the raw assembler method is made to determine the size.
631 * @param assemblerClassName the name of the class in which the assembler methods will be declared
632 * @param labelInstructionSubclassGenerator the object that writes the body of the
633 * {@link MutableAssembledObject#assemble} method in a generated label method helper class
634 */
635 protected final void printLabelMethodHelper(IndentWriter writer,
636 Template_Type template,
637 List<Parameter> parameters,
638 int placeholderInstructionSize,
639 String assemblerClassName,
640 InstructionWithLabelSubclass labelInstructionSubclassGenerator) {
641 assert template.labelParameterIndex() != -1;
642 printLabelMethodHead(writer, template, parameters);
643 writer.println("final int startPosition = currentPosition();");
644 final String size = printPlaceholderBytes(writer, template, placeholderInstructionSize);
645 writer.print("new " + labelInstructionSubclassGenerator.name + "(startPosition, " + size + ", ");
646 for (Parameter parameter : parameters) {
647 if (!(parameter instanceof LabelParameter)) {
648 writer.print(parameter.variableName() + ", ");
649 }
650 }
651 writer.println("label);");
652 writer.outdent();
653 writer.println("}");
654 writer.println();
655
656 final StringWriter stringWriter = new StringWriter();
657 final IndentWriter indentWriter = new IndentWriter(new PrintWriter(stringWriter));
658 indentWriter.indent();
659 printLabelMethodHelperClass(
660 indentWriter,
661 template,
662 parameters,
663 assemblerClassName,
664 labelInstructionSubclassGenerator);
665 labelMethodHelperClasses.add(stringWriter.toString());
666 }
667
668 private final List<String> labelMethodHelperClasses = new ArrayList<String>();
669
670 private void printLabelMethodHelperClass(
671 IndentWriter writer,
672 Template_Type template,
673 List<Parameter> parameters,
674 String assemblerClassName,
675 InstructionWithLabelSubclass labelInstructionSubclass) {
676 final String simpleAssemblerClassName = assemblerClassName.substring(assemblerClassName.lastIndexOf('.') + 1);
677 writer.println("class " + labelInstructionSubclass + " extends " + labelInstructionSubclass.superClass.getSimpleName() + " {");
678 writer.indent();
679 String parametersDecl = "";
680 for (Parameter parameter : parameters) {
681 if (!(parameter instanceof LabelParameter)) {
682 final Class parameterType = parameter.type();
683 final String typeName = Classes.getSimpleName(parameterType, true);
684 final String variableName = parameter.variableName();
685 writer.println("private final " + typeName + " " + variableName + ";");
686 parametersDecl = parametersDecl + typeName + " " + variableName + ", ";
687 }
688 }
689
690 writer.println(labelInstructionSubclass + "(int startPosition, int endPosition, " + parametersDecl + "Label label) {");
691 writer.indent();
692 writer.println("super(" + simpleAssemblerClassName + ".this, startPosition, currentPosition(), label" + labelInstructionSubclass.extraConstructorArguments + ");");
693 for (Parameter parameter : parameters) {
694 if (!(parameter instanceof LabelParameter)) {
695 final String variableName = parameter.variableName();
696 writer.println("this." + variableName + " = " + variableName + ";");
697 }
698 }
699 writer.outdent();
700 writer.println("}");
701 writer.println("@Override");
702 writer.println("protected void assemble() throws AssemblyException {");
703 writer.indent();
704 labelInstructionSubclass.printAssembleMethodBody(writer, template);
705 writer.outdent();
706 writer.println("}");
707 writer.outdent();
708 writer.println("}");
709 writer.println();
710 }
711
712 private boolean generateLabelAssemblerMethods(String labelAssemblerClassName) throws IOException {
713 Trace.line(1, "Generating label assembler methods");
714 final List<Template_Type> labelTemplateList = labelTemplates();
715 final File sourceFile = getSourceFileFor(labelAssemblerClassName);
716 ProgramError.check(sourceFile.exists(), "Source file for class containing label assembler methods does not exist: " + sourceFile);
717 final CharArraySource charArrayWriter = new CharArraySource((int) sourceFile.length());
718 final IndentWriter writer = new IndentWriter(new PrintWriter(charArrayWriter));
719 writer.indent();
720
721 int codeLineCount = 0;
722 int i = 0;
723 for (Template_Type labelTemplate : labelTemplateList) {
724 if (!omitLabelTemplate(labelTemplate)) {
725 printMethodComment(writer, labelTemplate, i + 1, true);
726 final int startLineCount = writer.lineCount();
727 printLabelMethod(writer, labelTemplate, labelAssemblerClassName);
728 codeLineCount += writer.lineCount() - startLineCount;
729 i++;
730 }
731 }
732 writer.outdent();
733
734 for (String labelMethodHelperClass : labelMethodHelperClasses) {
735 writer.print(labelMethodHelperClass);
736 }
737
738 writer.close();
739
740 Trace.line(1, "Generated label assembler methods" +
741 " [code line count=" + codeLineCount +
742 ", total line count=" + writer.lineCount() +
743 ", method count=" + templates().size() + ")");
744
745 return Files.updateGeneratedContent(sourceFile, charArrayWriter, "// START GENERATED LABEL ASSEMBLER METHODS", "// END GENERATED LABEL ASSEMBLER METHODS", false);
746 }
747
748 protected void emitByte(IndentWriter writer, String byteValue) {
749 writer.print("emitByte(" + byteValue + ");");
750 }
751
752 protected void emitByte(IndentWriter writer, byte value) {
753 emitByte(writer, "((byte) " + Bytes.toHexLiteral(value) + ")");
754 }
755
756 protected void generate() {
757 try {
758 final String rawAssemblerClassName = rawAssemblerClassNameOption.getValue();
759 final String labelAssemblerClassName = labelAssemblerClassNameOption.getValue();
760
761 final boolean rawAssemblerMethodsUpdated = generateRawAssemblerMethods(rawAssemblerClassName);
762 final boolean labelAssemblerMethodsUpdated = generateLabelAssemblerMethods(labelAssemblerClassName);
763
764 if (rawAssemblerClassName.equals(labelAssemblerClassName)) {
765 if (rawAssemblerMethodsUpdated || labelAssemblerMethodsUpdated) {
766 System.out.println("modified: " + getSourceFileFor(rawAssemblerClassName));
767 if (!ToolChain.compile(AssemblerGenerator.class, rawAssemblerClassName)) {
768 List<Template_Type> allTemplates = new ArrayList<Template_Type>(templates());
769 allTemplates.addAll(labelTemplates());
770 throw ProgramError.unexpected("compilation failed for: " + rawAssemblerClassName +
771 "[Maybe missing an import statement for one of the following packages: " +
772 getImportPackages(rawAssemblerClassName, allTemplates));
773 }
774 } else {
775 System.out.println("unmodified: " + getSourceFileFor(rawAssemblerClassName));
776 }
777 } else {
778 if (rawAssemblerMethodsUpdated) {
779 System.out.println("modified: " + getSourceFileFor(rawAssemblerClassName));
780 if (!ToolChain.compile(AssemblerGenerator.class, rawAssemblerClassName)) {
781 throw ProgramError.unexpected("compilation failed for: " + rawAssemblerClassName +
782 "[Maybe missing an import statement for one of the following packages: " +
783 getImportPackages(rawAssemblerClassName, templates()));
784 }
785 } else {
786 System.out.println("unmodified: " + getSourceFileFor(rawAssemblerClassName));
787 }
788
789 if (labelAssemblerMethodsUpdated) {
790 System.out.println("modified: " + getSourceFileFor(labelAssemblerClassName));
791 if (!ToolChain.compile(AssemblerGenerator.class, labelAssemblerClassName)) {
792 throw ProgramError.unexpected("compilation failed for: " + labelAssemblerClassName +
793 "[Maybe missing an import statement for one of the following packages: " +
794 getImportPackages(labelAssemblerClassName, labelTemplates()));
795 }
796 } else {
797 System.out.println("unmodified: " + getSourceFileFor(labelAssemblerClassName));
798 }
799
800 }
801
802 Trace.line(1, "done");
803 } catch (Throwable throwable) {
804 throwable.printStackTrace();
805 System.err.println("something went wrong: " + throwable + ": " + throwable.getMessage());
806 }
807 }
808
809 }