6824493: experimental support for additional info for instructions
Reviewed-by: mcimadamore
--- 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");
+ }
+ }
+ }
+}