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    }