aboutsummaryrefslogtreecommitdiff
path: root/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jdk/nashorn/internal/ir/debug/NashornClassReader.java')
-rw-r--r--src/jdk/nashorn/internal/ir/debug/NashornClassReader.java551
1 files changed, 551 insertions, 0 deletions
diff --git a/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java b/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
new file mode 100644
index 00000000..87eb18df
--- /dev/null
+++ b/src/jdk/nashorn/internal/ir/debug/NashornClassReader.java
@@ -0,0 +1,551 @@
+/*
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir.debug;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import jdk.internal.org.objectweb.asm.Attribute;
+import jdk.internal.org.objectweb.asm.ClassReader;
+import jdk.internal.org.objectweb.asm.ClassVisitor;
+import jdk.internal.org.objectweb.asm.Label;
+import jdk.nashorn.internal.ir.debug.NashornTextifier.NashornLabel;
+
+/**
+ * Subclass of the ASM classs reader that retains more info, such
+ * as bytecode offsets
+ */
+public class NashornClassReader extends ClassReader {
+
+ private final Map<String, List<Label>> labelMap = new HashMap<>();
+
+ /**
+ * Constructor
+ * @param bytecode bytecode for class
+ */
+ public NashornClassReader(final byte[] bytecode) {
+ super(bytecode);
+ parse(bytecode);
+ }
+
+ List<Label> getExtraLabels(final String className, final String methodName, final String methodDesc) {
+ final String key = fullyQualifiedName(className, methodName, methodDesc);
+ return labelMap.get(key);
+ }
+
+ private static int readByte(final byte[] bytecode, final int index) {
+ return (byte)(bytecode[index] & 0xff);
+ }
+
+ private static int readShort(final byte[] bytecode, final int index) {
+ return (short)((bytecode[index] & 0xff) << 8) | (bytecode[index + 1] & 0xff);
+ }
+
+ private static int readInt(final byte[] bytecode, final int index) {
+ return ((bytecode[index] & 0xff) << 24) | ((bytecode[index + 1] & 0xff) << 16) | ((bytecode[index + 2] & 0xff) << 8) | (bytecode[index + 3] & 0xff);
+ }
+
+ private static long readLong(final byte[] bytecode, final int index) {
+ final int hi = readInt(bytecode, index);
+ final int lo = readInt(bytecode, index + 4);
+ return ((long)hi << 32) | lo;
+ }
+
+ private static String readUTF(final int index, final int utfLen, final byte[] bytecode) {
+ final int endIndex = index + utfLen;
+ final char buf[] = new char[utfLen * 2];
+ int strLen = 0;
+ int c;
+ int st = 0;
+ char cc = 0;
+ int i = index;
+
+ while (i < endIndex) {
+ c = bytecode[i++];
+ switch (st) {
+ case 0:
+ c = c & 0xFF;
+ if (c < 0x80) { // 0xxxxxxx
+ buf[strLen++] = (char) c;
+ } else if (c < 0xE0 && c > 0xBF) { // 110x xxxx 10xx xxxx
+ cc = (char) (c & 0x1F);
+ st = 1;
+ } else { // 1110 xxxx 10xx xxxx 10xx xxxx
+ cc = (char) (c & 0x0F);
+ st = 2;
+ }
+ break;
+
+ case 1: // byte 2 of 2-byte char or byte 3 of 3-byte char
+ buf[strLen++] = (char) ((cc << 6) | (c & 0x3F));
+ st = 0;
+ break;
+
+ case 2: // byte 2 of 3-byte char
+ cc = (char) ((cc << 6) | (c & 0x3F));
+ st = 1;
+ break;
+
+ default:
+ break;
+ }
+ }
+ return new String(buf, 0, strLen);
+ }
+
+ private String parse(final byte[] bytecode) {
+ String thisClassName;
+
+ int u = 0;
+
+ final int magic = readInt(bytecode, u);
+ u += 4; //magic
+ assert magic == 0xcafebabe : Integer.toHexString(magic);
+ readShort(bytecode, u); //minor
+ u += 2;
+ readShort(bytecode, u); //major
+ u += 2; //minor
+
+ final int cpc = readShort(bytecode, u);
+ u += 2;
+ final ArrayList<Constant> cp = new ArrayList<>(cpc);
+ cp.add(null);
+
+ for (int i = 1; i < cpc; i++) {
+ //constant pool entries
+ final int tag = readByte(bytecode, u);
+ u += 1;
+ switch (tag) {
+ case 7: //class
+ cp.add(new IndexInfo(cp, tag, readShort(bytecode, u)));
+ u += 2;
+ break;
+ case 9: //fieldref
+ case 10: //methodref
+ case 11: //interfacemethodref
+ cp.add(new IndexInfo2(cp, tag, readShort(bytecode, u), readShort(bytecode, u + 2)));
+ u += 4;
+ break;
+ case 8: //string
+ cp.add(new IndexInfo(cp, tag, readShort(bytecode, u))); //string index
+ u += 2;
+ break;
+ case 3: //int
+ cp.add(new DirectInfo<>(cp, tag, readInt(bytecode, u)));
+ u += 4;
+ break;
+ case 4: //float
+ cp.add(new DirectInfo<>(cp, tag, Float.intBitsToFloat(readInt(bytecode, u))));
+ u += 4;
+ break;
+ case 5: //long
+ cp.add(new DirectInfo<>(cp, tag, readLong(bytecode, u)));
+ cp.add(null);
+ i++;
+ u += 8;
+ break;
+ case 6: //double
+ cp.add(new DirectInfo<>(cp, tag, Double.longBitsToDouble(readLong(bytecode, u))));
+ cp.add(null);
+ i++;
+ u += 8;
+ break;
+ case 12: //name and type
+ cp.add(new IndexInfo2(cp, tag, readShort(bytecode, u), readShort(bytecode, u + 2)));
+ u += 4;
+ break;
+ case 1: //utf8
+ final int len = readShort(bytecode, u);
+ u += 2;
+ cp.add(new DirectInfo<>(cp, tag, readUTF(u, len, bytecode)));
+ u += len;
+ break;
+ case 16: //methodtype
+ cp.add(new IndexInfo(cp, tag, readShort(bytecode, u)));
+ u += 2;
+ break;
+ case 18: //indy
+ cp.add(new IndexInfo2(cp, tag, readShort(bytecode, u), readShort(bytecode, u + 2)) {
+ @Override
+ public String toString() {
+ return "#" + index + ' ' + cp.get(index2).toString();
+ }
+
+ });
+ u += 4;
+ break;
+ case 15: //methodhandle
+ final int kind = readByte(bytecode, u);
+ assert kind >= 1 && kind <= 9 : kind;
+ cp.add(new IndexInfo2(cp, tag, kind, readShort(bytecode, u + 1)) {
+ @Override
+ public String toString() {
+ return "#" + index + ' ' + cp.get(index2).toString();
+ }
+ });
+
+ u += 3;
+ break;
+ default:
+ assert false : tag;
+ break;
+ }
+ }
+
+ readShort(bytecode, u); //access flags
+ u += 2; //access
+ final int cls = readShort(bytecode, u);
+ u += 2; //this_class
+ thisClassName = cp.get(cls).toString();
+ u += 2; //super
+
+ final int ifc = readShort(bytecode, u);
+ u += 2;
+ u += ifc * 2;
+
+ final int fc = readShort(bytecode, u);
+ u += 2; //fields
+
+ for (int i = 0 ; i < fc ; i++) {
+ u += 2; //access
+ readShort(bytecode, u); //fieldname
+ u += 2; //name
+ u += 2; //descriptor
+ final int ac = readShort(bytecode, u);
+ u += 2;
+ //field attributes
+ for (int j = 0; j < ac; j++) {
+ u += 2; //attribute name
+ final int len = readInt(bytecode, u);
+ u += 4;
+ u += len;
+ }
+ }
+
+ final int mc = readShort(bytecode, u);
+ u += 2;
+ for (int i = 0 ; i < mc ; i++) {
+ readShort(bytecode, u);
+ u += 2; //access
+
+ final int methodNameIndex = readShort(bytecode, u);
+ u += 2;
+ final String methodName = cp.get(methodNameIndex).toString();
+
+ final int methodDescIndex = readShort(bytecode, u);
+ u += 2;
+ final String methodDesc = cp.get(methodDescIndex).toString();
+
+ final int ac = readShort(bytecode, u);
+ u += 2;
+
+ //method attributes
+ for (int j = 0; j < ac; j++) {
+ final int nameIndex = readShort(bytecode, u);
+ u += 2;
+ final String attrName = cp.get(nameIndex).toString();
+
+ final int attrLen = readInt(bytecode, u);
+ u += 4;
+
+ if ("Code".equals(attrName)) {
+ readShort(bytecode, u);
+ u += 2; //max stack
+ readShort(bytecode, u);
+ u += 2; //max locals
+ final int len = readInt(bytecode, u);
+ u += 4;
+ parseCode(bytecode, u, len, fullyQualifiedName(thisClassName, methodName, methodDesc));
+ u += len;
+ final int elen = readShort(bytecode, u); //exception table length
+ u += 2;
+ u += elen * 8;
+
+ //method attributes
+ final int ac2 = readShort(bytecode, u);
+ u += 2;
+ for (int k = 0; k < ac2; k++) {
+ u += 2; //name;
+ final int aclen = readInt(bytecode, u);
+ u += 4; //length
+ u += aclen; //bytes;
+ }
+ } else {
+ u += attrLen;
+ }
+ }
+ }
+
+ final int ac = readShort(bytecode, u);
+ u += 2;
+ //other attributes
+ for (int i = 0 ; i < ac ; i++) {
+ readShort(bytecode, u); //name index
+ u += 2;
+ final int len = readInt(bytecode, u);
+ u += 4;
+ u += len;
+ //attribute
+ }
+
+ return thisClassName;
+ }
+
+ private static String fullyQualifiedName(final String className, final String methodName, final String methodDesc) {
+ return className + '.' + methodName + methodDesc;
+ }
+
+ private void parseCode(final byte[] bytecode, final int index, final int len, final String desc) {
+ final List<Label> labels = new ArrayList<>();
+ labelMap.put(desc, labels);
+
+ boolean wide = false;
+
+ for (int i = index; i < index + len;) {
+ final int opcode = bytecode[i];
+ labels.add(new NashornLabel(opcode, i - index));
+
+ switch (opcode & 0xff) {
+ case 0xc4: //wide
+ wide = true;
+ i += 1;
+ break;
+ case 0xa9: //ret
+ i += wide ? 4 : 2;
+ break;
+ case 0xab: //lookupswitch
+ i += 1;
+ while (((i - index) & 3) != 0) {
+ i++;
+ }
+ readInt(bytecode, i);
+ i += 4; //defaultbyte
+ final int npairs = readInt(bytecode, i);
+ i += 4;
+ i += 8 * npairs;
+ break;
+ case 0xaa: //tableswitch
+ i += 1;
+ while (((i - index) & 3) != 0) {
+ i++;
+ }
+ readInt(bytecode, i); //default
+ i += 4;
+ final int lo = readInt(bytecode, i);
+ i += 4;
+ final int hi = readInt(bytecode, i);
+ i += 4;
+ i += 4 * (hi - lo + 1);
+ break;
+ case 0xc5: //multianewarray
+ i += 4;
+ break;
+ case 0x19: //aload (wide)
+ case 0x18: //dload
+ case 0x17: //fload
+ case 0x15: //iload
+ case 0x16: //lload
+ case 0x3a: //astore wide
+ case 0x39: //dstore
+ case 0x38: //fstore
+ case 0x36: //istore
+ case 0x37: //lstore
+ i += wide ? 3 : 2;
+ break;
+ case 0x10: //bipush
+ case 0x12: //ldc
+ case 0xbc: //anewarrayu
+ i += 2;
+ break;
+ case 0xb4: //getfield
+ case 0xb2: //getstatic
+ case 0xbd: //anewarray
+ case 0xc0: //checkcast
+ case 0xa5: //ifacmp_eq
+ case 0xa6: //ifacmp_ne
+ case 0x9f: //all ifs and ifcmps
+ case 0xa0:
+ case 0xa1:
+ case 0xa2:
+ case 0xa3:
+ case 0xa4:
+ case 0x99:
+ case 0x9a:
+ case 0x9b:
+ case 0x9c:
+ case 0x9d:
+ case 0x9e:
+ case 0xc7:
+ case 0xc6:
+ case 0xc1: //instanceof
+ case 0xa7: //goto
+ case 0xb7: //special
+ case 0xb8: //static
+ case 0xb6: //virtual
+ case 0xa8: //jsr
+ case 0x13: //ldc_w
+ case 0x14: //ldc2_w
+ case 0xbb: //new
+ case 0xb5: //putfield
+ case 0xb3: //putstatic
+ case 0x11: //sipush
+ i += 3;
+ break;
+ case 0x84: //iinc (wide)
+ i += wide ? 5 : 3;
+ break;
+ case 0xba: //indy
+ case 0xb9: //interface
+ case 0xc8:
+ case 0xc9: //jsr_w
+ i += 5; //goto_w
+ break;
+ default:
+ i++;
+ break;
+ }
+
+ if (wide) {
+ wide = false;
+ }
+ }
+ }
+
+ @Override
+ public void accept(final ClassVisitor classVisitor, final Attribute[] attrs, final int flags) {
+ super.accept(classVisitor, attrs, flags);
+ }
+
+ @Override
+ protected Label readLabel(final int offset, final Label[] labels) {
+ final Label label = super.readLabel(offset, labels);
+ label.info = offset;
+ return label;
+ }
+
+ private abstract static class Constant {
+ protected ArrayList<Constant> cp;
+ protected int tag;
+ protected Constant(final ArrayList<Constant> cp, final int tag) {
+ this.cp = cp;
+ this.tag = tag;
+ }
+
+ @SuppressWarnings("unused")
+ final String getType() {
+ String str = type[tag];
+ while (str.length() < 16) {
+ str += " ";
+ }
+ return str;
+ }
+ }
+
+ private static class IndexInfo extends Constant {
+ protected final int index;
+
+ IndexInfo(final ArrayList<Constant> cp, final int tag, final int index) {
+ super(cp, tag);
+ this.index = index;
+ }
+
+ @Override
+ public String toString() {
+ return cp.get(index).toString();
+ }
+ }
+
+ private static class IndexInfo2 extends IndexInfo {
+ protected final int index2;
+
+ IndexInfo2(final ArrayList<Constant> cp, final int tag, final int index, final int index2) {
+ super(cp, tag, index);
+ this.index2 = index2;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString() + ' ' + cp.get(index2).toString();
+ }
+ }
+
+ private static class DirectInfo<T> extends Constant {
+ protected final T info;
+
+ DirectInfo(final ArrayList<Constant> cp, final int tag, final T info) {
+ super(cp, tag);
+ this.info = info;
+ }
+
+ @Override
+ public String toString() {
+ return info.toString();// + " [class=" + info.getClass().getSimpleName() + ']';
+ }
+ }
+
+ private static String type[] = {
+ //0
+ "<error>",
+ //1
+ "UTF8",
+ //2
+ "<error>",
+ //3
+ "Integer",
+ //4
+ "Float",
+ //5
+ "Long",
+ //6
+ "Double",
+ //7
+ "Class",
+ //8
+ "String",
+ //9
+ "Fieldref",
+ //10
+ "Methodref",
+ //11
+ "InterfaceMethodRef",
+ //12
+ "NameAndType",
+ //13
+ "<error>",
+ //14
+ "<error>",
+ //15
+ "MethodHandle",
+ //16
+ "MethodType",
+ //17
+ "<error>",
+ //18
+ "Invokedynamic"
+ };
+
+}