6824493: experimental support for additional info for instructions
authorjjg
Tue, 19 May 2009 11:50:54 -0700
changeset 2979 ea39317acd3d
parent 2978 a72220103e31
child 2980 f391c41bae7e
6824493: experimental support for additional info for instructions Reviewed-by: mcimadamore
langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java
langtools/src/share/classes/com/sun/tools/javap/BasicWriter.java
langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java
langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java
langtools/src/share/classes/com/sun/tools/javap/InstructionDetailWriter.java
langtools/src/share/classes/com/sun/tools/javap/JavapTask.java
langtools/src/share/classes/com/sun/tools/javap/Messages.java
langtools/src/share/classes/com/sun/tools/javap/Options.java
langtools/src/share/classes/com/sun/tools/javap/SourceWriter.java
langtools/src/share/classes/com/sun/tools/javap/StackMapWriter.java
langtools/src/share/classes/com/sun/tools/javap/TryBlockWriter.java
langtools/src/share/classes/com/sun/tools/javap/resources/javap.properties
langtools/test/tools/javap/T6824493.java
--- a/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/classfile/StackMapTable_attribute.java	Tue May 19 11:50:54 2009 -0700
@@ -107,6 +107,8 @@
             return 1;
         }
 
+        public abstract int getOffsetDelta();
+
         public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
 
         public final int frame_type;
@@ -130,6 +132,10 @@
         public <R, D> R accept(Visitor<R, D> visitor, D data) {
             return visitor.visit_same_frame(this, data);
         }
+
+        public int getOffsetDelta() {
+            return frame_type;
+        }
     }
 
     public static class same_locals_1_stack_item_frame extends stack_map_frame {
@@ -149,6 +155,10 @@
             return visitor.visit_same_locals_1_stack_item_frame(this, data);
         }
 
+        public int getOffsetDelta() {
+            return frame_type - 64;
+        }
+
         public final verification_type_info[] stack;
     }
 
@@ -170,6 +180,10 @@
             return visitor.visit_same_locals_1_stack_item_frame_extended(this, data);
         }
 
+        public int getOffsetDelta() {
+            return offset_delta;
+        }
+
         public final int offset_delta;
         public final verification_type_info[] stack;
     }
@@ -189,6 +203,10 @@
             return visitor.visit_chop_frame(this, data);
         }
 
+        public int getOffsetDelta() {
+            return offset_delta;
+        }
+
         public final int offset_delta;
     }
 
@@ -207,6 +225,10 @@
             return visitor.visit_same_frame_extended(this, data);
         }
 
+        public int getOffsetDelta() {
+            return offset_delta;
+        }
+
         public final int offset_delta;
     }
 
@@ -232,6 +254,10 @@
             return visitor.visit_append_frame(this, data);
         }
 
+        public int getOffsetDelta() {
+            return offset_delta;
+        }
+
         public final int offset_delta;
         public final verification_type_info[] locals;
     }
@@ -266,6 +292,10 @@
             return visitor.visit_full_frame(this, data);
         }
 
+        public int getOffsetDelta() {
+            return offset_delta;
+        }
+
         public final int offset_delta;
         public final int number_of_locals;
         public final verification_type_info[] locals;
@@ -308,7 +338,7 @@
             }
         }
 
-        verification_type_info(int tag) {
+        protected verification_type_info(int tag) {
             this.tag = tag;
         }
 
--- a/langtools/src/share/classes/com/sun/tools/javap/BasicWriter.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/BasicWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -44,6 +44,9 @@
     protected BasicWriter(Context context) {
         lineWriter = LineWriter.instance(context);
         out = context.get(PrintWriter.class);
+        messages = context.get(Messages.class);
+        if (messages == null)
+            throw new AssertionError();
     }
 
     protected void print(String s) {
@@ -88,8 +91,26 @@
         return "???";
     }
 
+    protected String space(int w) {
+        if (w < spaces.length && spaces[w] != null)
+            return spaces[w];
+
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < w; i++)
+            sb.append(" ");
+
+        String s = sb.toString();
+        if (w < spaces.length)
+            spaces[w] = s;
+
+        return s;
+    }
+
+    private String[] spaces = new String[80];
+
     private LineWriter lineWriter;
     private PrintWriter out;
+    protected Messages messages;
 
     private static class LineWriter {
         static LineWriter instance(Context context) {
--- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -26,7 +26,9 @@
 package com.sun.tools.javap;
 
 import java.net.URI;
+import java.text.DateFormat;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 
 import com.sun.tools.classfile.AccessFlags;
@@ -47,8 +49,6 @@
 import com.sun.tools.classfile.SourceFile_attribute;
 import com.sun.tools.classfile.Type;
 
-import java.text.DateFormat;
-import java.util.Date;
 import static com.sun.tools.classfile.AccessFlags.*;
 
 /*
--- a/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/CodeWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -25,6 +25,9 @@
 
 package com.sun.tools.javap;
 
+import java.util.ArrayList;
+import java.util.List;
+
 import com.sun.tools.classfile.AccessFlags;
 import com.sun.tools.classfile.Code_attribute;
 import com.sun.tools.classfile.ConstantPool;
@@ -33,9 +36,6 @@
 import com.sun.tools.classfile.Instruction;
 import com.sun.tools.classfile.Instruction.TypeKind;
 import com.sun.tools.classfile.Method;
-import com.sun.tools.classfile.Opcode;
-
-//import static com.sun.tools.classfile.OpCodes.*;
 
 /*
  *  Write the contents of a Code attribute.
@@ -59,6 +59,12 @@
         attrWriter = AttributeWriter.instance(context);
         classWriter = ClassWriter.instance(context);
         constantWriter = ConstantWriter.instance(context);
+        sourceWriter = SourceWriter.instance(context);
+        tryBlockWriter = TryBlockWriter.instance(context);
+        stackMapWriter = StackMapWriter.instance(context);
+        localVariableTableWriter = LocalVariableTableWriter.instance(context);
+        localVariableTypeTableWriter = LocalVariableTypeTableWriter.instance(context);
+        options = Options.instance(context);
     }
 
     void write(Code_attribute attr, ConstantPool constant_pool) {
@@ -90,14 +96,21 @@
     }
 
     public void writeInstrs(Code_attribute attr) {
+        List<InstructionDetailWriter> detailWriters = getDetailWriters(attr);
+
         for (Instruction instr: attr.getInstructions()) {
             try {
+                for (InstructionDetailWriter w: detailWriters)
+                    w.writeDetails(instr);
                 writeInstr(instr);
             } catch (ArrayIndexOutOfBoundsException e) {
                 println(report("error at or after byte " + instr.getPC()));
                 break;
             }
         }
+
+        for (InstructionDetailWriter w: detailWriters)
+            w.flush();
     }
 
     public void writeInstr(Instruction instr) {
@@ -211,11 +224,45 @@
         print(s);
     }
 
-    private static int align(int n) {
-        return (n + 3) & ~3;
+    private List<InstructionDetailWriter> getDetailWriters(Code_attribute attr) {
+        List<InstructionDetailWriter> detailWriters =
+                new ArrayList<InstructionDetailWriter>();
+        if (options.details.contains(InstructionDetailWriter.Kind.SOURCE)) {
+            sourceWriter.reset(classWriter.getClassFile(), attr);
+            detailWriters.add(sourceWriter);
+        }
+
+        if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VARS)) {
+            localVariableTableWriter.reset(attr);
+            detailWriters.add(localVariableTableWriter);
+        }
+
+        if (options.details.contains(InstructionDetailWriter.Kind.LOCAL_VAR_TYPES)) {
+            localVariableTypeTableWriter.reset(attr);
+            detailWriters.add(localVariableTypeTableWriter);
+        }
+
+        if (options.details.contains(InstructionDetailWriter.Kind.STACKMAPS)) {
+            stackMapWriter.reset(attr);
+            stackMapWriter.writeInitialDetails();
+            detailWriters.add(stackMapWriter);
+        }
+
+        if (options.details.contains(InstructionDetailWriter.Kind.TRY_BLOCKS)) {
+            tryBlockWriter.reset(attr);
+            detailWriters.add(tryBlockWriter);
+        }
+
+        return detailWriters;
     }
 
     private AttributeWriter attrWriter;
     private ClassWriter classWriter;
     private ConstantWriter constantWriter;
+    private LocalVariableTableWriter localVariableTableWriter;
+    private LocalVariableTypeTableWriter localVariableTypeTableWriter;
+    private SourceWriter sourceWriter;
+    private StackMapWriter stackMapWriter;
+    private TryBlockWriter tryBlockWriter;
+    private Options options;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javap/InstructionDetailWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javap;
+
+import com.sun.tools.classfile.Instruction;
+
+
+/*
+ *  Write additional details for an instruction.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public abstract class InstructionDetailWriter extends BasicWriter {
+    public enum Kind {
+        LOCAL_VARS("localVariables"),
+        LOCAL_VAR_TYPES("localVariableTypes"),
+        SOURCE("source"),
+        STACKMAPS("stackMaps"),
+        TRY_BLOCKS("tryBlocks");
+        Kind(String option) {
+            this.option = option;
+        }
+        final String option;
+    }
+    InstructionDetailWriter(Context context) {
+        super(context);
+    }
+
+    abstract void writeDetails(Instruction instr);
+    void flush() { }
+}
--- a/langtools/src/share/classes/com/sun/tools/javap/JavapTask.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/JavapTask.java	Tue May 19 11:50:54 2009 -0700
@@ -39,6 +39,7 @@
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -65,7 +66,7 @@
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
-public class JavapTask implements DisassemblerTool.DisassemblerTask {
+public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
     public class BadArgs extends Exception {
         static final long serialVersionUID = 8765093759964640721L;
         BadArgs(String key, Object... args) {
@@ -241,6 +242,56 @@
             }
         },
 
+        new Option(false, "-XDdetails") {
+            void process(JavapTask task, String opt, String arg) {
+                task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
+            }
+
+        },
+
+        new Option(false, "-XDdetails:") {
+            @Override
+            boolean matches(String opt) {
+                int sep = opt.indexOf(":");
+                return sep != -1 && super.matches(opt.substring(0, sep + 1));
+            }
+
+            void process(JavapTask task, String opt, String arg) throws BadArgs {
+                int sep = opt.indexOf(":");
+                for (String v: opt.substring(sep + 1).split("[,: ]+")) {
+                    if (!handleArg(task, v))
+                        throw task.new BadArgs("err.invalid.arg.for.option", v);
+                }
+            }
+
+            boolean handleArg(JavapTask task, String arg) {
+                if (arg.length() == 0)
+                    return true;
+
+                if (arg.equals("all")) {
+                    task.options.details = EnumSet.allOf(InstructionDetailWriter.Kind.class);
+                    return true;
+                }
+
+                boolean on = true;
+                if (arg.startsWith("-")) {
+                    on = false;
+                    arg = arg.substring(1);
+                }
+
+                for (InstructionDetailWriter.Kind k: InstructionDetailWriter.Kind.values()) {
+                    if (arg.equalsIgnoreCase(k.option)) {
+                        if (on)
+                            task.options.details.add(k);
+                        else
+                            task.options.details.remove(k);
+                        return true;
+                    }
+                }
+                return false;
+            }
+        },
+
         new Option(false, "-constants") {
             void process(JavapTask task, String opt, String arg) {
                 task.options.showConstants = true;
@@ -251,6 +302,7 @@
 
     JavapTask() {
         context = new Context();
+        context.put(Messages.class, this);
         options = Options.instance(context);
     }
 
@@ -469,6 +521,8 @@
 
         context.put(PrintWriter.class, log);
         ClassWriter classWriter = ClassWriter.instance(context);
+        SourceWriter sourceWriter = SourceWriter.instance(context);
+        sourceWriter.setFileManager(fileManager);
 
         boolean ok = true;
 
@@ -651,11 +705,11 @@
 
     }
 
-    private String getMessage(String key, Object... args) {
+    public String getMessage(String key, Object... args) {
         return getMessage(task_locale, key, args);
     }
 
-    private String getMessage(Locale locale, String key, Object... args) {
+    public String getMessage(Locale locale, String key, Object... args) {
         if (bundles == null) {
             // could make this a HashMap<Locale,SoftReference<ResourceBundle>>
             // and for efficiency, keep a hard reference to the bundle for the task
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javap/Messages.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2007-2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javap;
+
+import java.util.Locale;
+
+/**
+ *  Access to javap messages.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public interface Messages {
+    String getMessage(String key, Object... args);
+
+    String getMessage(Locale locale, String key, Object... args);
+}
--- a/langtools/src/share/classes/com/sun/tools/javap/Options.java	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/Options.java	Tue May 19 11:50:54 2009 -0700
@@ -25,8 +25,10 @@
 
 package com.sun.tools.javap;
 
+import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.Set;
+
 import com.sun.tools.classfile.AccessFlags;
 
 /*
@@ -77,6 +79,7 @@
     public boolean showLineAndLocalVariableTables;
     public int showAccess;
     public Set<String> accessOptions = new HashSet<String>();
+    public Set<InstructionDetailWriter.Kind> details = EnumSet.noneOf(InstructionDetailWriter.Kind.class);
     public boolean showDisassembled;
     public boolean showInternalSignatures;
     public boolean showAllAttrs;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javap/SourceWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javap;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileManager.Location;
+import javax.tools.JavaFileObject;
+import javax.tools.StandardLocation;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.ClassFile;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Instruction;
+import com.sun.tools.classfile.LineNumberTable_attribute;
+import com.sun.tools.classfile.SourceFile_attribute;
+
+
+/**
+ * Annotate instructions with source code.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class SourceWriter extends InstructionDetailWriter {
+    static SourceWriter instance(Context context) {
+        SourceWriter instance = context.get(SourceWriter.class);
+        if (instance == null)
+            instance = new SourceWriter(context);
+        return instance;
+    }
+
+    protected SourceWriter(Context context) {
+        super(context);
+        context.put(SourceWriter.class, this);
+    }
+
+    void setFileManager(JavaFileManager fileManager) {
+        this.fileManager = fileManager;
+    }
+
+    public void reset(ClassFile cf, Code_attribute attr) {
+        setSource(cf);
+        setLineMap(attr);
+    }
+
+    public void writeDetails(Instruction instr) {
+        String indent = space(40); // could get from Options?
+        Set<Integer> lines = lineMap.get(instr.getPC());
+        if (lines != null) {
+            for (int line: lines) {
+                print(indent);
+                print(String.format(" %4d ", line));
+                if (line < sourceLines.length)
+                    print(sourceLines[line]);
+                println();
+                int nextLine = nextLine(line);
+                for (int i = line + 1; i < nextLine; i++) {
+                    print(indent);
+                    print(String.format("(%4d)", i));
+                    if (i < sourceLines.length)
+                        print(sourceLines[i]);
+                    println();
+                }
+            }
+        }
+
+    }
+
+    private void setLineMap(Code_attribute attr) {
+        SortedMap<Integer, SortedSet<Integer>> map =
+                new TreeMap<Integer, SortedSet<Integer>>();
+        SortedSet<Integer> allLines = new TreeSet<Integer>();
+        for (Attribute a: attr.attributes) {
+            if (a instanceof LineNumberTable_attribute) {
+                LineNumberTable_attribute t = (LineNumberTable_attribute) a;
+                for (LineNumberTable_attribute.Entry e: t.line_number_table) {
+                    int start_pc = e.start_pc;
+                    int line = e.line_number;
+                    SortedSet<Integer> pcLines = map.get(start_pc);
+                    if (pcLines == null) {
+                        pcLines = new TreeSet<Integer>();
+                        map.put(start_pc, pcLines);
+                    }
+                    pcLines.add(line);
+                    allLines.add(line);
+                }
+            }
+        }
+        lineMap = map;
+        lineList = new ArrayList<Integer>(allLines);
+    }
+
+    private void setSource(ClassFile cf) {
+        if (cf != classFile) {
+            classFile = cf;
+            sourceLines = splitLines(readSource(cf));
+        }
+    }
+
+    private String readSource(ClassFile cf) {
+        Location location;
+        if (fileManager.hasLocation((StandardLocation.SOURCE_PATH)))
+            location = StandardLocation.SOURCE_PATH;
+        else
+            location = StandardLocation.CLASS_PATH;
+
+        // Guess the source file for a class from the package name for this
+        // class and the base of the source file. This avoids having to read
+        // additional classes to determine the outmost class from any
+        // InnerClasses and EnclosingMethod attributes.
+        try {
+            String className = cf.getName();
+            SourceFile_attribute sf =
+                    (SourceFile_attribute) cf.attributes.get(Attribute.SourceFile);
+            if (sf == null) {
+                report(messages.getMessage("err.no.SourceFile.attribute"));
+                return null;
+            }
+            String sourceFile = sf.getSourceFile(cf.constant_pool);
+            String fileBase = sourceFile.endsWith(".java")
+                ? sourceFile.substring(0, sourceFile.length() - 5) : sourceFile;
+            int sep = className.lastIndexOf("/");
+            String pkgName = (sep == -1 ? "" : className.substring(0, sep+1));
+            String topClassName = (pkgName + fileBase).replace('/', '.');
+            JavaFileObject fo =
+                    fileManager.getJavaFileForInput(location,
+                    topClassName,
+                    JavaFileObject.Kind.SOURCE);
+            if (fo == null) {
+                report(messages.getMessage("err.source.file.not.found"));
+                return null;
+            }
+            return fo.getCharContent(true).toString();
+        } catch (ConstantPoolException e) {
+            report(e);
+            return null;
+        } catch (IOException e) {
+            report(e.getLocalizedMessage());
+            return null;
+        }
+    }
+
+    private static String[] splitLines(String text) {
+        if (text == null)
+            return new String[0];
+
+        List<String> lines = new ArrayList<String>();
+        lines.add(""); // dummy line 0
+        try {
+            BufferedReader r = new BufferedReader(new StringReader(text));
+            String line;
+            while ((line = r.readLine()) != null)
+                lines.add(line);
+        } catch (IOException ignore) {
+        }
+        return lines.toArray(new String[lines.size()]);
+    }
+
+    private int nextLine(int line) {
+        int i = lineList.indexOf(line);
+        if (i == -1 || i == lineList.size() - 1)
+            return - 1;
+        return lineList.get(i + 1);
+    }
+
+    private JavaFileManager fileManager;
+    private ClassFile classFile;
+    private SortedMap<Integer, SortedSet<Integer>> lineMap;
+    private List<Integer> lineList;
+    private String[] sourceLines;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javap/StackMapWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,291 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javap;
+
+import com.sun.tools.classfile.AccessFlags;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.sun.tools.classfile.Attribute;
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.ConstantPool;
+import com.sun.tools.classfile.ConstantPoolException;
+import com.sun.tools.classfile.Descriptor;
+import com.sun.tools.classfile.Descriptor.InvalidDescriptor;
+import com.sun.tools.classfile.Instruction;
+import com.sun.tools.classfile.Method;
+import com.sun.tools.classfile.StackMapTable_attribute;
+import com.sun.tools.classfile.StackMapTable_attribute.*;
+
+import static com.sun.tools.classfile.StackMapTable_attribute.verification_type_info.*;
+
+/**
+ * Annotate instructions with stack map.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class StackMapWriter extends InstructionDetailWriter {
+    static StackMapWriter instance(Context context) {
+        StackMapWriter instance = context.get(StackMapWriter.class);
+        if (instance == null)
+            instance = new StackMapWriter(context);
+        return instance;
+    }
+
+    protected StackMapWriter(Context context) {
+        super(context);
+        context.put(StackMapWriter.class, this);
+        classWriter = ClassWriter.instance(context);
+    }
+
+    public void reset(Code_attribute attr) {
+        setStackMap((StackMapTable_attribute) attr.attributes.get(Attribute.StackMapTable));
+    }
+
+    void setStackMap(StackMapTable_attribute attr) {
+        if (attr == null) {
+            map = null;
+            return;
+        }
+
+        Method m = classWriter.getMethod();
+        Descriptor d = m.descriptor;
+        String[] args;
+        try {
+            ConstantPool cp = classWriter.getClassFile().constant_pool;
+            String argString = d.getParameterTypes(cp);
+            args = argString.substring(1, argString.length() - 1).split("[, ]+");
+        } catch (ConstantPoolException e) {
+            return;
+        } catch (InvalidDescriptor e) {
+            return;
+        }
+        boolean isStatic = m.access_flags.is(AccessFlags.ACC_STATIC);
+
+        verification_type_info[] initialLocals = new verification_type_info[(isStatic ? 0 : 1) + args.length];
+        if (!isStatic)
+            initialLocals[0] = new CustomVerificationTypeInfo("this");
+        for (int i = 0; i < args.length; i++) {
+            initialLocals[(isStatic ? 0 : 1) + i] =
+                    new CustomVerificationTypeInfo(args[i].replace(".", "/"));
+        }
+
+        map = new HashMap<Integer, StackMap>();
+        StackMapBuilder builder = new StackMapBuilder();
+
+        // using -1 as the pc for the initial frame effectively compensates for
+        // the difference in behavior for the first stack map frame (where the
+        // pc offset is just offset_delta) compared to subsequent frames (where
+        // the pc offset is always offset_delta+1).
+        int pc = -1;
+
+        map.put(pc, new StackMap(initialLocals, empty));
+
+        for (int i = 0; i < attr.entries.length; i++)
+            pc = attr.entries[i].accept(builder, pc);
+    }
+
+    public void writeInitialDetails() {
+        writeDetails(-1);
+    }
+
+    public void writeDetails(Instruction instr) {
+        writeDetails(instr.getPC());
+    }
+
+    private void writeDetails(int pc) {
+        if (map == null)
+            return;
+
+        StackMap m = map.get(pc);
+        if (m != null) {
+            print("StackMap locals: ", m.locals);
+            print("StackMap stack: ", m.stack);
+        }
+
+    }
+
+    void print(String label, verification_type_info[] entries) {
+        print(label);
+        for (int i = 0; i < entries.length; i++) {
+            print(" ");
+            print(entries[i]);
+        }
+        println();
+    }
+
+    void print(verification_type_info entry) {
+        if (entry == null) {
+            print("ERROR");
+            return;
+        }
+
+        switch (entry.tag) {
+            case -1:
+                print(((CustomVerificationTypeInfo) entry).text);
+                break;
+
+            case ITEM_Top:
+                print("top");
+                break;
+
+            case ITEM_Integer:
+                print("int");
+                break;
+
+            case ITEM_Float:
+                print("float");
+                break;
+
+            case ITEM_Long:
+                print("long");
+                break;
+
+            case ITEM_Double:
+                print("double");
+                break;
+
+            case ITEM_Null:
+                print("null");
+                break;
+
+            case ITEM_UninitializedThis:
+                print("uninit_this");
+                break;
+
+            case ITEM_Object:
+                try {
+                    ConstantPool cp = classWriter.getClassFile().constant_pool;
+                    ConstantPool.CONSTANT_Class_info class_info = cp.getClassInfo(((Object_variable_info) entry).cpool_index);
+                    print(cp.getUTF8Value(class_info.name_index));
+                } catch (ConstantPoolException e) {
+                    print("??");
+                }
+                break;
+
+            case ITEM_Uninitialized:
+                print(((Uninitialized_variable_info) entry).offset);
+                break;
+        }
+
+    }
+
+    private Map<Integer, StackMap> map;
+    private ClassWriter classWriter;
+
+    class StackMapBuilder
+            implements StackMapTable_attribute.stack_map_frame.Visitor<Integer, Integer> {
+
+        public Integer visit_same_frame(same_frame frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap m = map.get(pc);
+            assert (m != null);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_same_locals_1_stack_item_frame(same_locals_1_stack_item_frame frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap prev = map.get(pc);
+            assert (prev != null);
+            StackMap m = new StackMap(prev.locals, frame.stack);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_same_locals_1_stack_item_frame_extended(same_locals_1_stack_item_frame_extended frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap prev = map.get(pc);
+            assert (prev != null);
+            StackMap m = new StackMap(prev.locals, frame.stack);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_chop_frame(chop_frame frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap prev = map.get(pc);
+            assert (prev != null);
+            int k = 251 - frame.frame_type;
+            verification_type_info[] new_locals = new verification_type_info[prev.locals.length - k];
+            System.arraycopy(prev.locals, 0, new_locals, 0, new_locals.length);
+            StackMap m = new StackMap(new_locals, empty);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_same_frame_extended(same_frame_extended frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta();
+            StackMap m = map.get(pc);
+            assert (m != null);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_append_frame(append_frame frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap prev = map.get(pc);
+            assert (prev != null);
+            verification_type_info[] new_locals = new verification_type_info[prev.locals.length + frame.locals.length];
+            System.arraycopy(prev.locals, 0, new_locals, 0, prev.locals.length);
+            System.arraycopy(frame.locals, 0, new_locals, prev.locals.length, frame.locals.length);
+            StackMap m = new StackMap(new_locals, empty);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+        public Integer visit_full_frame(full_frame frame, Integer pc) {
+            int new_pc = pc + frame.getOffsetDelta() + 1;
+            StackMap m = new StackMap(frame.locals, frame.stack);
+            map.put(new_pc, m);
+            return new_pc;
+        }
+
+    }
+
+    class StackMap {
+        StackMap(verification_type_info[] locals, verification_type_info[] stack) {
+            this.locals = locals;
+            this.stack = stack;
+        }
+
+        private final verification_type_info[] locals;
+        private final verification_type_info[] stack;
+    }
+
+    class CustomVerificationTypeInfo extends verification_type_info {
+        public CustomVerificationTypeInfo(String text) {
+            super(-1);
+            this.text = text;
+        }
+        private String text;
+    }
+
+    private final verification_type_info[] empty = { };
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javap/TryBlockWriter.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.tools.javap;
+
+import com.sun.tools.classfile.Code_attribute;
+import com.sun.tools.classfile.Code_attribute.Exception_data;
+import com.sun.tools.classfile.Instruction;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+/**
+ * Annotate instructions with details about try blocks.
+ *
+ *  <p><b>This is NOT part of any API supported by Sun Microsystems.  If
+ *  you write code that depends on this, you do so at your own risk.
+ *  This code and its internal interfaces are subject to change or
+ *  deletion without notice.</b>
+ */
+public class TryBlockWriter extends InstructionDetailWriter {
+    public enum NoteKind {
+        START("try") {
+            public boolean match(Exception_data entry, int pc) {
+                return (pc == entry.start_pc);
+            }
+        },
+        END("end try") {
+            public boolean match(Exception_data entry, int pc) {
+                return (pc == entry.end_pc);
+            }
+        },
+        HANDLER("catch") {
+            public boolean match(Exception_data entry, int pc) {
+                return (pc == entry.handler_pc);
+            }
+        };
+        NoteKind(String text) {
+            this.text = text;
+        }
+        public abstract boolean match(Exception_data entry, int pc);
+        public final String text;
+    };
+
+    static TryBlockWriter instance(Context context) {
+        TryBlockWriter instance = context.get(TryBlockWriter.class);
+        if (instance == null)
+            instance = new TryBlockWriter(context);
+        return instance;
+    }
+
+    protected TryBlockWriter(Context context) {
+        super(context);
+        context.put(TryBlockWriter.class, this);
+        constantWriter = ConstantWriter.instance(context);
+    }
+
+    public void reset(Code_attribute attr) {
+        indexMap = new HashMap<Exception_data, Integer>();
+        pcMap = new HashMap<Integer, List<Exception_data>>();
+        for (int i = 0; i < attr.exception_table.length; i++) {
+            Exception_data entry = attr.exception_table[i];
+            indexMap.put(entry, i);
+            put(entry.start_pc, entry);
+            put(entry.end_pc, entry);
+            put(entry.handler_pc, entry);
+        }
+    }
+
+    public void writeDetails(Instruction instr) {
+        writeTrys(instr, NoteKind.END);
+        writeTrys(instr, NoteKind.START);
+        writeTrys(instr, NoteKind.HANDLER);
+    }
+
+    public void writeTrys(Instruction instr, NoteKind kind) {
+        String indent = space(2); // get from Options?
+        int pc = instr.getPC();
+        List<Exception_data> entries = pcMap.get(pc);
+        if (entries != null) {
+            for (ListIterator<Exception_data> iter =
+                    entries.listIterator(kind == NoteKind.END ? entries.size() : 0);
+                    kind == NoteKind.END ? iter.hasPrevious() : iter.hasNext() ; ) {
+                Exception_data entry =
+                        kind == NoteKind.END ? iter.previous() : iter.next();
+                if (kind.match(entry, pc)) {
+                    print(indent);
+                    print(kind.text);
+                    print("[");
+                    print(indexMap.get(entry));
+                    print("] ");
+                    if (entry.catch_type == 0)
+                        print("finally");
+                    else {
+                        print("#" + entry.catch_type);
+                        print(" // ");
+                        constantWriter.write(entry.catch_type);
+                    }
+                    println();
+                }
+            }
+        }
+    }
+
+    private void put(int pc, Exception_data entry) {
+        List<Exception_data> list = pcMap.get(pc);
+        if (list == null) {
+            list = new ArrayList<Exception_data>();
+            pcMap.put(pc, list);
+        }
+        if (!list.contains(entry))
+            list.add(entry);
+    }
+
+    private Map<Integer, List<Exception_data>> pcMap;
+    private Map<Exception_data, Integer> indexMap;
+    private ConstantWriter constantWriter;
+}
--- a/langtools/src/share/classes/com/sun/tools/javap/resources/javap.properties	Tue May 19 11:43:50 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/resources/javap.properties	Tue May 19 11:50:54 2009 -0700
@@ -9,6 +9,7 @@
 err.h.not.supported=-h is no longer available - use the 'javah' program
 err.incompatible.options=bad combination of options: {0}
 err.internal.error=internal error: {0} {1} {2}
+err.invalid.arg.for.option=invalid argument for option: {0}
 err.ioerror=IO error reading {0}: {1}
 err.missing.arg=no value given for {0}
 err.no.classes.specified=no classes specified
@@ -16,6 +17,8 @@
 err.unknown.option=unknown option: {0}
 err.verify.not.supported=-verify not supported
 err.Xold.not.supported.here=-Xold must be given as the first option
+err.no.SourceFile.attribute=no SourceFile attribute
+err.source.file.not.found=source file not found
 
 main.usage.summary=\
 Usage: {0} <options> <classes>\n\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/T6824493.java	Tue May 19 11:50:54 2009 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.util.*;
+
+/*
+ * @test
+ * @bug 6824493
+ * @summary experimental support for additional info for instructions
+ * @compile -g T6824493.java
+ * @run main T6824493
+ */
+public class T6824493 {
+    public static void main(String... args) {
+        new T6824493().run();
+    }
+
+    void run() {
+        // for each of the options, we run javap and check for some
+        // marker strings in the output that generally indicate the
+        // presence of the expected output, without being as specific
+        // as a full golden file test.
+        test("-XDdetails:source",
+            "for (int i = 0; i < 10; i++) {",
+            "System.out.println(s + i);");
+
+        test("-XDdetails:tryBlocks",
+                "try[0]",
+                "end try[0]",
+                "catch[0]");
+
+        test("-XDdetails:stackMaps",
+                "StackMap locals:  this java/lang/String int",
+                "StackMap stack:  java/lang/Throwable");
+
+        test("-XDdetails:localVariables",
+                "start local 3 // java.util.List list",
+                "end local 3 // java.util.List list");
+
+        test("-XDdetails:localVariableTypes",
+                "start generic local 3 // java.util.List<java.lang.String> list",
+                "end generic local 3 // java.util.List<java.lang.String> list");
+
+        if (errors > 0)
+            throw new Error(errors + " errors found");
+    }
+
+    void test(String option, String... expect) {
+        String[] args = {
+            "-c",
+            "-classpath",
+            testSrc + File.pathSeparator + testClasses,
+            option,
+            "Test"
+        };
+        StringWriter sw = new StringWriter();
+        PrintWriter pw = new PrintWriter(sw);
+        int rc = com.sun.tools.javap.Main.run(args, pw);
+        if (rc != 0) {
+            error("unexpected return code from javap: " + rc);
+            return;
+        }
+
+        String out = sw.toString();
+        System.out.println(out);
+        for (String e: expect) {
+            if (!out.contains(e))
+                error("Not found: " + e);
+        }
+    }
+
+    void error(String msg) {
+        System.err.println("Error: " + msg);
+        errors++;
+    }
+
+    private int errors;
+    private String testSrc = System.getProperty("test.src", ".");
+    private String testClasses = System.getProperty("test.classes", ".");
+}
+
+class Test {
+    void m(String s) {
+        for (int i = 0; i < 10; i++) {
+            try {
+                List<String> list = null;
+                System.out.println(s + i);
+            } catch (NullPointerException e) {
+                System.out.println("catch NPE");
+            } finally {
+                System.out.println("finally");
+            }
+        }
+    }
+}