Package org.springsource.loaded

Source Code of org.springsource.loaded.ConstantPoolChecker2$References

/*
* Copyright 2010-2012 VMware and contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springsource.loaded;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

// TODO try to recall why I created ConstantPoolChecker2, what was up with ConstantPoolChecker?

// http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html
/**
* Enables us to check things quickly in the constant pool. This version accumulates the class references and the method references,
* for classes that start with 'j' (we want to catch: java/lang). It skips everything it can and the end result is a list of class
* references and a list of method references. The former look like this 'a/b/C' whilst the latter look like this
* 'java/lang/Foo.bar' (the descriptor for the method is not included). Interface methods are skipped.
*
* @author Andy Clement
* @since 0.7.3
*/
public class ConstantPoolChecker2 {

  private static final boolean DEBUG = false;

  private final static byte CONSTANT_Utf8 = 1;
  private final static byte CONSTANT_Integer = 3;
  private final static byte CONSTANT_Float = 4;
  private final static byte CONSTANT_Long = 5;
  private final static byte CONSTANT_Double = 6;
  private final static byte CONSTANT_Class = 7;
  private final static byte CONSTANT_String = 8;
  private final static byte CONSTANT_Fieldref = 9;
  private final static byte CONSTANT_Methodref = 10;
  private final static byte CONSTANT_InterfaceMethodref = 11;
  private final static byte CONSTANT_NameAndType = 12;

  // Test entry point just goes through all the code in the bin folder
  public static void main(String[] args) throws Exception {
    File[] fs = new File("./bin").listFiles();
    //    File[] fs = new File("../testdata-groovy/bin").listFiles();
    //    File[] fs = new File("/Users/aclement/grailsreload/foo/target/classes").listFiles();

    checkThemAll(fs);
    System.out.println("total=" + total / 1000000d);
  }

  private static void checkThemAll(File[] fs) throws Exception {
    for (File f : fs) {
      if (f.isDirectory()) {
        checkThemAll(f.listFiles());
      } else if (f.getName().endsWith(".class")) {
        System.out.println(f);
        byte[] data = Utils.loadFromStream(new FileInputStream(f));
        long stime = System.nanoTime();
        References refs = getReferences(data);
        total += (System.nanoTime() - stime);
        System.out.println(refs.referencedClasses);
        System.out.println(refs.referencedMethods);
      }
    }
  }

  static long total = 0;

  //  ClassFile {
  //      u4 magic;
  //      u2 minor_version;
  //      u2 major_version;
  //      u2 constant_pool_count;
  //      cp_info constant_pool[constant_pool_count-1];
  //      u2 access_flags;
  //      u2 this_class;
  //      u2 super_class;
  //      u2 interfaces_count;
  //      u2 interfaces[interfaces_count];
  //      u2 fields_count;
  //      field_info fields[fields_count];
  //      u2 methods_count;
  //      method_info methods[methods_count];
  //      u2 attributes_count;
  //      attribute_info attributes[attributes_count];
  //    }

  static References getReferences(byte[] bytes) {
    ConstantPoolChecker2 cpc2 = new ConstantPoolChecker2(bytes);
    return new References(cpc2.slashedclassname, cpc2.referencedClasses, cpc2.referencedMethods);
  }

  static class References {
    String slashedClassName;
    List<String> referencedClasses;
    List<String> referencedMethods;

    References(String slashedClassName, List<String> rc, List<String> rm) {
      this.slashedClassName = slashedClassName;
      this.referencedClasses = rc;
      this.referencedMethods = rm;
    }
  }

  // Filled with strings and int[]
  private Object[] cpdata;
  private int cpsize;
  private int[] type;
  // Does not need to be a set as there are no dups in the ConstantPool (for a class from a decent compiler...)
  private List<String> referencedClasses = new ArrayList<String>();
  private List<String> referencedMethods = new ArrayList<String>();
  private String slashedclassname;

  private ConstantPoolChecker2(byte[] bytes) {
    readConstantPool(bytes);
    computeReferences();
  }

  public void computeReferences() {
    for (int i = 0; i < cpsize; i++) {
      switch (type[i]) {
      case CONSTANT_Class:
        int classindex = ((Integer) cpdata[i]);
        String classname = (String) cpdata[classindex];
        if (classname == null) {
          throw new IllegalStateException();
        }
        referencedClasses.add(classname);
        break;
      case CONSTANT_Methodref:
        int[] indexes = (int[]) cpdata[i];
        int classindex2 = indexes[0];
        int nameAndTypeIndex = indexes[1];
        StringBuilder s = new StringBuilder();
        String theClassName = (String) cpdata[(Integer) cpdata[classindex2]];
        if (theClassName.charAt(0) == 'j') {
          s.append(theClassName);
          s.append(".");
          s.append((String) cpdata[(Integer) cpdata[nameAndTypeIndex]]);
          referencedMethods.add(s.toString());
        }
        break;
      //      private final static byte CONSTANT_Utf8 = 1;
      //      private final static byte CONSTANT_Integer = 3;
      //      private final static byte CONSTANT_Float = 4;
      //      private final static byte CONSTANT_Long = 5;
      //      private final static byte CONSTANT_Double = 6;
      //      private final static byte CONSTANT_String = 8;
      //      private final static byte CONSTANT_Fieldref = 9;
      //      private final static byte CONSTANT_InterfaceMethodref = 11;
      //      private final static byte CONSTANT_NameAndType = 12;
      }
    }
  }

  public void readConstantPool(byte[] bytes) {
    try {
      ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
      DataInputStream dis = new DataInputStream(bais);

      int magic = dis.readInt(); // magic 0xCAFEBABE
      if (magic != 0xCAFEBABE) {
        throw new IllegalStateException("not bytecode, magic was 0x" + Integer.toString(magic, 16));
      }
      dis.skip(4); // skip minor and major versions
      cpsize = dis.readShort();
      if (DEBUG) {
        System.out.println("Constant Pool Size =" + cpsize);
      }
      cpdata = new Object[cpsize];
      type = new int[cpsize];
      for (int cpentry = 1; cpentry < cpsize; cpentry++) {
        boolean doubleSlot = processConstantPoolEntry(cpentry, dis);
        if (doubleSlot) {
          cpentry++;
        }
      }
      dis.skip(2); // access flags
      int thisclassname = dis.readShort();
      int classindex = ((Integer) cpdata[thisclassname]);
      slashedclassname = (String) cpdata[classindex];
    } catch (Exception e) {
      throw new IllegalStateException("Unexpected problem processing bytes for class", e);
    }
  }

  private boolean processConstantPoolEntry(int index, DataInputStream dis) throws IOException {
    byte b = dis.readByte();
    switch (b) {
    case CONSTANT_Utf8:
      // CONSTANT_Utf8_info { u1 tag; u2 length; u1 bytes[length]; }
      cpdata[index] = dis.readUTF();
      //      type[index] = b;
      if (DEBUG) {
        System.out.println(index + ":UTF8[" + cpdata[index] + "]");
      }
      break;
    case CONSTANT_Integer:
      // CONSTANT_Integer_info { u1 tag; u4 bytes; }
      if (DEBUG) {
        int i = dis.readInt();
        if (DEBUG) {
          System.out.println(index + ":INTEGER[" + i + "]");
        }
      } else {
        dis.skip(4);
      }
      break;
    case CONSTANT_Float:
      // CONSTANT_Float_info { u1 tag; u4 bytes; }
      if (DEBUG) {
        float f = dis.readFloat();
        if (DEBUG) {
          System.out.println(index + ":FLOAT[" + f + "]");
        }
      } else {
        dis.skip(4);
      }
      break;
    case CONSTANT_Long:
      //    CONSTANT_Long_info {
      //        u1 tag;
      //        u4 high_bytes;
      //        u4 low_bytes;
      //      }
      if (DEBUG) {
        long l = dis.readLong();
        if (DEBUG) {
          System.out.println(index + ":LONG[" + l + "]");
        }
      } else {
        dis.skip(8);
      }
      return true;
    case CONSTANT_Double:
      //      CONSTANT_Double_info {
      //        u1 tag;
      //        u4 high_bytes;
      //        u4 low_bytes;
      //      }
      if (DEBUG) {
        double d = dis.readDouble();
        if (DEBUG) {
          System.out.println(index + ":DOUBLE[" + d + "]");
        }
      } else {
        dis.skip(8);
      }
      return true;
    case CONSTANT_Class:
      // CONSTANT_Class_info { u1 tag; u2 name_index; }
      type[index] = b;
      cpdata[index] = (int) dis.readShort();
      if (DEBUG) {
        System.out.println(index + ":CLASS[name_index=" + cpdata[index] + "]");
      }
      break;
    case CONSTANT_String:
      // CONSTANT_String_info { u1 tag; u2 string_index; }
      if (DEBUG) {
        cpdata[index] = (int) dis.readShort();
        if (DEBUG) {
          System.out.println(index + ":STRING[string_index=" + cpdata[index] + "]");
        }
      } else {
        dis.skip(2);
      }
      break;
    case CONSTANT_Fieldref:
      // CONSTANT_Fieldref_info { u1 tag; u2 class_index; u2 name_and_type_index; }
      if (DEBUG) {
        cpdata[index] = new int[] { dis.readShort(), dis.readShort() };
        if (DEBUG) {
          System.out.println(index + ":FIELDREF[class_index=" + ((int[]) cpdata[index])[0] + ",name_and_type_index="
              + ((int[]) cpdata[index])[1] + "]");
        }
      } else {
        dis.skip(4);
      }
      break;
    case CONSTANT_Methodref:
      // CONSTANT_Methodref_info { u1 tag; u2 class_index; u2 name_and_type_index; } 
      type[index] = b;
      //if (DEBUG) {
      cpdata[index] = new int[] { dis.readShort(), dis.readShort() };
      if (DEBUG) {
        System.out.println(index + ":METHODREF[class_index=" + ((int[]) cpdata[index])[0] + ",name_and_type_index="
            + ((int[]) cpdata[index])[1] + "]");
      }
      //      } else {
      //        dis.skip(4);
      //      }
      break;
    case CONSTANT_InterfaceMethodref:
      //       CONSTANT_InterfaceMethodref_info {
      //            u1 tag;
      //            u2 class_index;
      //            u2 name_and_type_index;
      //          }
      if (DEBUG) {
        cpdata[index] = new int[] { dis.readShort(), dis.readShort() };
        if (DEBUG) {
          System.out.println(index + ":INTERFACEMETHODREF[class_index=" + ((int[]) cpdata[index])[0]
              + ",name_and_type_index=" + ((int[]) cpdata[index])[1] + "]");
        }
      } else {
        dis.skip(4);
      }
      break;
    case CONSTANT_NameAndType:
      // The CONSTANT_NameAndType_info structure is used to represent a field or method, without indicating which class or interface type it belongs to:
      // CONSTANT_NameAndType_info { u1 tag; u2 name_index; u2 descriptor_index; }
      //      type[index] = b;
      cpdata[index] = (int) dis.readShort();// new int[] { dis.readShort(), dis.readShort() };
      dis.skip(2); // skip the descriptor for now
      if (DEBUG) {
        System.out.println(index + ":NAMEANDTYPE[name_index=" + ((int[]) cpdata[index])[0] + ",descriptor_index="
            + ((int[]) cpdata[index])[1] + "]");
      }
      break;
    default:
      throw new IllegalStateException("Entry: " + index + " " + Byte.toString(b));
    }
    return false;
  }
}
TOP

Related Classes of org.springsource.loaded.ConstantPoolChecker2$References

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.