6824493: experimental support for additional info for instructions
Reviewed-by: mcimadamore
This commit is contained in:
parent
f05e74203e
commit
72b623769a
@ -107,6 +107,8 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract int getOffsetDelta();
|
||||||
|
|
||||||
public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
|
public abstract <R,D> R accept(Visitor<R,D> visitor, D data);
|
||||||
|
|
||||||
public final int frame_type;
|
public final int frame_type;
|
||||||
@ -130,6 +132,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
public <R, D> R accept(Visitor<R, D> visitor, D data) {
|
public <R, D> R accept(Visitor<R, D> visitor, D data) {
|
||||||
return visitor.visit_same_frame(this, 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 {
|
public static class same_locals_1_stack_item_frame extends stack_map_frame {
|
||||||
@ -149,6 +155,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_same_locals_1_stack_item_frame(this, data);
|
return visitor.visit_same_locals_1_stack_item_frame(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOffsetDelta() {
|
||||||
|
return frame_type - 64;
|
||||||
|
}
|
||||||
|
|
||||||
public final verification_type_info[] stack;
|
public final verification_type_info[] stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +180,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_same_locals_1_stack_item_frame_extended(this, data);
|
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 int offset_delta;
|
||||||
public final verification_type_info[] stack;
|
public final verification_type_info[] stack;
|
||||||
}
|
}
|
||||||
@ -189,6 +203,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_chop_frame(this, data);
|
return visitor.visit_chop_frame(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOffsetDelta() {
|
||||||
|
return offset_delta;
|
||||||
|
}
|
||||||
|
|
||||||
public final int offset_delta;
|
public final int offset_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,6 +225,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_same_frame_extended(this, data);
|
return visitor.visit_same_frame_extended(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOffsetDelta() {
|
||||||
|
return offset_delta;
|
||||||
|
}
|
||||||
|
|
||||||
public final int offset_delta;
|
public final int offset_delta;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +254,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_append_frame(this, data);
|
return visitor.visit_append_frame(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOffsetDelta() {
|
||||||
|
return offset_delta;
|
||||||
|
}
|
||||||
|
|
||||||
public final int offset_delta;
|
public final int offset_delta;
|
||||||
public final verification_type_info[] locals;
|
public final verification_type_info[] locals;
|
||||||
}
|
}
|
||||||
@ -266,6 +292,10 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
return visitor.visit_full_frame(this, data);
|
return visitor.visit_full_frame(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getOffsetDelta() {
|
||||||
|
return offset_delta;
|
||||||
|
}
|
||||||
|
|
||||||
public final int offset_delta;
|
public final int offset_delta;
|
||||||
public final int number_of_locals;
|
public final int number_of_locals;
|
||||||
public final verification_type_info[] locals;
|
public final verification_type_info[] locals;
|
||||||
@ -308,7 +338,7 @@ public class StackMapTable_attribute extends Attribute {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
verification_type_info(int tag) {
|
protected verification_type_info(int tag) {
|
||||||
this.tag = tag;
|
this.tag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,9 @@ public class BasicWriter {
|
|||||||
protected BasicWriter(Context context) {
|
protected BasicWriter(Context context) {
|
||||||
lineWriter = LineWriter.instance(context);
|
lineWriter = LineWriter.instance(context);
|
||||||
out = context.get(PrintWriter.class);
|
out = context.get(PrintWriter.class);
|
||||||
|
messages = context.get(Messages.class);
|
||||||
|
if (messages == null)
|
||||||
|
throw new AssertionError();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void print(String s) {
|
protected void print(String s) {
|
||||||
@ -88,8 +91,26 @@ public class BasicWriter {
|
|||||||
return "???";
|
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 LineWriter lineWriter;
|
||||||
private PrintWriter out;
|
private PrintWriter out;
|
||||||
|
protected Messages messages;
|
||||||
|
|
||||||
private static class LineWriter {
|
private static class LineWriter {
|
||||||
static LineWriter instance(Context context) {
|
static LineWriter instance(Context context) {
|
||||||
|
@ -26,7 +26,9 @@
|
|||||||
package com.sun.tools.javap;
|
package com.sun.tools.javap;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.text.DateFormat;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import com.sun.tools.classfile.AccessFlags;
|
import com.sun.tools.classfile.AccessFlags;
|
||||||
@ -47,8 +49,6 @@ import com.sun.tools.classfile.Signature_attribute;
|
|||||||
import com.sun.tools.classfile.SourceFile_attribute;
|
import com.sun.tools.classfile.SourceFile_attribute;
|
||||||
import com.sun.tools.classfile.Type;
|
import com.sun.tools.classfile.Type;
|
||||||
|
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.util.Date;
|
|
||||||
import static com.sun.tools.classfile.AccessFlags.*;
|
import static com.sun.tools.classfile.AccessFlags.*;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -25,6 +25,9 @@
|
|||||||
|
|
||||||
package com.sun.tools.javap;
|
package com.sun.tools.javap;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import com.sun.tools.classfile.AccessFlags;
|
import com.sun.tools.classfile.AccessFlags;
|
||||||
import com.sun.tools.classfile.Code_attribute;
|
import com.sun.tools.classfile.Code_attribute;
|
||||||
import com.sun.tools.classfile.ConstantPool;
|
import com.sun.tools.classfile.ConstantPool;
|
||||||
@ -33,9 +36,6 @@ import com.sun.tools.classfile.DescriptorException;
|
|||||||
import com.sun.tools.classfile.Instruction;
|
import com.sun.tools.classfile.Instruction;
|
||||||
import com.sun.tools.classfile.Instruction.TypeKind;
|
import com.sun.tools.classfile.Instruction.TypeKind;
|
||||||
import com.sun.tools.classfile.Method;
|
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.
|
* Write the contents of a Code attribute.
|
||||||
@ -59,6 +59,12 @@ class CodeWriter extends BasicWriter {
|
|||||||
attrWriter = AttributeWriter.instance(context);
|
attrWriter = AttributeWriter.instance(context);
|
||||||
classWriter = ClassWriter.instance(context);
|
classWriter = ClassWriter.instance(context);
|
||||||
constantWriter = ConstantWriter.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) {
|
void write(Code_attribute attr, ConstantPool constant_pool) {
|
||||||
@ -90,14 +96,21 @@ class CodeWriter extends BasicWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeInstrs(Code_attribute attr) {
|
public void writeInstrs(Code_attribute attr) {
|
||||||
|
List<InstructionDetailWriter> detailWriters = getDetailWriters(attr);
|
||||||
|
|
||||||
for (Instruction instr: attr.getInstructions()) {
|
for (Instruction instr: attr.getInstructions()) {
|
||||||
try {
|
try {
|
||||||
|
for (InstructionDetailWriter w: detailWriters)
|
||||||
|
w.writeDetails(instr);
|
||||||
writeInstr(instr);
|
writeInstr(instr);
|
||||||
} catch (ArrayIndexOutOfBoundsException e) {
|
} catch (ArrayIndexOutOfBoundsException e) {
|
||||||
println(report("error at or after byte " + instr.getPC()));
|
println(report("error at or after byte " + instr.getPC()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (InstructionDetailWriter w: detailWriters)
|
||||||
|
w.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeInstr(Instruction instr) {
|
public void writeInstr(Instruction instr) {
|
||||||
@ -211,11 +224,45 @@ class CodeWriter extends BasicWriter {
|
|||||||
print(s);
|
print(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int align(int n) {
|
private List<InstructionDetailWriter> getDetailWriters(Code_attribute attr) {
|
||||||
return (n + 3) & ~3;
|
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 AttributeWriter attrWriter;
|
||||||
private ClassWriter classWriter;
|
private ClassWriter classWriter;
|
||||||
private ConstantWriter constantWriter;
|
private ConstantWriter constantWriter;
|
||||||
|
private LocalVariableTableWriter localVariableTableWriter;
|
||||||
|
private LocalVariableTypeTableWriter localVariableTypeTableWriter;
|
||||||
|
private SourceWriter sourceWriter;
|
||||||
|
private StackMapWriter stackMapWriter;
|
||||||
|
private TryBlockWriter tryBlockWriter;
|
||||||
|
private Options options;
|
||||||
}
|
}
|
||||||
|
@ -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() { }
|
||||||
|
}
|
@ -39,6 +39,7 @@ import java.security.MessageDigest;
|
|||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -65,7 +66,7 @@ import com.sun.tools.classfile.*;
|
|||||||
* This code and its internal interfaces are subject to change or
|
* This code and its internal interfaces are subject to change or
|
||||||
* deletion without notice.</b>
|
* deletion without notice.</b>
|
||||||
*/
|
*/
|
||||||
public class JavapTask implements DisassemblerTool.DisassemblerTask {
|
public class JavapTask implements DisassemblerTool.DisassemblerTask, Messages {
|
||||||
public class BadArgs extends Exception {
|
public class BadArgs extends Exception {
|
||||||
static final long serialVersionUID = 8765093759964640721L;
|
static final long serialVersionUID = 8765093759964640721L;
|
||||||
BadArgs(String key, Object... args) {
|
BadArgs(String key, Object... args) {
|
||||||
@ -241,6 +242,56 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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") {
|
new Option(false, "-constants") {
|
||||||
void process(JavapTask task, String opt, String arg) {
|
void process(JavapTask task, String opt, String arg) {
|
||||||
task.options.showConstants = true;
|
task.options.showConstants = true;
|
||||||
@ -251,6 +302,7 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask {
|
|||||||
|
|
||||||
JavapTask() {
|
JavapTask() {
|
||||||
context = new Context();
|
context = new Context();
|
||||||
|
context.put(Messages.class, this);
|
||||||
options = Options.instance(context);
|
options = Options.instance(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -469,6 +521,8 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask {
|
|||||||
|
|
||||||
context.put(PrintWriter.class, log);
|
context.put(PrintWriter.class, log);
|
||||||
ClassWriter classWriter = ClassWriter.instance(context);
|
ClassWriter classWriter = ClassWriter.instance(context);
|
||||||
|
SourceWriter sourceWriter = SourceWriter.instance(context);
|
||||||
|
sourceWriter.setFileManager(fileManager);
|
||||||
|
|
||||||
boolean ok = true;
|
boolean ok = true;
|
||||||
|
|
||||||
@ -651,11 +705,11 @@ public class JavapTask implements DisassemblerTool.DisassemblerTask {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getMessage(String key, Object... args) {
|
public String getMessage(String key, Object... args) {
|
||||||
return getMessage(task_locale, key, 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) {
|
if (bundles == null) {
|
||||||
// could make this a HashMap<Locale,SoftReference<ResourceBundle>>
|
// could make this a HashMap<Locale,SoftReference<ResourceBundle>>
|
||||||
// and for efficiency, keep a hard reference to the bundle for the task
|
// and for efficiency, keep a hard reference to the bundle for the task
|
||||||
|
@ -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);
|
||||||
|
}
|
@ -25,8 +25,10 @@
|
|||||||
|
|
||||||
package com.sun.tools.javap;
|
package com.sun.tools.javap;
|
||||||
|
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.sun.tools.classfile.AccessFlags;
|
import com.sun.tools.classfile.AccessFlags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -77,6 +79,7 @@ public class Options {
|
|||||||
public boolean showLineAndLocalVariableTables;
|
public boolean showLineAndLocalVariableTables;
|
||||||
public int showAccess;
|
public int showAccess;
|
||||||
public Set<String> accessOptions = new HashSet<String>();
|
public Set<String> accessOptions = new HashSet<String>();
|
||||||
|
public Set<InstructionDetailWriter.Kind> details = EnumSet.noneOf(InstructionDetailWriter.Kind.class);
|
||||||
public boolean showDisassembled;
|
public boolean showDisassembled;
|
||||||
public boolean showInternalSignatures;
|
public boolean showInternalSignatures;
|
||||||
public boolean showAllAttrs;
|
public boolean showAllAttrs;
|
||||||
|
@ -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;
|
||||||
|
}
|
@ -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 = { };
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
@ -9,6 +9,7 @@ err.file.not.found=file not found: {0}
|
|||||||
err.h.not.supported=-h is no longer available - use the 'javah' program
|
err.h.not.supported=-h is no longer available - use the 'javah' program
|
||||||
err.incompatible.options=bad combination of options: {0}
|
err.incompatible.options=bad combination of options: {0}
|
||||||
err.internal.error=internal error: {0} {1} {2}
|
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.ioerror=IO error reading {0}: {1}
|
||||||
err.missing.arg=no value given for {0}
|
err.missing.arg=no value given for {0}
|
||||||
err.no.classes.specified=no classes specified
|
err.no.classes.specified=no classes specified
|
||||||
@ -16,6 +17,8 @@ err.not.standard.file.manager=can only specify class files when using a standard
|
|||||||
err.unknown.option=unknown option: {0}
|
err.unknown.option=unknown option: {0}
|
||||||
err.verify.not.supported=-verify not supported
|
err.verify.not.supported=-verify not supported
|
||||||
err.Xold.not.supported.here=-Xold must be given as the first option
|
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=\
|
main.usage.summary=\
|
||||||
Usage: {0} <options> <classes>\n\
|
Usage: {0} <options> <classes>\n\
|
||||||
|
116
langtools/test/tools/javap/T6824493.java
Normal file
116
langtools/test/tools/javap/T6824493.java
Normal file
@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user