LocalVariableTypeTableAttribute.java

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

  20. import java.io.DataOutputStream;
  21. import java.io.IOException;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import java.util.List;

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

  26. /**
  27.  * Local variable type table.
  28.  */
  29. public class LocalVariableTypeTableAttribute extends BCIRenumberedAttribute {

  30.     private static CPUTF8 attributeName;

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

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

  42.     private int codeLength;

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

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

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

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

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

  81.         // Next renumber startPcs in place
  82.         super.renumber(byteCodeOffsets);

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

  90.         final int maxSize = codeLength;

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

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

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

  131.     public void setCodeLength(final int length) {
  132.         codeLength = length;
  133.     }

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

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

  149. }