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

📄 codewriter.java

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
   *      <tt>i & 0x03</tt>).
   */

  private static int getArgumentsAndReturnSizes (final String desc) {
    int n = 1;
    int c = 1;
    while (true) {
      char car = desc.charAt(c++);
      if (car == ')') {
        car = desc.charAt(c);
        return n << 2 | (car == 'V' ? 0 : (car == 'D' || car == 'J' ? 2 : 1));
      } else if (car == 'L') {
        while (desc.charAt(c++) != ';') {
        }
        n += 1;
      } else if (car == '[') {
        while ((car = desc.charAt(c)) == '[') {
          ++c;
        }
        if (car == 'D' || car == 'J') {
          n -= 1;
        }
      } else if (car == 'D' || car == 'J') {
        n += 2;
      } else {
        n += 1;
      }
    }
  }

  /**
   * Adds a successor to the {@link #currentBlock currentBlock} block.
   *
   * @param stackSize the current (relative) stack size in the current block.
   * @param successor the successor block to be added to the current block.
   */

  private void addSuccessor (final int stackSize, final Label successor) {
    Edge b;
    // creates a new Edge object or reuses one from the shared pool
    synchronized (SIZE) {
      if (pool == null) {
        b = new Edge();
      } else {
        b = pool;
        // removes b from the pool
        pool = pool.poolNext;
      }
    }
    // adds the previous Edge to the list of Edges used by this CodeWriter
    if (tail == null) {
      tail = b;
    }
    b.poolNext = head;
    head = b;
    // initializes the previous Edge object...
    b.stackSize = stackSize;
    b.successor = successor;
    // ...and adds it to the successor list of the currentBlock block
    b.next = currentBlock.successors;
    currentBlock.successors = b;
  }

  // --------------------------------------------------------------------------
  // Utility methods: dump bytecode array
  // --------------------------------------------------------------------------

  /**
   * Returns the size of the bytecode of this method.
   *
   * @return the size of the bytecode of this method.
   */

  final int getSize () {
    if (resize) {
      // replaces the temporary jump opcodes introduced by Label.resolve.
      resizeInstructions(new int[0], new int[0], 0);
    }
    int size = 8;
    if (code.length > 0) {
      cw.newUTF8("Code");
      size += 18 + code.length + 8 * catchCount;
      if (localVar != null) {
        size += 8 + localVar.length;
      }
      if (lineNumber != null) {
        size += 8 + lineNumber.length;
      }
      if (cattrs != null) {
        size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals);
      }
    }
    if (exceptionCount > 0) {
      cw.newUTF8("Exceptions");
      size += 8 + 2 * exceptionCount;
    }
    if ((access & Constants.ACC_SYNTHETIC) != 0) {
      cw.newUTF8("Synthetic");
      size += 6;
    }
    if ((access & Constants.ACC_DEPRECATED) != 0) {
      cw.newUTF8("Deprecated");
      size += 6;
    }
    if (attrs != null) {
      size += attrs.getSize(cw, null, 0, -1, -1);
    }
    return size;
  }

  /**
   * Puts the bytecode of this method in the given byte vector.
   *
   * @param out the byte vector into which the bytecode of this method must be
   *      copied.
   */

  final void put (final ByteVector out) {
    out.putShort(access).putShort(name).putShort(desc);
    int attributeCount = 0;
    if (code.length > 0) {
      ++attributeCount;
    }
    if (exceptionCount > 0) {
      ++attributeCount;
    }
    if ((access & Constants.ACC_SYNTHETIC) != 0) {
      ++attributeCount;
    }
    if ((access & Constants.ACC_DEPRECATED) != 0) {
      ++attributeCount;
    }
    if (attrs != null) {
      attributeCount += attrs.getCount();
    }
    out.putShort(attributeCount);
    if (code.length > 0) {
      int size = 12 + code.length + 8 * catchCount;
      if (localVar != null) {
        size += 8 + localVar.length;
      }
      if (lineNumber != null) {
        size += 8 + lineNumber.length;
      }
      if (cattrs != null) {
        size += cattrs.getSize(cw, code.data, code.length, maxStack, maxLocals);
      }
      out.putShort(cw.newUTF8("Code")).putInt(size);
      out.putShort(maxStack).putShort(maxLocals);
      out.putInt(code.length).putByteArray(code.data, 0, code.length);
      out.putShort(catchCount);
      if (catchCount > 0) {
        out.putByteArray(catchTable.data, 0, catchTable.length);
      }
      attributeCount = 0;
      if (localVar != null) {
        ++attributeCount;
      }
      if (lineNumber != null) {
        ++attributeCount;
      }
      if (cattrs != null) {
        attributeCount += cattrs.getCount();
      }
      out.putShort(attributeCount);
      if (localVar != null) {
        out.putShort(cw.newUTF8("LocalVariableTable"));
        out.putInt(localVar.length + 2).putShort(localVarCount);
        out.putByteArray(localVar.data, 0, localVar.length);
      }
      if (lineNumber != null) {
        out.putShort(cw.newUTF8("LineNumberTable"));
        out.putInt(lineNumber.length + 2).putShort(lineNumberCount);
        out.putByteArray(lineNumber.data, 0, lineNumber.length);
      }
      if (cattrs != null) {
        cattrs.put(cw, code.data, code.length, maxLocals, maxStack, out);
      }
    }
    if (exceptionCount > 0) {
      out.putShort(cw.newUTF8("Exceptions")).putInt(2 * exceptionCount + 2);
      out.putShort(exceptionCount);
      for (int i = 0; i < exceptionCount; ++i) {
        out.putShort(exceptions[i]);
      }
    }
    if ((access & Constants.ACC_SYNTHETIC) != 0) {
      out.putShort(cw.newUTF8("Synthetic")).putInt(0);
    }
    if ((access & Constants.ACC_DEPRECATED) != 0) {
      out.putShort(cw.newUTF8("Deprecated")).putInt(0);
    }
    if (attrs != null) {
      attrs.put(cw, null, 0, -1, -1, out);
    }
  }

  // --------------------------------------------------------------------------
  // Utility methods: instruction resizing (used to handle GOTO_W and JSR_W)
  // --------------------------------------------------------------------------

  /**
   * Resizes the designated instructions, while keeping jump offsets and
   * instruction addresses consistent. This may require to resize other existing
   * instructions, or even to introduce new instructions: for example,
   * increasing the size of an instruction by 2 at the middle of a method can
   * increases the offset of an IFEQ instruction from 32766 to 32768, in which
   * case IFEQ 32766 must be replaced with IFNEQ 8 GOTO_W 32765. This, in turn,
   * may require to increase the size of another jump instruction, and so on...
   * All these operations are handled automatically by this method.
   * <p>
   * <i>This method must be called after all the method that is being built has
   * been visited</i>. In particular, the {@link Label Label} objects used to
   * construct the method are no longer valid after this method has been called.
   *
   * @param indexes current positions of the instructions to be resized. Each
   *      instruction must be designated by the index of its <i>last</i> byte,
   *      plus one (or, in other words, by the index of the <i>first</i> byte of
   *      the <i>next</i> instruction).
   * @param sizes the number of bytes to be <i>added</i> to the above
   *      instructions. More precisely, for each i &lt; <tt>len</tt>,
   *      <tt>sizes</tt>[i] bytes will be added at the end of the instruction
   *      designated by <tt>indexes</tt>[i] or, if <tt>sizes</tt>[i] is
   *      negative, the <i>last</i> |<tt>sizes[i]</tt>| bytes of the instruction
   *      will be removed (the instruction size <i>must not</i> become negative
   *      or null). The gaps introduced by this method must be filled in
   *      "manually" in the array returned by the {@link #getCode getCode}
   *      method.
   * @param len the number of instruction to be resized. Must be smaller than or
   *      equal to <tt>indexes</tt>.length and <tt>sizes</tt>.length.
   * @return the <tt>indexes</tt> array, which now contains the new positions of
   *      the resized instructions (designated as above).
   */

  protected int[] resizeInstructions (
    final int[] indexes,
    final int[] sizes,
    final int len)
  {
    byte[] b = code.data; // bytecode of the method
    int u, v, label;      // indexes in b
    int i, j;             // loop indexes

    // 1st step:
    // As explained above, resizing an instruction may require to resize another
    // one, which may require to resize yet another one, and so on. The first
    // step of the algorithm consists in finding all the instructions that
    // need to be resized, without modifying the code. This is done by the
    // following "fix point" algorithm:
    // - parse the code to find the jump instructions whose offset will need
    //   more than 2 bytes to be stored (the future offset is computed from the
    //   current offset and from the number of bytes that will be inserted or
    //   removed between the source and target instructions). For each such
    //   instruction, adds an entry in (a copy of) the indexes and sizes arrays
    //   (if this has not already been done in a previous iteration!)
    // - if at least one entry has been added during the previous step, go back
    //   to the beginning, otherwise stop.
    // In fact the real algorithm is complicated by the fact that the size of
    // TABLESWITCH and LOOKUPSWITCH instructions depends on their position in
    // the bytecode (because of padding). In order to ensure the convergence of
    // the algorithm, the number of bytes to be added or removed from these
    // instructions is over estimated during the previous loop, and computed
    // exactly only after the loop is finished (this requires another pass to
    // parse the bytecode of the method).

    int[] allIndexes = new int[len]; // copy of indexes
    int[] allSizes = new int[len];   // copy of sizes
    boolean[] resize;                // instructions to be resized
    int newOffset;                   // future offset of a jump instruction

    System.arraycopy(indexes, 0, allIndexes, 0, len);
    System.arraycopy(sizes, 0, allSizes, 0, len);
    resize = new boolean[code.length];

    int state = 3; // 3 = loop again, 2 = loop ended, 1 = last pass, 0 = done
    do {
      if (state == 3) {
        state = 2;
      }
      u = 0;
      while (u < b.length) {
        int opcode = b[u] & 0xFF;  // opcode of current instruction
        int insert = 0;            // bytes to be added after this instruction

        switch (ClassWriter.TYPE[opcode]) {
          case ClassWriter.NOARG_INSN:
          case ClassWriter.IMPLVAR_INSN:
            u += 1;
            break;
          case ClassWriter.LABEL_INSN:
            if (opcode > 201) {
              // converts temporary opcodes 202 to 217 (inclusive), 218 and 219
              // to IFEQ ... JSR (inclusive), IFNULL and IFNONNULL
              opcode = opcode < 218 ? opcode - 49 : opcode - 20;
              label = u + readUnsignedShort(b, u + 1);
            } else {
              label = u + readShort(b, u + 1);
            }
            newOffset = getNewOffset(allIndexes, allSizes, u, label);
            if (newOffset < Short.MIN_VALUE || newOffset > Short.MAX_VALUE) {
              if (!resize[u]) {
                if (opcode == Constants.GOTO || opcode == Constants.JSR) {
                  // two additional bytes will be required to replace this
                  // GOTO or JSR instruction with a GOTO_W or a JSR_W
                  insert = 2;
                } else {
                  // five additional bytes will be required to replace this
                  // IFxxx <l> instruction with IFNOTxxx <l'> GOTO_W <l>, where
                  // IFNOTxxx is the "opposite" opcode of IFxxx (i.e., IFNE for
                  // IFEQ) and where <l'> designates the instruction just after
                  // the GOTO_W.
                  insert = 5;
                }
                resize[u] = true;
              }
            }
            u += 3;
            break;
          case ClassWriter.LABELW_INSN:
            u += 5;
            break;
          case ClassWriter.TABL_INSN:
            if (state == 1) {
              // true number of bytes to be added (or removed) from this
              // instruction = (future number of padding bytes - current number
              // of padding byte) - previously over estimated variation =
              // = ((3 - newOffset%4) - (3 - u%4)) - u%4
              // = (-newOffset%4 + u%4) - u%4
              // = -(newOffset & 3)
              newOffset = getNewOffset(allIndexes, allSizes, 0, u);
              insert = -(newOffset & 3);
            } else if (!resize[u]) {
              // over estimation of the number of bytes to be added to this
              // instruction = 3 - current number of padding bytes = 3 - (3 -
              // u%4) = u%4 = u & 3
              insert = u & 3;
              resize[u] = true;
            }
            // skips instruction
            u = u + 4 - (u & 3);
            u += 4*(readInt(b, u + 8) - readInt(b, u + 4) + 1) + 12;
            break;
          case ClassWriter.LOOK_INSN:
            if (state == 1) {
              // like TABL_INSN
              newOffset = getNewOffset(allIndexes, allSizes, 0, u);
              insert = -(newOffset & 3);
            } else if (!resize[u]) {
              // like TABL_INSN
              insert = u & 3;
              resize[u] = true;
            }
            // skips instruction
            u = u + 4 - (u & 3);
            u += 8*readInt(b, u + 4) + 8;
            break;
          case ClassWriter.WIDE_INSN:
            opcode = b[u + 1] & 0xFF;
            if (opcode == Constants.IINC) {
              u += 6;
            } else {
              u += 4;
            }
            break;
          case ClassWriter.VAR_INSN:

⌨️ 快捷键说明

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