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    }