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    import java.io.*;
032    
033    aspect Attributes {
034    
035      class Attribute {
036        int attribute_name_index;
037        ByteArrayOutputStream buf = new ByteArrayOutputStream();
038        DataOutputStream output = new DataOutputStream(buf);
039    
040        public Attribute(ConstantPool cp, String name) {
041          attribute_name_index = cp.addUtf8(name);
042        }
043    
044        public void emit(DataOutputStream out) throws IOException {
045          out.writeChar(attribute_name_index);
046          out.writeInt(buf.size());
047          buf.writeTo(out);
048          output.close();
049          buf.close();
050        }
051        public int size() { return buf.size(); }
052        public void u1(int v) { try { output.writeByte(v); } catch(IOException e) {} }
053        public void u2(int v) { try { output.writeChar(v); } catch(IOException e) {} }
054        public void u4(int v) { try { output.writeInt(v); } catch(IOException e) {} }
055        public void append(byte[] data) { try { output.write(data, 0, data.length); } catch(IOException e) {} }
056        public void append(Attribute attribute) { try { attribute.emit(output); } catch(IOException e) {} }
057      }
058    
059      class SourceFileAttribute extends Attribute {
060        public SourceFileAttribute(ConstantPool p, String sourcefile) {
061          super(p, "SourceFile");
062          u2(p.addUtf8(sourcefile));
063        }
064      }
065    
066      class SyntheticAttribute extends Attribute {
067        public SyntheticAttribute(ConstantPool p) {
068          super(p, "Synthetic");
069        }
070      }
071    
072      class ConstantValueAttribute extends Attribute {
073        public ConstantValueAttribute(ConstantPool p, FieldDeclaration f) {
074          super(p, "ConstantValue");
075          int constantvalue_index = f.type().addConstant(p, f.getInit().constant());
076          u2(constantvalue_index);
077        }
078      }
079    
080      public int TypeDecl.addConstant(ConstantPool p, Constant c)     {
081        if (isString()) {
082          return p.addConstant(c.stringValue());
083        }
084        throw new Error("Not supported");
085      }
086      public int BooleanType.addConstant(ConstantPool p, Constant c)  { return p.addConstant(c.booleanValue() ? 1 : 0); }
087      public int IntegralType.addConstant(ConstantPool p, Constant c) { return p.addConstant(c.intValue()); }
088      public int LongType.addConstant(ConstantPool p, Constant c)     { return p.addConstant(c.longValue()); }
089      public int FloatType.addConstant(ConstantPool p, Constant c)    { return p.addConstant(c.floatValue()); }
090      public int DoubleType.addConstant(ConstantPool p, Constant c)   { return p.addConstant(c.doubleValue()); }
091    
092      class InnerClassesAttribute extends Attribute {
093        public InnerClassesAttribute(TypeDecl typeDecl) {
094          super(typeDecl.constantPool(), "InnerClasses");
095          ConstantPool c = typeDecl.constantPool();
096          Collection list = typeDecl.innerClassesAttributeEntries();
097          u2(list.size());
098          for (Iterator iter = list.iterator(); iter.hasNext(); ) {
099            TypeDecl type = (TypeDecl) iter.next();
100            u2(c.addClass(type.constantPoolName())); // inner_class_info_index
101            u2(type.isMemberType() ? c.addClass(type.enclosingType().constantPoolName()) : 0); // outer_class_info_index
102            u2(type.isAnonymous() ? 0 : c.addUtf8(type.name())); // inner_name_index
103            u2(type.isInterfaceDecl() ? (type.flags() | Modifiers.ACC_INTERFACE) : type.flags()); // inner_class_access_flags
104          }
105        }
106      }
107      syn lazy Collection TypeDecl.innerClassesAttributeEntries() {
108        HashSet list = new HashSet();
109        if (isNestedType()) {
110          list.add(this);
111        }
112        for (Iterator iter = nestedTypes.iterator(); iter.hasNext(); ) {
113          list.add(iter.next());
114        }
115        for (Iterator iter = usedNestedTypes.iterator(); iter.hasNext(); ) {
116          list.add(iter.next());
117        }
118        return list;
119      }
120    
121      class LocalVariableTableAttribute extends Attribute {
122        public LocalVariableTableAttribute(CodeGeneration gen) {
123          super(gen.constantPool(), "LocalVariableTable");
124          u2(gen.localVariableTable.size());
125          for (Iterator iter = gen.localVariableTable.iterator(); iter.hasNext(); ) {
126            CodeGeneration.LocalVariableEntry e = (CodeGeneration.LocalVariableEntry)iter.next();
127            u2(e.start_pc);
128            u2(e.length);
129            u2(e.name_index);
130            u2(e.descriptor_index);
131            u2(e.index);
132          }
133        }
134      }
135    
136      class LineNumberTableAttribute extends Attribute {
137        public LineNumberTableAttribute(CodeGeneration gen) {
138          super(gen.constantPool(), "LineNumberTable");
139          u2(gen.lineNumberTable.size());
140          for (Iterator iter = gen.lineNumberTable.iterator(); iter.hasNext(); ) {
141            CodeGeneration.LineNumberEntry e = (CodeGeneration.LineNumberEntry)iter.next();
142            u2(e.start_pc);
143            u2(e.line_number);
144          }
145        }
146      }
147    
148      class CodeAttribute extends Attribute {
149        public CodeAttribute(CodeGeneration codeGen, MethodDecl m) {
150          super(codeGen.constantPool(), "Code");
151          u2(codeGen.maxStackDepth());
152          u2(codeGen.maxLocals());
153          u4(codeGen.pos()); // code_length
154          append(codeGen.toArray());
155          u2(codeGen.exceptions.size());
156          for (Iterator iter = codeGen.exceptions.iterator(); iter.hasNext(); ) {
157            CodeGeneration.ExceptionEntry e = (CodeGeneration.ExceptionEntry)iter.next();
158            u2(e.start_pc);
159            u2(e.end_pc);
160            u2(e.handlerPC());
161            u2(e.catch_type);
162          }
163    
164          if (m == null || !m.getModifiers().isSynthetic()) {
165            u2(2); // Attribute count
166            append(new LineNumberTableAttribute(codeGen));
167            append(new LocalVariableTableAttribute(codeGen));
168          } else {
169            u2(0); // Attribute count
170          }
171        }
172      }
173    
174      interface ExceptionHolder {
175        public int getNumException();
176        public Access getException(int i);
177      }
178      MethodDecl implements ExceptionHolder;
179      ConstructorDecl implements ExceptionHolder;
180    
181      class ExceptionsAttribute extends Attribute {
182        public ExceptionsAttribute(CodeGeneration gen, ExceptionHolder m) {
183          super(gen.constantPool(), "Exceptions");
184          u2(m.getNumException());
185          for (int i = 0; i < m.getNumException(); i++) {
186            u2(gen.constantPool().addClass(m.getException(i).type().constantPoolName()));
187          }
188        }
189      }
190    
191      syn lazy Collection TypeDecl.attributes() {
192        Collection c = new ArrayList();
193        if (!innerClassesAttributeEntries().isEmpty()) {
194          c.add(new InnerClassesAttribute(this));
195        }
196        if (isSynthetic()) {
197          c.add(new SyntheticAttribute(constantPool()));
198        }
199        if (compilationUnit().fromSource()) {
200          String relativeName = compilationUnit().relativeName();
201          if (relativeName != null) {
202            String splitToken = java.io.File.separator;
203            if (splitToken.equals("\\")) {
204              splitToken = "\\\\";
205            }
206            String[] strings = relativeName.split(splitToken);
207            c.add(new SourceFileAttribute(constantPool(), strings[strings.length-1]));
208          }
209        }
210        return c;
211      }
212      syn lazy Collection BodyDecl.attributes() = new ArrayList();
213      eq FieldDeclaration.attributes() {
214        ArrayList l = new ArrayList();
215        if (isFinal() && isConstant() && (type().isPrimitive() || type().isString())) {
216          l.add(new ConstantValueAttribute(hostType().constantPool(), this));
217        }
218        return l;
219      }
220    
221      eq MethodDecl.attributes() {
222        ArrayList l = new ArrayList();
223        CodeGeneration bytecodes = bytecodes(hostType().constantPool());
224        l.add(new ExceptionsAttribute(bytecodes, this));
225        if (isAbstract() || isNative()) {
226          return l;
227        } else {
228          l.add(new CodeAttribute(bytecodes, this));
229          if (getModifiers().isSynthetic()) {
230            l.add(new SyntheticAttribute(hostType().constantPool()));
231          }
232          return l;
233        }
234      }
235    
236      eq ConstructorDecl.attributes() {
237        ArrayList l = new ArrayList();
238        CodeGeneration bytecodes = bytecodes(hostType().constantPool());
239        l.add(new CodeAttribute(bytecodes, null));
240        l.add(new ExceptionsAttribute(bytecodes, this));
241        if (getModifiers().isSynthetic()) {
242          l.add(new SyntheticAttribute(hostType().constantPool()));
243        }
244        return l;
245      }
246    
247      syn lazy Collection TypeDecl.clinit_attributes() {
248        ArrayList l = new ArrayList();
249        l.add(new CodeAttribute(bytecodes(constantPool()), null));
250        return l;
251      }
252    }