⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 classreader.java

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/***
 * ASM: a very small and fast Java bytecode manipulation framework
 * Copyright (c) 2000,2002,2003 INRIA, France Telecom
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holders nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.objectweb.asm153;

import java.io.InputStream;
import java.io.IOException;

/**
 * A Java class parser to make a {@link ClassVisitor ClassVisitor} visit an
 * existing class. This class parses a byte array conforming to the Java class
 * file format and calls the appropriate visit methods of a given class visitor
 * for each field, method and bytecode instruction encountered.
 * 
 * @author Eric Bruneton
 */

public class ClassReader {

  /**
   * The class to be parsed. <i>The content of this array must not be
   * modified. This field is intended for {@link Attribute} sub classes, and is
   * normally not needed by class generators or adapters.</i>
   */

  public final byte[] b;

  /**
   * The start index of each constant pool item in {@link #b b}, plus one. The
   * one byte offset skips the constant pool item tag that indicates its type.
   */

  private int[] items;

  /**
   * The String objects corresponding to the CONSTANT_Utf8 items. This cache
   * avoids multiple parsing of a given CONSTANT_Utf8 constant pool item, which
   * GREATLY improves performances (by a factor 2 to 3). This caching strategy
   * could be extended to all constant pool items, but its benefit would not be
   * so great for these items (because they are much less expensive to parse
   * than CONSTANT_Utf8 items).
   */

  private String[] strings;

  /**
   * Maximum length of the strings contained in the constant pool of the class.
   */

  private int maxStringLength;

  /**
   * Start index of the class header information (access, name...) in {@link #b
   * b}.
   */

  private int header;

  // --------------------------------------------------------------------------
  // Constructors
  // --------------------------------------------------------------------------

  /**
   * Constructs a new {@link ClassReader ClassReader} object.
   *
   * @param b the bytecode of the class to be read.
   */

  public ClassReader (final byte[] b) {
    this(b, 0, b.length);
  }

  /**
   * Constructs a new {@link ClassReader ClassReader} object.
   *
   * @param b the bytecode of the class to be read.
   * @param off the start offset of the class data.
   * @param len the length of the class data.
   */

  public ClassReader (final byte[] b, final int off, final int len) {
    this.b = b;
    // parses the constant pool
    items = new int[readUnsignedShort(off + 8)];
    strings = new String[items.length];
    int max = 0;
    int index = off + 10;
    for (int i = 1; i < items.length; ++i) {
      items[i] = index + 1;
      int tag = b[index];
      int size;
      switch (tag) {
        case ClassWriter.FIELD:
        case ClassWriter.METH:
        case ClassWriter.IMETH:
        case ClassWriter.INT:
        case ClassWriter.FLOAT:
        case ClassWriter.NAME_TYPE:
          size = 5;
          break;
        case ClassWriter.LONG:
        case ClassWriter.DOUBLE:
          size = 9;
          ++i;
          break;
        case ClassWriter.UTF8:
          size = 3 + readUnsignedShort(index + 1);
          max = (size > max ? size : max);
          break;
        //case ClassWriter.CLASS:
        //case ClassWriter.STR:
        default:
          size = 3;
          break;
      }
      index += size;
    }
    maxStringLength = max;
    // the class header information starts just after the constant pool
    header = index;
  }

  /**
   * Constructs a new {@link ClassReader ClassReader} object.
   *
   * @param is an input stream from which to read the class.
   * @throws IOException if a problem occurs during reading.
   */

  public ClassReader (final InputStream is) throws IOException {
    this(readClass(is));
  }

  /**
   * Constructs a new {@link ClassReader ClassReader} object.
   *
   * @param name the fully qualified name of the class to be read.
   * @throws IOException if an exception occurs during reading.
   */

  public ClassReader (final String name) throws IOException {
    this(ClassLoader.getSystemResourceAsStream(name.replace('.','/') + ".class"));
  }

  /**
   * Reads the bytecode of a class.
   *
   * @param is an input stream from which to read the class.
   * @return the bytecode read from the given input stream.
   * @throws IOException if a problem occurs during reading.
   */

  private static byte[] readClass (final InputStream is) throws IOException {
    if (is == null) {
      throw new IOException("Class not found");
    }
    byte[] b = new byte[is.available()];
    int len = 0;
    while (true) {
      int n = is.read(b, len, b.length - len);
      if (n == -1) {
        if (len < b.length) {
          byte[] c = new byte[len];
          System.arraycopy(b, 0, c, 0, len);
          b = c;
        }
        return b;
      } else {
        len += n;
        if (len == b.length) {
          byte[] c = new byte[b.length + 1000];
          System.arraycopy(b, 0, c, 0, len);
          b = c;
        }
      }
    }
  }

  // --------------------------------------------------------------------------
  // Public methods
  // --------------------------------------------------------------------------

  /**
   * Makes the given visitor visit the Java class of this {@link ClassReader
   * ClassReader}. This class is the one specified in the constructor (see
   * {@link #ClassReader(byte[]) ClassReader}).
   *
   * @param classVisitor the visitor that must visit this class.
   * @param skipDebug <tt>true</tt> if the debug information of the class must
   *      not be visited. In this case the {@link CodeVisitor#visitLocalVariable
   *      visitLocalVariable} and {@link CodeVisitor#visitLineNumber
   *      visitLineNumber} methods will not be called.
   */

  public void accept (
    final ClassVisitor classVisitor,
    final boolean skipDebug)
  {
    accept(classVisitor, new Attribute[0], skipDebug);
  }

  /**
   * Makes the given visitor visit the Java class of this {@link ClassReader
   * ClassReader}. This class is the one specified in the constructor (see
   * {@link #ClassReader(byte[]) ClassReader}).
   *
   * @param classVisitor the visitor that must visit this class.
   * @param attrs prototypes of the attributes that must be parsed during the
   *      visit of the class. Any attribute whose type is not equal to the type
   *      of one the prototypes will be ignored.
   * @param skipDebug <tt>true</tt> if the debug information of the class must
   *      not be visited. In this case the {@link CodeVisitor#visitLocalVariable
   *      visitLocalVariable} and {@link CodeVisitor#visitLineNumber
   *      visitLineNumber} methods will not be called.
   */

  public void accept (
    final ClassVisitor classVisitor,
    final Attribute[] attrs,
    final boolean skipDebug)
  {
    byte[] b = this.b;                     // the bytecode array
    char[] c = new char[maxStringLength];  // buffer used to read strings
    int i, j, k;                           // loop variables
    int u, v, w;                           // indexes in b
    Attribute attr;

    // visits the header
    u = header;
    int version = readInt(4);
    int access = readUnsignedShort(u);
    String className = readClass(u + 2, c);
    v = items[readUnsignedShort(u + 4)];
    String superClassName = v == 0 ? null : readUTF8(v, c);
    String[] implementedItfs = new String[readUnsignedShort(u + 6)];
    String sourceFile = null;
    Attribute clattrs = null;
    w = 0;
    u += 8;
    for (i = 0; i < implementedItfs.length; ++i) {
      implementedItfs[i] = readClass(u, c); u += 2;
    }
    // skips fields and methods
    v = u;
    i = readUnsignedShort(v); v += 2;
    for ( ; i > 0; --i) {
      j = readUnsignedShort(v + 6);
      v += 8;
      for ( ; j > 0; --j) {
        v += 6 + readInt(v + 2);
      }
    }
    i = readUnsignedShort(v); v += 2;
    for ( ; i > 0; --i) {
      j = readUnsignedShort(v + 6);
      v += 8;
      for ( ; j > 0; --j) {
        v += 6 + readInt(v + 2);
      }
    }
    // reads the class's attributes
    i = readUnsignedShort(v); v += 2;
    for ( ; i > 0; --i) {
      String attrName = readUTF8(v, c);
      if (attrName.equals("SourceFile")) {
        sourceFile = readUTF8(v + 6, c);
      } else if (attrName.equals("Deprecated")) {
        access |= Constants.ACC_DEPRECATED;
      } else if (attrName.equals("Synthetic")) {
        access |= Constants.ACC_SYNTHETIC;
      } else if (attrName.equals("InnerClasses")) {
        w = v + 6;
      } else {
        attr = readAttribute(
            attrs, attrName, v + 6, readInt(v + 2), c, -1, null);
        if (attr != null) {
          attr.next = clattrs;
          clattrs = attr;
        }
      }
      v += 6 + readInt(v + 2);
    }
    // calls the visit method
    classVisitor.visit(
      version, access, className, superClassName, implementedItfs, sourceFile);

    // visits the inner classes info
    if (w != 0) {
      i = readUnsignedShort(w); w += 2;
      for ( ; i > 0; --i) {
        classVisitor.visitInnerClass(
          readUnsignedShort(w) == 0 ? null : readClass(w, c),
          readUnsignedShort(w + 2) == 0 ? null : readClass(w + 2, c),
          readUnsignedShort(w + 4) == 0 ? null : readUTF8(w + 4, c),
          readUnsignedShort(w + 6));
        w += 8;
      }
    }

    // visits the fields
    i = readUnsignedShort(u); u += 2;
    for ( ; i > 0; --i) {
      access = readUnsignedShort(u);
      String fieldName = readUTF8(u + 2, c);
      String fieldDesc = readUTF8(u + 4, c);
      Attribute fattrs = null;
      // visits the field's attributes and looks for a ConstantValue attribute
      int fieldValueItem = 0;
      j = readUnsignedShort(u + 6);
      u += 8;
      for ( ; j > 0; --j) {
        String attrName = readUTF8(u, c);
        if (attrName.equals("ConstantValue")) {
          fieldValueItem = readUnsignedShort(u + 6);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -