001    /*
002     * Copyright 2007-2008 Sun Microsystems, Inc.  All Rights Reserved.
003     * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004     *
005     * This code is free software; you can redistribute it and/or modify it
006     * under the terms of the GNU General Public License version 2 only, as
007     * published by the Free Software Foundation.  Sun designates this
008     * particular file as subject to the "Classpath" exception as provided
009     * by Sun in the LICENSE file that accompanied this code.
010     *
011     * This code is distributed in the hope that it will be useful, but WITHOUT
012     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013     * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014     * version 2 for more details (a copy is included in the LICENSE file that
015     * accompanied this code).
016     *
017     * You should have received a copy of the GNU General Public License version
018     * 2 along with this work; if not, write to the Free Software Foundation,
019     * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020     *
021     * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022     * CA 95054 USA or visit www.sun.com if you need additional information or
023     * have any questions.
024     */
025    
026    package com.sun.tools.javap;
027    
028    import com.sun.tools.classfile.AccessFlags;
029    import com.sun.tools.classfile.Code_attribute;
030    import com.sun.tools.classfile.ConstantPool;
031    import com.sun.tools.classfile.ConstantPoolException;
032    import com.sun.tools.classfile.DescriptorException;
033    import com.sun.tools.classfile.Method;
034    
035    import static com.sun.tools.classfile.OpCodes.*;
036    
037    /*
038     *  Write the contents of a Code attribute.
039     *
040     *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
041     *  you write code that depends on this, you do so at your own risk.
042     *  This code and its internal interfaces are subject to change or
043     *  deletion without notice.</b>
044     */
045    class CodeWriter extends BasicWriter {
046        static CodeWriter instance(Context context) {
047            CodeWriter instance = context.get(CodeWriter.class);
048            if (instance == null)
049                instance = new CodeWriter(context);
050            return instance;
051        }
052    
053        protected CodeWriter(Context context) {
054            super(context);
055            context.put(CodeWriter.class, this);
056            attrWriter = AttributeWriter.instance(context);
057            classWriter = ClassWriter.instance(context);
058            constantWriter = ConstantWriter.instance(context);
059        }
060    
061        void write(Code_attribute attr, ConstantPool constant_pool) {
062            println("  Code:");
063            writeVerboseHeader(attr, constant_pool);
064            writeInstrs(attr);
065            writeExceptionTable(attr);
066            attrWriter.write(attr, attr.attributes, constant_pool);
067        }
068    
069        public void writeVerboseHeader(Code_attribute attr, ConstantPool constant_pool) {
070            Method method = classWriter.getMethod();
071            String argCount;
072            try {
073                int n = method.descriptor.getParameterCount(constant_pool);
074                if (!method.access_flags.is(AccessFlags.ACC_STATIC))
075                    ++n;  // for 'this'
076                argCount = Integer.toString(n);
077            } catch (ConstantPoolException e) {
078                argCount = report(e);
079            } catch (DescriptorException e) {
080                argCount = report(e);
081            }
082    
083            println("   Stack=" + attr.max_stack +
084                    ", Locals=" + attr.max_locals +
085                    ", Args_size=" + argCount);
086    
087        }
088    
089        public void writeInstrs(Code_attribute attr) {
090            try {
091                for (int pc = 0; pc < attr.code_length;) {
092                    print("   " + pc + ":\t");
093                    pc += writeInstr(attr, pc);
094                    println();
095                }
096            } catch (Code_attribute.InvalidIndex e) {
097                println(report(e));
098            }
099        }
100    
101        public int writeInstr(Code_attribute attr, int pc)
102                throws Code_attribute.InvalidIndex {
103            String lP = "";
104            int opcode = attr.getUnsignedByte(pc);
105            int opcode2;
106            String mnem;
107            switch (opcode) {
108                case opc_nonpriv:
109                case opc_priv: {
110                    opcode2 = attr.getUnsignedByte(pc + 1);
111                    mnem = opcName((opcode << 8) + opcode2);
112                    if (mnem == null) {
113                        mnem = opcName(opcode) + " " + opcode2;
114                    }
115                    print(mnem);
116                    return 2;
117                }
118                case opc_wide: {
119                    opcode2 = attr.getUnsignedByte(pc + 1);
120                    mnem = opcName((opcode << 8) + opcode2);
121                    if (mnem == null) {
122                        print("bytecode " + opcode);
123                        return 1;
124                    }
125                    print(mnem + " " + attr.getUnsignedShort(pc + 2));
126                    if (opcode2 == opc_iinc) {
127                        print(", " + attr.getShort(pc + 4));
128                        return 6;
129                    }
130                    return 4;
131                }
132            }
133            mnem = opcName(opcode);
134            if (mnem == null) {
135                print("bytecode " + opcode);
136                return 1;
137            }
138            if (opcode > opc_jsr_w) {
139                print("bytecode " + opcode);
140                return 1;
141            }
142            print(opcName(opcode));
143            switch (opcode) {
144                case opc_aload:
145                case opc_astore:
146                case opc_fload:
147                case opc_fstore:
148                case opc_iload:
149                case opc_istore:
150                case opc_lload:
151                case opc_lstore:
152                case opc_dload:
153                case opc_dstore:
154                case opc_ret:
155                    print("\t" + attr.getUnsignedByte(pc + 1));
156                    return 2;
157                case opc_iinc:
158                    print("\t" + attr.getUnsignedByte(pc + 1) + ", " + attr.getByte(pc + 2));
159                    return 3;
160                case opc_tableswitch:
161                    {
162                        int tb = align(pc + 1);
163                        int default_skip = attr.getInt(tb);
164                        int low = attr.getInt(tb + 4);
165                        int high = attr.getInt(tb + 8);
166                        int count = high - low;
167                        print("{ //" + low + " to " + high);
168                        for (int i = 0; i <= count; i++) {
169                            print("\n\t\t" + (i + low) + ": " + lP + (pc + attr.getInt(tb + 12 + 4 * i)) + ";");
170                        }
171                        print("\n\t\tdefault: " + lP + (default_skip + pc) + " }");
172                        return tb - pc + 16 + count * 4;
173                    }
174                case opc_lookupswitch:
175                    {
176                        int tb = align(pc + 1);
177                        int default_skip = attr.getInt(tb);
178                        int npairs = attr.getInt(tb + 4);
179                        print("{ //" + npairs);
180                        for (int i = 1; i <= npairs; i++) {
181                            print("\n\t\t" + attr.getInt(tb + i * 8) + ": " + lP + (pc + attr.getInt(tb + 4 + i * 8)) + ";");
182                        }
183                        print("\n\t\tdefault: " + lP + (default_skip + pc) + " }");
184                        return tb - pc + (npairs + 1) * 8;
185                    }
186                case opc_newarray:
187                    int type = attr.getUnsignedByte(pc + 1);
188                    switch (type) {
189                        case T_BOOLEAN:
190                            print(" boolean");
191                            break;
192                        case T_BYTE:
193                            print(" byte");
194                            break;
195                        case T_CHAR:
196                            print(" char");
197                            break;
198                        case T_SHORT:
199                            print(" short");
200                            break;
201                        case T_INT:
202                            print(" int");
203                            break;
204                        case T_LONG:
205                            print(" long");
206                            break;
207                        case T_FLOAT:
208                            print(" float");
209                            break;
210                        case T_DOUBLE:
211                            print(" double");
212                            break;
213                        case T_CLASS:
214                            print(" class");
215                            break;
216                        default:
217                            print(" BOGUS TYPE:" + type);
218                    }
219                    return 2;
220                case opc_anewarray:
221                    {
222                        int index = attr.getUnsignedShort(pc + 1);
223                        print("\t#" + index + "; //");
224                        printConstant(index);
225                        return 3;
226                    }
227                case opc_sipush:
228                    print("\t" + attr.getShort(pc + 1));
229                    return 3;
230                case opc_bipush:
231                    print("\t" + attr.getByte(pc + 1));
232                    return 2;
233                case opc_ldc:
234                    {
235                        int index = attr.getUnsignedByte(pc + 1);
236                        print("\t#" + index + "; //");
237                        printConstant(index);
238                        return 2;
239                    }
240                case opc_ldc_w:
241                case opc_ldc2_w:
242                case opc_instanceof:
243                case opc_checkcast:
244                case opc_new:
245                case opc_putstatic:
246                case opc_getstatic:
247                case opc_putfield:
248                case opc_getfield:
249                case opc_invokevirtual:
250                case opc_invokespecial:
251                case opc_invokestatic:
252                    {
253                        int index = attr.getUnsignedShort(pc + 1);
254                        print("\t#" + index + "; //");
255                        printConstant(index);
256                        return 3;
257                    }
258                case opc_invokeinterface:
259                    {
260                        int index = attr.getUnsignedShort(pc + 1);
261                        int nargs = attr.getUnsignedByte(pc + 3);
262                        print("\t#" + index + ",  " + nargs + "; //");
263                        printConstant(index);
264                        return 5;
265                    }
266                case opc_multianewarray:
267                    {
268                        int index = attr.getUnsignedShort(pc + 1);
269                        int dimensions = attr.getUnsignedByte(pc + 3);
270                        print("\t#" + index + ",  " + dimensions + "; //");
271                        printConstant(index);
272                        return 4;
273                    }
274                case opc_jsr:
275                case opc_goto:
276                case opc_ifeq:
277                case opc_ifge:
278                case opc_ifgt:
279                case opc_ifle:
280                case opc_iflt:
281                case opc_ifne:
282                case opc_if_icmpeq:
283                case opc_if_icmpne:
284                case opc_if_icmpge:
285                case opc_if_icmpgt:
286                case opc_if_icmple:
287                case opc_if_icmplt:
288                case opc_if_acmpeq:
289                case opc_if_acmpne:
290                case opc_ifnull:
291                case opc_ifnonnull:
292                    print("\t" + lP + (pc + attr.getShort(pc + 1)));
293                    return 3;
294                case opc_jsr_w:
295                case opc_goto_w:
296                    print("\t" + lP + (pc + attr.getInt(pc + 1)));
297                    return 5;
298                default:
299                    return 1;
300            }
301        }
302    
303        public void writeExceptionTable(Code_attribute attr) {
304            if (attr.exception_table_langth > 0) {
305                println("  Exception table:");
306                println("   from   to  target type");
307                for (int i = 0; i < attr.exception_table.length; i++) {
308                    Code_attribute.Exception_data handler = attr.exception_table[i];
309                    printFixedWidthInt(handler.start_pc, 6);
310                    printFixedWidthInt(handler.end_pc, 6);
311                    printFixedWidthInt(handler.handler_pc, 6);
312                    print("   ");
313                    int catch_type = handler.catch_type;
314                    if (catch_type == 0) {
315                        println("any");
316                    } else {
317                        print("Class ");
318                        println(constantWriter.stringValue(catch_type));
319                        println("");
320                    }
321                }
322            }
323    
324        }
325    
326        private void printConstant(int index) {
327            constantWriter.write(index);
328        }
329    
330        private void printFixedWidthInt(int n, int width) {
331            String s = String.valueOf(n);
332            for (int i = s.length(); i < width; i++)
333                print(" ");
334            print(s);
335        }
336    
337        private static int align(int n) {
338            return (n + 3) & ~3;
339        }
340    
341        private AttributeWriter attrWriter;
342        private ClassWriter classWriter;
343        private ConstantWriter constantWriter;
344    }