import java.io.*; aspect Attributes { class Attribute { public boolean isEmpty() { return false; } public void emit(DataOutputStream out) throws IOException { throw new Error("Emit not implemented for " + getClass().getName()); } public int size() { throw new Error("size not supported for attribute " + getClass().getName()); } } class SourceFileAttribute extends Attribute { int attribute_name_index; int attribute_length; int sourcefile_index; String sourcefile; public SourceFileAttribute(ConstantPool p, String sourcefile) { attribute_name_index = p.addUtf8("SourceFile"); attribute_length = 2; sourcefile_index = p.addUtf8(sourcefile); this.sourcefile = sourcefile; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(sourcefile_index); } public String toString() { return "SourceFile: " + sourcefile; } public String toString(ConstantPool c) { return toString(); } } class SyntheticAttribute extends Attribute { int attribute_name_index; int attribute_length; public SyntheticAttribute(ConstantPool p) { attribute_name_index = p.addUtf8("Synthetic"); attribute_length = 0; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); } public String toString() { return "Synthetic"; } public String toString(ConstantPool c) { return toString(); } public int size() { return 4; } } class ConstantValueAttribute extends Attribute { int attribute_name_index; int attribute_length; int constantvalue_index; public ConstantValueAttribute(ConstantPool p, FieldDeclaration f) { attribute_name_index = p.addUtf8("ConstantValue"); attribute_length = 2; constantvalue_index = f.constantIndex(p); } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(constantvalue_index); } public String toString() { return "ConstantValue"; } public String toString(ConstantPool c) { StringBuffer s = new StringBuffer(); s.append("attribute_name_index: " + c.addUtf8("ConstantValue")); s.append(", attribute_length " + attribute_length); s.append(", constantvalue_index " + constantvalue_index); return s.toString(); } } class InnerClassesAttribute extends Attribute { public static class Classes { int inner_class_info_index; int outer_class_info_index; int inner_name_index; int inner_class_access_flags; } int attribute_name_index; int attribute_length; Classes[] classes; public InnerClassesAttribute(TypeDecl typeDecl) { ConstantPool c = typeDecl.constantPool(); ArrayList list = new ArrayList(); typeDecl.collectInnerClasses(list, c, typeDecl); classes = new Classes[list.size()]; for(int i = 0; i < list.size(); i++) classes[i] = (Classes)list.get(i); if(classes.length != 0) attribute_name_index = c.addUtf8("InnerClasses"); attribute_length = 2 + classes.length * 8; } public boolean isEmpty() { return classes.length == 0; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(classes.length); for(int i = 0; i < classes.length; i++) { out.writeChar(classes[i].inner_class_info_index); out.writeChar(classes[i].outer_class_info_index); out.writeChar(classes[i].inner_name_index); out.writeChar(classes[i].inner_class_access_flags); } } public String toString() { return "InnerClasses"; } public String toString(ConstantPool c) { StringBuffer s = new StringBuffer(); s.append("attribute_name_index: " + c.addUtf8("InnerClasses")); s.append(", attribute_length " + attribute_length); for(int i = 0; i < classes.length; i++) { s.append(" inner_class_info_index: " + classes[i].inner_class_info_index + "\n"); s.append(" outer_class_info_index: " + classes[i].outer_class_info_index + "\n"); s.append(" inner_name_index: " + classes[i].inner_name_index + "\n"); s.append(" inner_class_access_flags: " + Integer.toHexString(classes[i].inner_class_access_flags) + "\n"); } return s.toString(); } } class LocalVariableTableAttribute extends Attribute { int attribute_name_index; int attribute_length; int local_variable_table_length; Collection local_variable_table; public LocalVariableTableAttribute(CodeGeneration gen) { ConstantPool p = gen.constantPool(); attribute_name_index = p.addUtf8("LocalVariableTable"); local_variable_table = gen.localVariableTable; local_variable_table_length = local_variable_table.size(); attribute_length = local_variable_table_length * 10 + 2; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(local_variable_table_length); for(Iterator iter = local_variable_table.iterator(); iter.hasNext(); ) { CodeGeneration.LocalVariableEntry e = (CodeGeneration.LocalVariableEntry)iter.next(); out.writeChar(e.start_pc); out.writeChar(e.length); out.writeChar(e.name_index); out.writeChar(e.descriptor_index); out.writeChar(e.index); } } public String toString() { return "LocalVariableTable"; } public String toString(ConstantPool c) { return toString(); } public int size() { return attribute_length + 6; } } class LineNumberTableAttribute extends Attribute { int attribute_name_index; int attribute_length; int line_number_table_length; Collection line_number_table; public LineNumberTableAttribute(CodeGeneration gen) { ConstantPool p = gen.constantPool(); attribute_name_index = p.addUtf8("LineNumberTable"); line_number_table = gen.lineNumberTable; line_number_table_length = line_number_table.size(); attribute_length = line_number_table_length * 4 + 2; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(line_number_table_length); for(Iterator iter = line_number_table.iterator(); iter.hasNext(); ) { CodeGeneration.LineNumberEntry e = (CodeGeneration.LineNumberEntry)iter.next(); out.writeChar(e.start_pc); out.writeChar(e.line_number); } } public String toString() { return "LineNumberTable"; } public String toString(ConstantPool c) { return toString(); } public int size() { return attribute_length + 6; } } class CodeAttribute extends Attribute { int attribute_name_index; int attribute_length; int max_stack; int max_locals; int code_length; byte[] code; int exception_table_length = 0; Collection exceptions; int attributes_size = 0; Collection attributes; public CodeAttribute(CodeGeneration codeGen, MethodDecl m) { ConstantPool c = codeGen.constantPool(); attribute_name_index = c.addUtf8("Code"); max_stack = codeGen.maxStackDepth(); if(codeGen.stackDepth() != 0) { //throw new Error("Stack depth grows in method " + m.signature() + " in class " + m.hostType().fullName() + " ... size: " + codeGen.stackDepth()); if(m != null) System.err.println(m.errorPrefix() + "Stack depth grows in method " + m.signature() + " in class " + m.hostType().fullName() + " ... size: " + codeGen.stackDepth()); else System.err.println("Stack depth grows in constructor"); } max_locals = codeGen.maxLocals(); code_length = codeGen.pos(); code = codeGen.toArray(); exceptions = codeGen.exceptions; exception_table_length = exceptions.size(); attributes = new ArrayList(); if(m == null || !m.getModifiers().isSynthetic()) { attributes.add(new LineNumberTableAttribute(codeGen)); attributes.add(new LocalVariableTableAttribute(codeGen)); } attributes_size = 0; for(Iterator iter = attributes.iterator(); iter.hasNext(); ) attributes_size += ((Attribute)iter.next()).size(); attribute_length = 12 + code_length + exception_table_length * 8 + attributes_size; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(max_stack); out.writeChar(max_locals); out.writeInt(code_length); out.write(code, 0, code_length); out.writeChar(exception_table_length); // Exception tablelength for(Iterator iter = exceptions.iterator(); iter.hasNext(); ) { CodeGeneration.ExceptionEntry e = (CodeGeneration.ExceptionEntry)iter.next(); out.writeChar(e.start_pc); out.writeChar(e.end_pc); out.writeChar(e.handler_pc); out.writeChar(e.catch_type); } out.writeChar(attributes.size()); // Attribute count for(Iterator iter = attributes.iterator(); iter.hasNext(); ) ((Attribute)iter.next()).emit(out); } public String toString() { return "Code"; } public String toString(ConstantPool c) { StringBuffer s = new StringBuffer(); s.append("attribute_name_index: " + c.addUtf8("Code")); s.append(", attribute_length " + attribute_length); s.append(", max_stack " + max_stack); s.append(", max_locals " + max_locals); s.append(", code_length " + code_length); s.append("\n"); Bytecode.appendBytecodes(s, code); s.append("exception_table_length " + exceptions.size()); for(Iterator iter = exceptions.iterator(); iter.hasNext(); ) { CodeGeneration.ExceptionEntry e = (CodeGeneration.ExceptionEntry)iter.next(); s.append("\nstart_pc " + e.start_pc); s.append(", end_pc " + e.start_pc); s.append(", handler_ps " + e.start_pc); s.append(", catch_type " + e.start_pc); } return s.toString(); } } interface ExceptionHolder { public int getNumException(); public Access getException(int i); } MethodDecl implements ExceptionHolder; ConstructorDecl implements ExceptionHolder; class ExceptionsAttribute extends Attribute { int attribute_name_index; int attribute_length; int number_of_exceptions; int[] exception_index_table; public ExceptionsAttribute(CodeGeneration gen, ExceptionHolder m) { ConstantPool c = gen.constantPool(); attribute_name_index = c.addUtf8("Exceptions"); number_of_exceptions = m.getNumException(); exception_index_table = new int[number_of_exceptions]; for(int i = 0; i< m.getNumException(); i++) { int pos = c.addClass(m.getException(i).type().constantPoolName()); exception_index_table[i] = pos; } attribute_length = 2 + number_of_exceptions * 2; } public void emit(DataOutputStream out) throws IOException { out.writeChar(attribute_name_index); out.writeInt(attribute_length); out.writeChar(number_of_exceptions); for(int i = 0; i < number_of_exceptions; i++) out.writeChar(exception_index_table[i]); } public String toString(ConstantPool c) { StringBuffer s = new StringBuffer(); s.append("attribute_name_index: " + c.addUtf8("Exceptions")); s.append(", attribute_length " + attribute_length); s.append(", number_of_exceptions " + number_of_exceptions + ": "); for(int i = 0; i < number_of_exceptions; i++) s.append(exception_index_table[i]); return s.toString(); } } inh CompilationUnit TypeDecl.compilationUnit(); eq CompilationUnit.getTypeDecl(int i).compilationUnit() = this; syn lazy Collection TypeDecl.attributes() { Collection c = new ArrayList(); Attribute a = new InnerClassesAttribute(this); if(!a.isEmpty()) c.add(a); if(isSynthetic()) c.add(new SyntheticAttribute(constantPool())); if(compilationUnit().fromSource()) { String relativeName = compilationUnit().relativeName(); if(relativeName != null) { String[] strings = relativeName.split(java.io.File.separator); c.add(new SourceFileAttribute(constantPool(), strings[strings.length-1])); } } return c; } syn lazy Collection BodyDecl.attributes() = new ArrayList(); eq FieldDeclaration.attributes() { ArrayList l = new ArrayList(); if(isStatic() && isFinal() && isConstant() && (type().isPrimitive() || type().isString())) l.add(new ConstantValueAttribute(hostType().constantPool(), this)); return l; } eq MethodDecl.attributes() { ArrayList l = new ArrayList(); if(isAbstract() || isNative()) return l; l.add(new CodeAttribute(bytecodes(hostType().constantPool()), this)); l.add(new ExceptionsAttribute(bytecodes(hostType().constantPool()), this)); if(getModifiers().isSynthetic()) l.add(new SyntheticAttribute(hostType().constantPool())); return l; } eq ConstructorDecl.attributes() { ArrayList l = new ArrayList(); l.add(new CodeAttribute(bytecodes(hostType().constantPool()), null)); l.add(new ExceptionsAttribute(bytecodes(hostType().constantPool()), this)); if(getModifiers().isSynthetic()) l.add(new SyntheticAttribute(hostType().constantPool())); return l; } syn lazy Collection TypeDecl.clinit_attributes() { ArrayList l = new ArrayList(); l.add(new CodeAttribute(bytecodes(constantPool()), null)); return l; } }