001 /* 002 * The JastAdd Extensible Java Compiler (http://jastadd.org) is covered 003 * by the modified BSD License. You should have received a copy of the 004 * modified BSD license with this compiler. 005 * 006 * Copyright (c) 2005-2008, Torbjorn Ekman 007 * All rights reserved. 008 */ 009 010 aspect GenerateClassfile { 011 public void Program.generateClassfile() { 012 for(Iterator iter = compilationUnitIterator(); iter.hasNext(); ) { 013 CompilationUnit cu = (CompilationUnit)iter.next(); 014 cu.generateClassfile(); 015 } 016 } 017 018 public void CompilationUnit.generateClassfile() { 019 if(fromSource()) { 020 for(int i = 0; i < getNumTypeDecl(); i++) { 021 getTypeDecl(i).generateClassfile(); 022 getTypeDecl(i).clear(); 023 } 024 } 025 } 026 027 public void TypeDecl.generateClassfile() { 028 for(Iterator iter = nestedTypes().iterator(); iter.hasNext(); ) { 029 TypeDecl typeDecl = (TypeDecl)iter.next(); 030 typeDecl.generateClassfile(); 031 } 032 } 033 034 syn int TypeDecl.magicHeader() = 0xCAFEBABE; 035 syn int TypeDecl.minorVersion() = 0; 036 syn int TypeDecl.majorVersion() = 48; 037 038 public void ClassDecl.generateClassfile() { 039 super.generateClassfile(); 040 String fileName = destinationPath() + File.separator + constantPoolName() + ".class"; 041 if(options().verbose()) System.out.println("Writing class file to " + fileName); 042 try { 043 ConstantPool cp = constantPool(); 044 045 // force building of constant pool 046 cp.addClass(constantPoolName()); 047 if(hasSuperclass()) { 048 cp.addClass(superclass().constantPoolName()); 049 } 050 int numInterfaces = 0; 051 for(Iterator iter = interfacesIterator(); iter.hasNext(); numInterfaces++) 052 cp.addClass(((TypeDecl)iter.next()).constantPoolName()); 053 for(Iterator iter = bcFields().iterator(); iter.hasNext(); ) { 054 FieldDeclaration field = (FieldDeclaration) iter.next(); 055 cp.addUtf8(field.name()); 056 cp.addUtf8(field.type().typeDescriptor()); 057 field.attributes(); 058 } 059 if(needsEnclosing()) { 060 cp.addUtf8("this$0"); 061 cp.addUtf8(enclosing().typeDescriptor()); 062 cp.addUtf8("Synthetic"); 063 } 064 065 for(Iterator iter = bcMethods().iterator(); iter.hasNext(); ) { 066 BodyDecl decl = (BodyDecl)iter.next(); 067 decl.touchMethod(cp); 068 } 069 if(hasClinit()) { 070 cp.addUtf8("<clinit>"); 071 cp.addUtf8("()V"); 072 clinit_attributes(); 073 } 074 attributes(); 075 076 077 // Actual ClassFile generation 078 File dest = new File(fileName); 079 File parentFile = dest.getParentFile(); 080 if(parentFile != null) 081 parentFile.mkdirs(); 082 FileOutputStream f = new FileOutputStream(fileName); 083 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(f)); 084 out.writeInt(magicHeader()); 085 out.writeChar(minorVersion()); 086 out.writeChar(majorVersion()); 087 cp.emit(out); 088 int flags = flags(); 089 if(isNestedType()) 090 flags = mangledFlags(flags); 091 flags |= Modifiers.ACC_SUPER; 092 out.writeChar(flags); 093 out.writeChar(cp.addClass(constantPoolName())); 094 out.writeChar(hasSuperclass() ? cp.addClass(superclass().constantPoolName()) : 0); 095 out.writeChar(numInterfaces); 096 for(Iterator iter = interfacesIterator(); iter.hasNext(); ) 097 out.writeChar(cp.addClass(((TypeDecl)iter.next()).constantPoolName())); 098 Collection fields = bcFields(); 099 out.writeChar(fields.size() + (needsEnclosing() ? 1 : 0)); 100 for(Iterator iter = fields.iterator(); iter.hasNext(); ) { 101 FieldDeclaration field = (FieldDeclaration) iter.next(); 102 out.writeChar(field.flags()); 103 out.writeChar(cp.addUtf8(field.name())); 104 out.writeChar(cp.addUtf8(field.type().typeDescriptor())); 105 out.writeChar(field.attributes().size()); 106 for(Iterator itera = field.attributes().iterator(); itera.hasNext();) 107 ((Attribute)itera.next()).emit(out); 108 } 109 if(needsEnclosing()) { 110 out.writeChar(0 /*Modifiers.ACC_PRIVATE*/); 111 out.writeChar(cp.addUtf8("this$0")); 112 out.writeChar(cp.addUtf8(enclosing().typeDescriptor())); 113 out.writeChar(1); 114 new SyntheticAttribute(cp).emit(out); 115 116 } 117 118 Collection methods = bcMethods(); 119 out.writeChar(methods.size() + (hasClinit() ? 1 : 0)); 120 for(Iterator iter = methods.iterator(); iter.hasNext(); ) { 121 BodyDecl b = (BodyDecl)iter.next(); 122 b.generateMethod(out, cp); 123 } 124 if(hasClinit()) { 125 out.writeChar(Modifiers.ACC_STATIC); 126 out.writeChar(cp.addUtf8("<clinit>")); 127 out.writeChar(cp.addUtf8("()V")); 128 out.writeChar(clinit_attributes().size()); 129 for(Iterator itera = clinit_attributes().iterator(); itera.hasNext();) 130 ((Attribute)itera.next()).emit(out); 131 } 132 out.writeChar(attributes().size()); 133 for(Iterator itera = attributes().iterator(); itera.hasNext();) 134 ((Attribute)itera.next()).emit(out); 135 136 out.close(); 137 } catch (IOException e) { 138 e.printStackTrace(); 139 } 140 } 141 142 public void InterfaceDecl.generateClassfile() { 143 super.generateClassfile(); 144 String fileName = destinationPath() + File.separator + constantPoolName() + ".class"; 145 if(options().verbose()) System.out.println("Writing class file to " + fileName); 146 try { 147 ConstantPool cp = constantPool(); 148 // force building of constant pool 149 cp.addClass(constantPoolName()); 150 cp.addClass("java/lang/Object"); 151 for(int i = 0; i < getNumSuperInterfaceId(); i++) { 152 cp.addClass(getSuperInterfaceId(i).type().constantPoolName()); 153 } 154 for(Iterator iter = bcFields().iterator(); iter.hasNext(); ) { 155 FieldDeclaration field = (FieldDeclaration) iter.next(); 156 cp.addUtf8(field.name()); 157 cp.addUtf8(field.type().typeDescriptor()); 158 field.attributes(); 159 } 160 for(Iterator iter = bcMethods().iterator(); iter.hasNext(); ) { 161 Object obj = iter.next(); 162 if(obj instanceof MethodDecl) { 163 MethodDecl m = (MethodDecl) obj; 164 cp.addUtf8(m.name()); 165 cp.addUtf8(m.descName()); 166 m.attributes(); 167 } 168 } 169 attributes(); 170 171 if(hasClinit()) { 172 cp.addUtf8("<clinit>"); 173 cp.addUtf8("()V"); 174 clinit_attributes(); 175 } 176 177 // actual classfile generation 178 File dest = new File(fileName); 179 File parentFile = dest.getParentFile(); 180 if(parentFile != null) 181 parentFile.mkdirs(); 182 183 FileOutputStream f = new FileOutputStream(fileName); 184 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(f)); 185 out.writeInt(magicHeader()); 186 out.writeChar(minorVersion()); 187 out.writeChar(majorVersion()); 188 cp.emit(out); 189 int flags = flags(); 190 if(isNestedType()) 191 flags = mangledFlags(flags); 192 if(isInterfaceDecl()) 193 flags |= Modifiers.ACC_INTERFACE; 194 out.writeChar(flags); 195 out.writeChar(cp.addClass(constantPoolName())); 196 out.writeChar(cp.addClass("java/lang/Object")); 197 if(getNumSuperInterfaceId() == 1 && getSuperInterfaceId(0).type().isObject()) 198 out.writeChar(0); 199 else 200 out.writeChar(getNumSuperInterfaceId()); 201 for(int i = 0; i < getNumSuperInterfaceId(); i++) { 202 TypeDecl typeDecl = getSuperInterfaceId(i).type(); 203 if(typeDecl.isInterfaceDecl()) 204 out.writeChar(cp.addClass(typeDecl.constantPoolName())); 205 } 206 Collection fields = bcFields(); 207 out.writeChar(fields.size()); 208 for(Iterator iter = fields.iterator(); iter.hasNext(); ) { 209 FieldDeclaration field = (FieldDeclaration) iter.next(); 210 out.writeChar(field.flags()); 211 out.writeChar(cp.addUtf8(field.name())); 212 out.writeChar(cp.addUtf8(field.type().typeDescriptor())); 213 out.writeChar(field.attributes().size()); 214 for(Iterator itera = field.attributes().iterator(); itera.hasNext();) 215 ((Attribute)itera.next()).emit(out); 216 } 217 Collection methods = bcMethods(); 218 out.writeChar(methods.size() + (hasClinit() ? 1 : 0)); 219 for(Iterator iter = methods.iterator(); iter.hasNext(); ) { 220 BodyDecl b = (BodyDecl)iter.next(); 221 b.generateMethod(out, cp); 222 } 223 if(hasClinit()) { 224 out.writeChar(Modifiers.ACC_STATIC); 225 out.writeChar(cp.addUtf8("<clinit>")); 226 out.writeChar(cp.addUtf8("()V")); 227 out.writeChar(clinit_attributes().size()); 228 for(Iterator itera = clinit_attributes().iterator(); itera.hasNext();) 229 ((Attribute)itera.next()).emit(out); 230 } 231 out.writeChar(attributes().size()); 232 for(Iterator itera = attributes().iterator(); itera.hasNext();) 233 ((Attribute)itera.next()).emit(out); 234 235 out.close(); 236 } catch (IOException e) { 237 e.printStackTrace(); 238 } 239 } 240 241 242 public void BodyDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 243 } 244 public void MethodDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 245 out.writeChar(flags()); 246 out.writeChar(cp.addUtf8(name())); 247 out.writeChar(cp.addUtf8(descName())); 248 out.writeChar(attributes().size()); 249 for(Iterator itera = attributes().iterator(); itera.hasNext();) 250 ((Attribute)itera.next()).emit(out); 251 } 252 public void ConstructorDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 253 out.writeChar(flags()); 254 out.writeChar(cp.addUtf8("<init>")); 255 out.writeChar(cp.addUtf8(descName())); 256 out.writeChar(attributes().size()); 257 for(Iterator itera = attributes().iterator(); itera.hasNext();) 258 ((Attribute)itera.next()).emit(out); 259 } 260 261 public void BodyDecl.touchMethod(ConstantPool cp) { 262 } 263 public void MethodDecl.touchMethod(ConstantPool cp) { 264 cp.addUtf8(name()); 265 cp.addUtf8(descName()); 266 attributes(); 267 } 268 public void ConstructorDecl.touchMethod(ConstantPool cp) { 269 cp.addUtf8("<init>"); 270 cp.addUtf8(descName()); 271 attributes(); 272 } 273 274 275 syn lazy Collection TypeDecl.bcFields() = new ArrayList(); 276 eq ReferenceType.bcFields() { 277 ArrayList l = new ArrayList(); 278 for(int i = 0; i < getNumBodyDecl(); i++) 279 if(getBodyDecl(i).isBytecodeField() && getBodyDecl(i).generate()) 280 l.add(getBodyDecl(i)); 281 return l; 282 } 283 284 syn Collection ReferenceType.bcMethods() { 285 ArrayList l = new ArrayList(); 286 constructors(); 287 for(int i = 0; i < getNumBodyDecl(); i++) 288 if(getBodyDecl(i).isBytecodeMethod() && getBodyDecl(i).generate()) 289 l.add(getBodyDecl(i)); 290 return l; 291 } 292 293 syn boolean BodyDecl.isBytecodeField() = false; 294 eq FieldDeclaration.isBytecodeField() = true; 295 296 syn boolean BodyDecl.isBytecodeMethod() = false; 297 eq MethodDecl.isBytecodeMethod() = true; 298 eq ConstructorDecl.isBytecodeMethod() = true; 299 300 syn boolean BodyDecl.generate() = true; 301 302 // Remove method bodies and cached attributes after the class file has been generated 303 public boolean ASTNode.clear() { 304 boolean empty = true; 305 for(int i = 0; i < getNumChild(); i++) { 306 ASTNode child = getChild(i); 307 if(!child.clear()) 308 empty = false; 309 else { 310 if(child instanceof List) 311 ((ASTNode)this).setChild(new List(), i); 312 else if(child instanceof Opt) 313 ((ASTNode)this).setChild(new Opt(), i); 314 //setChild(null, i); 315 } 316 } 317 if(empty) { 318 setParent(null); 319 } 320 if(flush()) 321 flushCache(); 322 return empty; 323 } 324 325 syn boolean ASTNode.flush() = true; 326 327 eq TypeDecl.flush() = false; 328 eq LocalClassDeclStmt.flush() = true; 329 eq AnonymousDecl.flush() = true; 330 331 eq MethodDecl.flush() = false; 332 eq FieldDeclaration.flush() = false; 333 eq ConstructorDecl.flush() = false; 334 335 public boolean TypeDecl.clear() { 336 bytecodes(constantPool()).clearCodeGeneration(); 337 for(int i = 0; i < getNumBodyDecl(); i++) 338 getBodyDecl(i).clear(); 339 attributes_computed = false; 340 attributes_value = null; 341 clinit_attributes_computed = false; 342 clinit_attributes_value = null; 343 constantPool_computed = false; 344 constantPool_value = null; 345 bytecodes_ConstantPool_values = null; 346 return false; 347 } 348 public boolean LocalClassDeclStmt.clear() { 349 for(int i = 0; i < getNumChild(); i++) 350 getChild(i).clear(); 351 setParent(null); 352 flushCache(); 353 return true; 354 } 355 public boolean AnonymousDecl.clear() { 356 for(int i = 0; i < getNumChild(); i++) 357 getChild(i).clear(); 358 setParent(null); 359 flushCache(); 360 return true; 361 } 362 363 public boolean MethodDecl.clear() { 364 if(hasBlock()) { 365 getBlock().clear(); 366 setBlock(new Block(new List())); 367 } 368 bytecodes_ConstantPool_values = null; 369 return false; 370 } 371 372 public boolean FieldDeclaration.clear() { 373 return false; 374 } 375 376 public boolean ConstructorDecl.clear() { 377 getBlock().clear(); 378 setBlock(new Block(new List())); 379 bytecodes_ConstantPool_values = null; 380 return false; 381 } 382 }