001 /* Copyright (c) 2005-2008, Torbjorn Ekman 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * 1. Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * 010 * 2. Redistributions in binary form must reproduce the above copyright notice, 011 * this list of conditions and the following disclaimer in the documentation 012 * and/or other materials provided with the distribution. 013 * 014 * 3. Neither the name of the copyright holder nor the names of its 015 * contributors may be used to endorse or promote products derived from this 016 * software without specific prior written permission. 017 * 018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 028 * POSSIBILITY OF SUCH DAMAGE. 029 */ 030 031 aspect GenerateClassfile { 032 public void Program.generateClassfile() { 033 for (Iterator iter = compilationUnitIterator(); iter.hasNext(); ) { 034 CompilationUnit cu = (CompilationUnit) iter.next(); 035 cu.generateClassfile(); 036 } 037 } 038 039 public void CompilationUnit.generateClassfile() { 040 if (fromSource()) { 041 for (int i = 0; i < getNumTypeDecl(); i++) { 042 getTypeDecl(i).generateClassfile(); 043 getTypeDecl(i).clear(); 044 } 045 } 046 } 047 048 public void TypeDecl.generateClassfile() { 049 for (Iterator iter = nestedTypes.iterator(); iter.hasNext(); ) { 050 TypeDecl typeDecl = (TypeDecl) iter.next(); 051 typeDecl.generateClassfile(); 052 } 053 } 054 055 syn int TypeDecl.magicHeader() = 0xCAFEBABE; 056 syn int TypeDecl.minorVersion() = 0; 057 syn int TypeDecl.majorVersion() = 48; 058 059 public void ClassDecl.generateClassfile() { 060 super.generateClassfile(); 061 String fileName = destinationPath(); 062 if (program().options().verbose()) { 063 System.out.println("Writing class file to " + fileName); 064 } 065 try { 066 ConstantPool cp = constantPool(); 067 068 // force building of constant pool 069 cp.addClass(constantPoolName()); 070 if (hasSuperclass()) { 071 cp.addClass(superclass().constantPoolName()); 072 } 073 int numInterfaces = 0; 074 for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); numInterfaces++) { 075 cp.addClass(iter.next().constantPoolName()); 076 } 077 for (Iterator iter = bcFields().iterator(); iter.hasNext(); ) { 078 FieldDeclaration field = (FieldDeclaration) iter.next(); 079 cp.addUtf8(field.name()); 080 cp.addUtf8(field.type().typeDescriptor()); 081 field.attributes(); 082 } 083 if (needsEnclosing()) { 084 cp.addUtf8("this$0"); 085 cp.addUtf8(enclosing().typeDescriptor()); 086 cp.addUtf8("Synthetic"); 087 } 088 089 for (Iterator iter = bcMethods().iterator(); iter.hasNext(); ) { 090 BodyDecl decl = (BodyDecl) iter.next(); 091 decl.touchMethod(cp); 092 } 093 if (hasClinit()) { 094 cp.addUtf8("<clinit>"); 095 cp.addUtf8("()V"); 096 clinit_attributes(); 097 } 098 attributes(); 099 100 // Actual ClassFile generation 101 File dest = new File(fileName); 102 File parentFile = dest.getParentFile(); 103 if (parentFile != null) { 104 parentFile.mkdirs(); 105 } 106 FileOutputStream f = new FileOutputStream(fileName); 107 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(f)); 108 out.writeInt(magicHeader()); 109 out.writeChar(minorVersion()); 110 out.writeChar(majorVersion()); 111 cp.emit(out); 112 int flags = flags(); 113 if (isNestedType()) { 114 flags = mangledFlags(flags); 115 } 116 flags |= Modifiers.ACC_SUPER; 117 out.writeChar(flags); 118 out.writeChar(cp.addClass(constantPoolName())); 119 out.writeChar(hasSuperclass() ? cp.addClass(superclass().constantPoolName()) : 0); 120 out.writeChar(numInterfaces); 121 for (Iterator<TypeDecl> iter = interfacesIterator(); iter.hasNext(); ) { 122 out.writeChar(cp.addClass(iter.next().constantPoolName())); 123 } 124 Collection fields = bcFields(); 125 out.writeChar(fields.size() + (needsEnclosing() ? 1 : 0)); 126 for (Iterator iter = fields.iterator(); iter.hasNext(); ) { 127 FieldDeclaration field = (FieldDeclaration) iter.next(); 128 out.writeChar(field.flags()); 129 out.writeChar(cp.addUtf8(field.name())); 130 out.writeChar(cp.addUtf8(field.type().typeDescriptor())); 131 out.writeChar(field.attributes().size()); 132 for (Iterator itera = field.attributes().iterator(); itera.hasNext();) { 133 ((Attribute) itera.next()).emit(out); 134 } 135 } 136 if (needsEnclosing()) { 137 out.writeChar(0 /*Modifiers.ACC_PRIVATE*/); 138 out.writeChar(cp.addUtf8("this$0")); 139 out.writeChar(cp.addUtf8(enclosing().typeDescriptor())); 140 out.writeChar(1); 141 new SyntheticAttribute(cp).emit(out); 142 143 } 144 145 Collection methods = bcMethods(); 146 out.writeChar(methods.size() + (hasClinit() ? 1 : 0)); 147 for (Iterator iter = methods.iterator(); iter.hasNext(); ) { 148 BodyDecl b = (BodyDecl) iter.next(); 149 b.generateMethod(out, cp); 150 } 151 if (hasClinit()) { 152 out.writeChar(Modifiers.ACC_STATIC); 153 out.writeChar(cp.addUtf8("<clinit>")); 154 out.writeChar(cp.addUtf8("()V")); 155 out.writeChar(clinit_attributes().size()); 156 for (Iterator itera = clinit_attributes().iterator(); itera.hasNext();) { 157 ((Attribute) itera.next()).emit(out); 158 } 159 } 160 out.writeChar(attributes().size()); 161 for (Iterator itera = attributes().iterator(); itera.hasNext();) { 162 ((Attribute) itera.next()).emit(out); 163 } 164 165 out.close(); 166 } catch (IOException e) { 167 e.printStackTrace(); 168 } 169 } 170 171 public void InterfaceDecl.generateClassfile() { 172 super.generateClassfile(); 173 String fileName = destinationPath(); 174 if (program().options().verbose()) { 175 System.out.println("Writing class file to " + fileName); 176 } 177 try { 178 ConstantPool cp = constantPool(); 179 // force building of constant pool 180 cp.addClass(constantPoolName()); 181 cp.addClass("java/lang/Object"); 182 for (int i = 0; i < getNumSuperInterface(); i++) { 183 cp.addClass(getSuperInterface(i).type().constantPoolName()); 184 } 185 for (Iterator iter = bcFields().iterator(); iter.hasNext(); ) { 186 FieldDeclaration field = (FieldDeclaration) iter.next(); 187 cp.addUtf8(field.name()); 188 cp.addUtf8(field.type().typeDescriptor()); 189 field.attributes(); 190 } 191 for (Iterator iter = bcMethods().iterator(); iter.hasNext(); ) { 192 Object obj = iter.next(); 193 if (obj instanceof MethodDecl) { 194 MethodDecl m = (MethodDecl) obj; 195 cp.addUtf8(m.name()); 196 cp.addUtf8(m.descName()); 197 m.attributes(); 198 } 199 } 200 attributes(); 201 202 if (hasClinit()) { 203 cp.addUtf8("<clinit>"); 204 cp.addUtf8("()V"); 205 clinit_attributes(); 206 } 207 208 // actual classfile generation 209 File dest = new File(fileName); 210 File parentFile = dest.getParentFile(); 211 if (parentFile != null) { 212 parentFile.mkdirs(); 213 } 214 215 FileOutputStream f = new FileOutputStream(fileName); 216 DataOutputStream out = new DataOutputStream(new BufferedOutputStream(f)); 217 out.writeInt(magicHeader()); 218 out.writeChar(minorVersion()); 219 out.writeChar(majorVersion()); 220 cp.emit(out); 221 int flags = flags(); 222 if (isNestedType()) { 223 flags = mangledFlags(flags); 224 } 225 if (isInterfaceDecl()) { 226 flags |= Modifiers.ACC_INTERFACE; 227 } 228 out.writeChar(flags); 229 out.writeChar(cp.addClass(constantPoolName())); 230 out.writeChar(cp.addClass("java/lang/Object")); 231 if (getNumSuperInterface() == 1 && getSuperInterface(0).type().isObject()) { 232 out.writeChar(0); 233 } else { 234 out.writeChar(getNumSuperInterface()); 235 } 236 for (int i = 0; i < getNumSuperInterface(); i++) { 237 TypeDecl typeDecl = getSuperInterface(i).type(); 238 if (typeDecl.isInterfaceDecl()) { 239 out.writeChar(cp.addClass(typeDecl.constantPoolName())); 240 } 241 } 242 Collection fields = bcFields(); 243 out.writeChar(fields.size()); 244 for (Iterator iter = fields.iterator(); iter.hasNext(); ) { 245 FieldDeclaration field = (FieldDeclaration) iter.next(); 246 out.writeChar(field.flags()); 247 out.writeChar(cp.addUtf8(field.name())); 248 out.writeChar(cp.addUtf8(field.type().typeDescriptor())); 249 out.writeChar(field.attributes().size()); 250 for (Iterator itera = field.attributes().iterator(); itera.hasNext();) { 251 ((Attribute) itera.next()).emit(out); 252 } 253 } 254 Collection methods = bcMethods(); 255 out.writeChar(methods.size() + (hasClinit() ? 1 : 0)); 256 for (Iterator iter = methods.iterator(); iter.hasNext(); ) { 257 BodyDecl b = (BodyDecl) iter.next(); 258 b.generateMethod(out, cp); 259 } 260 if (hasClinit()) { 261 out.writeChar(Modifiers.ACC_STATIC); 262 out.writeChar(cp.addUtf8("<clinit>")); 263 out.writeChar(cp.addUtf8("()V")); 264 out.writeChar(clinit_attributes().size()); 265 for (Iterator itera = clinit_attributes().iterator(); itera.hasNext();) { 266 ((Attribute) itera.next()).emit(out); 267 } 268 } 269 out.writeChar(attributes().size()); 270 for (Iterator itera = attributes().iterator(); itera.hasNext();) { 271 ((Attribute) itera.next()).emit(out); 272 } 273 274 out.close(); 275 } catch (IOException e) { 276 e.printStackTrace(); 277 } 278 } 279 280 281 public void BodyDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 282 } 283 public void MethodDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 284 out.writeChar(flags()); 285 out.writeChar(cp.addUtf8(name())); 286 out.writeChar(cp.addUtf8(descName())); 287 out.writeChar(attributes().size()); 288 for (Iterator itera = attributes().iterator(); itera.hasNext();) { 289 ((Attribute) itera.next()).emit(out); 290 } 291 } 292 public void ConstructorDecl.generateMethod(DataOutputStream out, ConstantPool cp) throws IOException { 293 out.writeChar(flags()); 294 out.writeChar(cp.addUtf8("<init>")); 295 out.writeChar(cp.addUtf8(descName())); 296 out.writeChar(attributes().size()); 297 for (Iterator itera = attributes().iterator(); itera.hasNext();) { 298 ((Attribute) itera.next()).emit(out); 299 } 300 } 301 302 public void BodyDecl.touchMethod(ConstantPool cp) { 303 } 304 305 public void MethodDecl.touchMethod(ConstantPool cp) { 306 cp.addUtf8(name()); 307 cp.addUtf8(descName()); 308 attributes(); 309 } 310 311 public void ConstructorDecl.touchMethod(ConstantPool cp) { 312 cp.addUtf8("<init>"); 313 cp.addUtf8(descName()); 314 attributes(); 315 } 316 317 syn lazy Collection TypeDecl.bcFields() = new ArrayList(); 318 eq ReferenceType.bcFields() { 319 ArrayList l = new ArrayList(); 320 for (int i = 0; i < getNumBodyDecl(); i++) { 321 if (getBodyDecl(i).isBytecodeField()) { 322 l.add(getBodyDecl(i)); 323 } 324 } 325 return l; 326 } 327 328 syn Collection ReferenceType.bcMethods() { 329 ArrayList l = new ArrayList(); 330 for (int i = 0; i < getNumBodyDecl(); i++) { 331 if (getBodyDecl(i).isBytecodeMethod()) { 332 l.add(getBodyDecl(i)); 333 } 334 } 335 return l; 336 } 337 338 eq ClassDecl.bcMethods() { 339 Collection c = new ArrayList(); 340 if (hasImplicitConstructor()) { 341 c.add(getImplicitConstructor()); 342 } 343 c.addAll(super.bcMethods()); 344 return c; 345 } 346 347 syn boolean BodyDecl.isBytecodeField() = false; 348 eq FieldDeclaration.isBytecodeField() = true; 349 350 syn boolean BodyDecl.isBytecodeMethod() = false; 351 eq MethodDecl.isBytecodeMethod() = true; 352 eq ConstructorDecl.isBytecodeMethod() = true; 353 354 // Remove method bodies and cached attributes after the class file has been generated 355 public boolean ASTNode.clear() { 356 boolean empty = true; 357 for (int i = 0; i < getNumChild(); i++) { 358 ASTNode child = getChild(i); 359 if (!child.clear()) { 360 empty = false; 361 } else { 362 if (child instanceof List) { 363 ((ASTNode) this).setChild(new List(), i); 364 } else if (child instanceof Opt) { 365 ((ASTNode) this).setChild(new Opt(), i); 366 } 367 //setChild(null, i); 368 } 369 } 370 if (empty) { 371 setParent(null); 372 } 373 if (flush()) { 374 flushCache(); 375 } 376 return empty; 377 } 378 379 syn boolean ASTNode.flush() = true; 380 381 eq TypeDecl.flush() = false; 382 eq LocalClassDeclStmt.flush() = true; 383 eq AnonymousDecl.flush() = true; 384 385 eq MethodDecl.flush() = false; 386 eq FieldDeclaration.flush() = false; 387 eq ConstructorDecl.flush() = false; 388 389 public boolean TypeDecl.clear() { 390 bytecodes(constantPool()).clearCodeGeneration(); 391 for (int i = 0; i < getNumBodyDecl(); i++) { 392 getBodyDecl(i).clear(); 393 } 394 attributes_computed = false; 395 attributes_value = null; 396 clinit_attributes_computed = false; 397 clinit_attributes_value = null; 398 constantPool_computed = false; 399 constantPool_value = null; 400 bytecodes_ConstantPool_values = null; 401 return false; 402 } 403 public boolean LocalClassDeclStmt.clear() { 404 for (int i = 0; i < getNumChild(); i++) { 405 getChild(i).clear(); 406 } 407 setParent(null); 408 flushCache(); 409 return true; 410 } 411 public boolean AnonymousDecl.clear() { 412 for (int i = 0; i < getNumChild(); i++) { 413 getChild(i).clear(); 414 } 415 setParent(null); 416 flushCache(); 417 return true; 418 } 419 420 public boolean MethodDecl.clear() { 421 if (hasBlock()) { 422 getBlock().clear(); 423 setBlock(new Block(new List())); 424 } 425 bytecodes_ConstantPool_values = null; 426 return false; 427 } 428 429 public boolean FieldDeclaration.clear() { 430 return false; 431 } 432 433 public boolean ConstructorDecl.clear() { 434 getBlock().clear(); 435 setBlock(new Block(new List())); 436 bytecodes_ConstantPool_values = null; 437 return false; 438 } 439 }