/** * 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 } } } } }