LocalVariableTableAttribute.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.compress.harmony.unpack200.bytecode;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.compress.harmony.pack200.Pack200Exception;
/**
* Local variable table
*/
public class LocalVariableTableAttribute extends BCIRenumberedAttribute {
private static CPUTF8 attributeName;
public static void setAttributeName(final CPUTF8 cpUTF8Value) {
attributeName = cpUTF8Value;
}
private final int localVariableTableLength;
private final int[] startPcs;
private final int[] lengths;
private int[] nameIndexes;
private int[] descriptorIndexes;
private final int[] indexes;
private final CPUTF8[] names;
private final CPUTF8[] descriptors;
private int codeLength;
public LocalVariableTableAttribute(final int localVariableTableLength, final int[] startPcs, final int[] lengths, final CPUTF8[] names,
final CPUTF8[] descriptors, final int[] indexes) {
super(attributeName);
this.localVariableTableLength = localVariableTableLength;
this.startPcs = startPcs;
this.lengths = lengths;
this.names = names;
this.descriptors = descriptors;
this.indexes = indexes;
}
@Override
protected int getLength() {
return 2 + 10 * localVariableTableLength;
}
@Override
protected ClassFileEntry[] getNestedClassFileEntries() {
final List<CPUTF8> nestedEntries = new ArrayList<>();
nestedEntries.add(getAttributeName());
for (int i = 0; i < localVariableTableLength; i++) {
nestedEntries.add(names[i]);
nestedEntries.add(descriptors[i]);
}
return nestedEntries.toArray(NONE);
}
@Override
protected int[] getStartPCs() {
return startPcs;
}
/*
* (non-Javadoc)
*
* @see org.apache.commons.compress.harmony.unpack200.bytecode.BCIRenumberedAttribute#renumber(java.util.List)
*/
@Override
public void renumber(final List<Integer> byteCodeOffsets) throws Pack200Exception {
// Remember the unrenumbered startPcs, since that's used later
// to calculate end position.
final int[] unrenumberedStartPcs = Arrays.copyOf(startPcs, startPcs.length);
// Next renumber startPcs in place
super.renumber(byteCodeOffsets);
// lengths are BRANCH5 encoded, not BCI-encoded.
// In other words:
// startPc is BCI5 startPc
// endPc is byteCodeOffset[(index of startPc in byteCodeOffset) +
// (encoded length)]
// real length = endPc - startPc
// special case if endPc is beyond end of bytecode array
final int maxSize = codeLength;
// Iterate through the lengths and update each in turn.
// This is done in place in the lengths array.
for (int index = 0; index < lengths.length; index++) {
final int startPc = startPcs[index];
int revisedLength = -1;
final int encodedLength = lengths[index];
// First get the index of the startPc in the byteCodeOffsets
final int indexOfStartPC = unrenumberedStartPcs[index];
// Given the index of the startPc, we can now add
// the encodedLength to it to get the stop index.
final int stopIndex = indexOfStartPC + encodedLength;
if (stopIndex < 0) {
throw new Pack200Exception("Error renumbering bytecode indexes");
}
// Length can either be an index into the byte code offsets, or one
// beyond the
// end of the byte code offsets. Need to determine which this is.
if (stopIndex == byteCodeOffsets.size()) {
// Pointing to one past the end of the byte code array
revisedLength = maxSize - startPc;
} else {
// We're indexed into the byte code array
final int stopValue = byteCodeOffsets.get(stopIndex).intValue();
revisedLength = stopValue - startPc;
}
lengths[index] = revisedLength;
}
}
@Override
protected void resolve(final ClassConstantPool pool) {
super.resolve(pool);
nameIndexes = new int[localVariableTableLength];
descriptorIndexes = new int[localVariableTableLength];
for (int i = 0; i < localVariableTableLength; i++) {
names[i].resolve(pool);
descriptors[i].resolve(pool);
nameIndexes[i] = pool.indexOf(names[i]);
descriptorIndexes[i] = pool.indexOf(descriptors[i]);
}
}
public void setCodeLength(final int length) {
codeLength = length;
}
@Override
public String toString() {
return "LocalVariableTable: " + +localVariableTableLength + " variables";
}
@Override
protected void writeBody(final DataOutputStream dos) throws IOException {
dos.writeShort(localVariableTableLength);
for (int i = 0; i < localVariableTableLength; i++) {
dos.writeShort(startPcs[i]);
dos.writeShort(lengths[i]);
dos.writeShort(nameIndexes[i]);
dos.writeShort(descriptorIndexes[i]);
dos.writeShort(indexes[i]);
}
}
}