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

📄 codewriter.java

📁 开源的java 编辑器源代码
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
      labels[i].put(this, code, source, true);    }  }  public void visitLookupSwitchInsn (    final Label dflt,    final int keys[],    final Label labels[])  {    if (computeMaxs) {      // updates current stack size (max stack size unchanged)      --stackSize;      // ends current block (with many new successors)      if (currentBlock != null) {        currentBlock.maxStackSize = maxStackSize;        addSuccessor(stackSize, dflt);        for (int i = 0; i < labels.length; ++i) {          addSuccessor(stackSize, labels[i]);        }        currentBlock = null;      }    }    // adds the instruction to the bytecode of the method    int source = code.length;    code.put1(Constants.LOOKUPSWITCH);    while (code.length % 4 != 0) {      code.put1(0);    }    dflt.put(this, code, source, true);    code.put4(labels.length);    for (int i = 0; i < labels.length; ++i) {      code.put4(keys[i]);      labels[i].put(this, code, source, true);    }  }  public void visitMultiANewArrayInsn (final String desc, final int dims) {    if (computeMaxs) {      // updates current stack size (max stack size unchanged because stack      // size variation always negative or null)      stackSize += 1 - dims;    }    // adds the instruction to the bytecode of the method    Item classItem = cw.newClass(desc);    code.put12(Constants.MULTIANEWARRAY, classItem.index).put1(dims);  }  public void visitTryCatchBlock (    final Label start,    final Label end,    final Label handler,    final String type)  {    if (CHECK) {      if (start.owner != this || end.owner != this || handler.owner != this) {        throw new IllegalArgumentException();      }      if (!start.resolved || !end.resolved || !handler.resolved) {        throw new IllegalArgumentException();      }    }    if (computeMaxs) {      // pushes handler block onto the stack of blocks to be visited      if (!handler.pushed) {        handler.beginStackSize = 1;        handler.pushed = true;        handler.next = blockStack;        blockStack = handler;      }    }    ++catchCount;    if (catchTable == null) {      catchTable = new ByteVector();    }    catchTable.put2(start.position);    catchTable.put2(end.position);    catchTable.put2(handler.position);    catchTable.put2(type != null ? cw.newClass(type).index : 0);  }  public void visitMaxs (final int maxStack, final int maxLocals) {    if (computeMaxs) {      // true (non relative) max stack size      int max = 0;      // control flow analysis algorithm: while the block stack is not empty,      // pop a block from this stack, update the max stack size, compute      // the true (non relative) begin stack size of the successors of this      // block, and push these successors onto the stack (unless they have      // already been pushed onto the stack). Note: by hypothesis, the {@link      // Label#beginStackSize} of the blocks in the block stack are the true      // (non relative) beginning stack sizes of these blocks.      Label stack = blockStack;      while (stack != null) {        // pops a block from the stack        Label l = stack;        stack = stack.next;        // computes the true (non relative) max stack size of this block        int start = l.beginStackSize;        int blockMax = start + l.maxStackSize;        // updates the global max stack size        if (blockMax > max) {          max = blockMax;        }        // analyses the successors of the block        Edge b = l.successors;        while (b != null) {          l = b.successor;          // if this successor has not already been pushed onto the stack...          if (!l.pushed) {            // computes the true beginning stack size of this successor block            l.beginStackSize = start + b.stackSize;            // pushes this successor onto the stack            l.pushed = true;            l.next = stack;            stack = l;          }          b = b.next;        }      }      this.maxStack = max;      // releases all the Edge objects used by this CodeWriter      synchronized (SIZE) {        // appends the [head ... tail] list at the beginning of the pool list        if (tail != null) {          tail.poolNext = pool;          pool = head;        }      }    } else {      this.maxStack = maxStack;      this.maxLocals = maxLocals;    }  }  public void visitLocalVariable (    final String name,    final String desc,    final Label start,    final Label end,    final int index)  {    if (CHECK) {      if (start.owner != this || !start.resolved) {        throw new IllegalArgumentException();      }      if (end.owner != this || !end.resolved) {        throw new IllegalArgumentException();      }    }    if (localVar == null) {      cw.newUTF8("LocalVariableTable");      localVar = new ByteVector();    }    ++localVarCount;    localVar.put2(start.position);    localVar.put2(end.position - start.position);    localVar.put2(cw.newUTF8(name).index);    localVar.put2(cw.newUTF8(desc).index);    localVar.put2(index);  }  public void visitLineNumber (final int line, final Label start) {    if (CHECK) {      if (start.owner != this || !start.resolved) {        throw new IllegalArgumentException();      }    }    if (lineNumber == null) {      cw.newUTF8("LineNumberTable");      lineNumber = new ByteVector();    }    ++lineNumberCount;    lineNumber.put2(start.position);    lineNumber.put2(line);  }  // --------------------------------------------------------------------------  // Utility methods: control flow analysis algorithm  // --------------------------------------------------------------------------  /**   * Computes the size of the arguments and of the return value of a method.   *   * @param desc the descriptor of a method.   * @return the size of the arguments of the method (plus one for the implicit   *      this argument), argSize, and the size of its return value, retSize,   *      packed into a single int i = <tt>(argSize << 2) | retSize</tt>   *      (argSize is therefore equal to <tt>i >> 2</tt>, and retSize to   *      <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 (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;    }    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.put2(access).put2(name.index).put2(desc.index);    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;    }    out.put2(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;      }      out.put2(cw.newUTF8("Code").index).put4(size);      out.put2(maxStack).put2(maxLocals);      out.put4(code.length).putByteArray(code.data, 0, code.length);      out.put2(catchCount);      if (catchCount > 0) {        out.putByteArray(catchTable.data, 0, catchTable.length);      }      attributeCount = 0;      if (localVar != null) {        ++attributeCount;      }      if (lineNumber != null) {        ++attributeCount;      }      out.put2(attributeCount);      if (localVar != null) {        out.put2(cw.newUTF8("LocalVariableTable").index);        out.put4(localVar.length + 2).put2(localVarCount);        out.putByteArray(localVar.data, 0, localVar.length);      }      if (lineNumber != null) {        out.put2(cw.newUTF8("LineNumberTable").index);        out.put4(lineNumber.length + 2).put2(lineNumberCount);        out.putByteArray(lineNumber.data, 0, lineNumber.length);      }    }    if (exceptionCount > 0) {      out.put2(cw.newUTF8("Exceptions").index).put4(2 * exceptionCount + 2);      out.put2(exceptionCount);      for (int i = 0; i < exceptionCount; ++i) {        out.put2(exceptions[i]);      }    }    if ((access & Constants.ACC_SYNTHETIC) != 0) {      out.put2(cw.newUTF8("Synthetic").index).put4(0);    }    if ((access & Constants.ACC_DEPRECATED) != 0) {      out.put2(cw.newUTF8("Deprecated").index).put4(0);    }  }  // --------------------------------------------------------------------------  // 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

⌨️ 快捷键说明

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