/**
  * Give all instructions their position number (offset in byte stream), i.e., make the list ready
  * to be dumped.
  *
  * @param check Perform sanity checks, e.g. if all targeted instructions really belong to this
  *     list
  */
 public void setPositions(boolean check) {
   int max_additional_bytes = 0, additional_bytes = 0;
   int index = 0, count = 0;
   int[] pos = new int[length];
   /* Pass 0: Sanity checks
    */
   if (check) {
     for (InstructionHandle ih = start; ih != null; ih = ih.next) {
       Instruction i = ih.instruction;
       if (i instanceof BranchInstruction) { // target instruction within list?
         Instruction inst = ((BranchInstruction) i).getTarget().instruction;
         if (!contains(inst)) {
           throw new ClassGenException(
               "Branch target of "
                   + Constants.OPCODE_NAMES[i.opcode]
                   + ":"
                   + inst
                   + " not in instruction list");
         }
         if (i instanceof Select) {
           InstructionHandle[] targets = ((Select) i).getTargets();
           for (InstructionHandle target : targets) {
             inst = target.instruction;
             if (!contains(inst)) {
               throw new ClassGenException(
                   "Branch target of "
                       + Constants.OPCODE_NAMES[i.opcode]
                       + ":"
                       + inst
                       + " not in instruction list");
             }
           }
         }
         if (!(ih instanceof BranchHandle)) {
           throw new ClassGenException(
               "Branch instruction "
                   + Constants.OPCODE_NAMES[i.opcode]
                   + ":"
                   + inst
                   + " not contained in BranchHandle.");
         }
       }
     }
   }
   /* Pass 1: Set position numbers and sum up the maximum number of bytes an
    * instruction may be shifted.
    */
   for (InstructionHandle ih = start; ih != null; ih = ih.next) {
     Instruction i = ih.instruction;
     ih.setPosition(index);
     pos[count++] = index;
     /* Get an estimate about how many additional bytes may be added, because
      * BranchInstructions may have variable length depending on the target
      * offset (short vs. int) or alignment issues (TABLESWITCH and
      * LOOKUPSWITCH).
      */
     switch (i.getOpcode()) {
       case Constants.JSR:
       case Constants.GOTO:
         max_additional_bytes += 2;
         break;
       case Constants.TABLESWITCH:
       case Constants.LOOKUPSWITCH:
         max_additional_bytes += 3;
         break;
     }
     index += i.getLength();
   }
   /* Pass 2: Expand the variable-length (Branch)Instructions depending on
    * the target offset (short or int) and ensure that branch targets are
    * within this list.
    */
   for (InstructionHandle ih = start; ih != null; ih = ih.next) {
     additional_bytes += ih.updatePosition(additional_bytes, max_additional_bytes);
   }
   /* Pass 3: Update position numbers (which may have changed due to the
    * preceding expansions), like pass 1.
    */
   index = count = 0;
   for (InstructionHandle ih = start; ih != null; ih = ih.next) {
     Instruction i = ih.instruction;
     ih.setPosition(index);
     pos[count++] = index;
     index += i.getLength();
   }
   byte_positions = new int[count]; // Trim to proper size
   System.arraycopy(pos, 0, byte_positions, 0, count);
 }
 /**
  * Initialize instruction list from byte array.
  *
  * @param code byte array containing the instructions
  */
 public InstructionList(byte[] code) {
   ByteSequence bytes = new ByteSequence(code);
   InstructionHandle[] ihs = new InstructionHandle[code.length];
   int[] pos = new int[code.length]; // Can't be more than that
   int count = 0; // Contains actual length
   /* Pass 1: Create an object for each byte code and append them
    * to the list.
    */
   try {
     while (bytes.available() > 0) {
       // Remember byte offset and associate it with the instruction
       int off = bytes.getIndex();
       pos[count] = off;
       /* Read one instruction from the byte stream, the byte position is set
        * accordingly.
        */
       Instruction i = Instruction.readInstruction(bytes);
       InstructionHandle ih;
       if (i instanceof BranchInstruction) {
         ih = append((BranchInstruction) i);
       } else {
         ih = append(i);
       }
       ih.setPosition(off);
       ihs[count] = ih;
       count++;
     }
   } catch (IOException e) {
     throw new ClassGenException(e.toString(), e);
   }
   byte_positions = new int[count]; // Trim to proper size
   System.arraycopy(pos, 0, byte_positions, 0, count);
   /* Pass 2: Look for BranchInstruction and update their targets, i.e.,
    * convert offsets to instruction handles.
    */
   for (int i = 0; i < count; i++) {
     if (ihs[i] instanceof BranchHandle) {
       BranchInstruction bi = (BranchInstruction) ihs[i].instruction;
       int target = bi.position + bi.getIndex(); /* Byte code position:
                * relative -> absolute. */
       // Search for target position
       InstructionHandle ih = findHandle(ihs, pos, count, target);
       if (ih == null) {
         throw new ClassGenException("Couldn't find target for branch: " + bi);
       }
       bi.setTarget(ih); // Update target
       // If it is a Select instruction, update all branch targets
       if (bi instanceof Select) { // Either LOOKUPSWITCH or TABLESWITCH
         Select s = (Select) bi;
         int[] indices = s.getIndices();
         for (int j = 0; j < indices.length; j++) {
           target = bi.position + indices[j];
           ih = findHandle(ihs, pos, count, target);
           if (ih == null) {
             throw new ClassGenException("Couldn't find target for switch: " + bi);
           }
           s.setTarget(j, ih); // Update target
         }
       }
     }
   }
 }