LocalVariableTypeTableAttribute.java

  1. /*
  2.  *  Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.commons.compress.harmony.unpack200.bytecode;

  18. import java.io.DataOutputStream;
  19. import java.io.IOException;
  20. import java.util.ArrayList;
  21. import java.util.Arrays;
  22. import java.util.List;

  23. import org.apache.commons.compress.harmony.pack200.Pack200Exception;

  24. /**
  25.  * Local variable type table.
  26.  */
  27. public class LocalVariableTypeTableAttribute extends BCIRenumberedAttribute {

  28.     private static CPUTF8 attributeName;

  29.     public static void setAttributeName(final CPUTF8 cpUTF8Value) {
  30.         attributeName = cpUTF8Value;
  31.     }

  32.     private final int localVariableTypeTableLength;
  33.     private final int[] startPcs;
  34.     private final int[] lengths;
  35.     private int[] nameIndexes;
  36.     private int[] signatureIndexes;
  37.     private final int[] indexes;
  38.     private final CPUTF8[] names;
  39.     private final CPUTF8[] signatures;

  40.     private int codeLength;

  41.     public LocalVariableTypeTableAttribute(final int localVariableTypeTableLength, final int[] startPcs, final int[] lengths, final CPUTF8[] names,
  42.             final CPUTF8[] signatures, final int[] indexes) {
  43.         super(attributeName);
  44.         this.localVariableTypeTableLength = localVariableTypeTableLength;
  45.         this.startPcs = startPcs;
  46.         this.lengths = lengths;
  47.         this.names = names;
  48.         this.signatures = signatures;
  49.         this.indexes = indexes;
  50.     }

  51.     @Override
  52.     protected int getLength() {
  53.         return 2 + 10 * localVariableTypeTableLength;
  54.     }

  55.     @Override
  56.     protected ClassFileEntry[] getNestedClassFileEntries() {
  57.         final List<CPUTF8> nestedEntries = new ArrayList<>();
  58.         nestedEntries.add(getAttributeName());
  59.         for (int i = 0; i < localVariableTypeTableLength; i++) {
  60.             nestedEntries.add(names[i]);
  61.             nestedEntries.add(signatures[i]);
  62.         }
  63.         return nestedEntries.toArray(NONE);
  64.     }

  65.     @Override
  66.     protected int[] getStartPCs() {
  67.         return startPcs;
  68.     }

  69.     /*
  70.      * (non-Javadoc)
  71.      *
  72.      * @see org.apache.commons.compress.harmony.unpack200.bytecode.BCIRenumberedAttribute#renumber(java.util.List)
  73.      */
  74.     @Override
  75.     public void renumber(final List<Integer> byteCodeOffsets) throws Pack200Exception {
  76.         // Remember the unrenumbered startPcs, since that's used later
  77.         // to calculate end position.
  78.         final int[] unrenumberedStartPcs = Arrays.copyOf(startPcs, startPcs.length);

  79.         // Next renumber startPcs in place
  80.         super.renumber(byteCodeOffsets);

  81.         // lengths are BRANCH5 encoded, not BCI-encoded.
  82.         // In other words:
  83.         // startPc is BCI5 startPc
  84.         // endPc is byteCodeOffset[(index of startPc in byteCodeOffset) +
  85.         // (encoded length)]
  86.         // real length = endPc - startPc
  87.         // special case if endPc is beyond end of bytecode array

  88.         final int maxSize = codeLength;

  89.         // Iterate through the lengths and update each in turn.
  90.         // This is done in place in the lengths array.
  91.         for (int index = 0; index < lengths.length; index++) {
  92.             final int startPc = startPcs[index];
  93.             int revisedLength = -1;
  94.             final int encodedLength = lengths[index];

  95.             // First get the index of the startPc in the byteCodeOffsets
  96.             final int indexOfStartPC = unrenumberedStartPcs[index];
  97.             // Given the index of the startPc, we can now add
  98.             // the encodedLength to it to get the stop index.
  99.             final int stopIndex = indexOfStartPC + encodedLength;
  100.             if (stopIndex < 0) {
  101.                 throw new Pack200Exception("Error renumbering bytecode indexes");
  102.             }
  103.             // Length can either be an index into the byte code offsets, or one
  104.             // beyond the
  105.             // end of the byte code offsets. Need to determine which this is.
  106.             if (stopIndex == byteCodeOffsets.size()) {
  107.                 // Pointing to one past the end of the byte code array
  108.                 revisedLength = maxSize - startPc;
  109.             } else {
  110.                 // We're indexed into the byte code array
  111.                 final int stopValue = byteCodeOffsets.get(stopIndex).intValue();
  112.                 revisedLength = stopValue - startPc;
  113.             }
  114.             lengths[index] = revisedLength;
  115.         }
  116.     }

  117.     @Override
  118.     protected void resolve(final ClassConstantPool pool) {
  119.         super.resolve(pool);
  120.         nameIndexes = new int[localVariableTypeTableLength];
  121.         signatureIndexes = new int[localVariableTypeTableLength];
  122.         for (int i = 0; i < localVariableTypeTableLength; i++) {
  123.             names[i].resolve(pool);
  124.             signatures[i].resolve(pool);
  125.             nameIndexes[i] = pool.indexOf(names[i]);
  126.             signatureIndexes[i] = pool.indexOf(signatures[i]);
  127.         }
  128.     }

  129.     public void setCodeLength(final int length) {
  130.         codeLength = length;
  131.     }

  132.     @Override
  133.     public String toString() {
  134.         return "LocalVariableTypeTable: " + +localVariableTypeTableLength + " varaibles";
  135.     }

  136.     @Override
  137.     protected void writeBody(final DataOutputStream dos) throws IOException {
  138.         dos.writeShort(localVariableTypeTableLength);
  139.         for (int i = 0; i < localVariableTypeTableLength; i++) {
  140.             dos.writeShort(startPcs[i]);
  141.             dos.writeShort(lengths[i]);
  142.             dos.writeShort(nameIndexes[i]);
  143.             dos.writeShort(signatureIndexes[i]);
  144.             dos.writeShort(indexes[i]);
  145.         }
  146.     }

  147. }