StackMap.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.bcel.classfile;

  18. import java.io.DataInput;
  19. import java.io.DataOutputStream;
  20. import java.io.IOException;
  21. import java.util.Arrays;

  22. import org.apache.bcel.Const;
  23. import org.apache.bcel.util.Args;

  24. /**
  25.  * This class represents a stack map attribute used for preverification of Java classes for the
  26.  * <a href="https://java.sun.com/j2me/"> Java 2 Micro Edition</a> (J2ME). This attribute is used by the
  27.  * <a href="https://java.sun.com/products/cldc/">KVM</a> and contained within the Code attribute of a method. See CLDC
  28.  * specification �5.3.1.2
  29.  *
  30.  * <pre>
  31.  * StackMapTable_attribute {
  32.  *   u2              attribute_name_index;
  33.  *   u4              attribute_length;
  34.  *   u2              number_of_entries;
  35.  *   stack_map_frame entries[number_of_entries];
  36.  * }
  37.  * </pre>
  38.  *
  39.  * @see Code
  40.  * @see StackMapEntry
  41.  * @see StackMapType
  42.  */
  43. public final class StackMap extends Attribute {

  44.     private StackMapEntry[] table; // Table of stack map entries

  45.     /**
  46.      * Constructs object from input stream.
  47.      *
  48.      * @param nameIndex Index of name
  49.      * @param length Content length in bytes
  50.      * @param dataInput Input stream
  51.      * @param constantPool Array of constants
  52.      * @throws IOException if an I/O error occurs.
  53.      */
  54.     StackMap(final int nameIndex, final int length, final DataInput dataInput, final ConstantPool constantPool) throws IOException {
  55.         this(nameIndex, length, (StackMapEntry[]) null, constantPool);
  56.         final int mapLength = dataInput.readUnsignedShort();
  57.         table = new StackMapEntry[mapLength];
  58.         for (int i = 0; i < mapLength; i++) {
  59.             table[i] = new StackMapEntry(dataInput, constantPool);
  60.         }
  61.     }

  62.     /*
  63.      * @param nameIndex Index of name
  64.      *
  65.      * @param length Content length in bytes
  66.      *
  67.      * @param map Table of stack map entries
  68.      *
  69.      * @param constantPool Array of constants
  70.      */
  71.     public StackMap(final int nameIndex, final int length, final StackMapEntry[] table, final ConstantPool constantPool) {
  72.         super(Const.ATTR_STACK_MAP, nameIndex, length, constantPool);
  73.         this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
  74.         Args.requireU2(this.table.length, "table.length");
  75.     }

  76.     /**
  77.      * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class.
  78.      * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
  79.      *
  80.      * @param v Visitor object
  81.      */
  82.     @Override
  83.     public void accept(final Visitor v) {
  84.         v.visitStackMap(this);
  85.     }

  86.     /**
  87.      * @return deep copy of this attribute
  88.      */
  89.     @Override
  90.     public Attribute copy(final ConstantPool constantPool) {
  91.         final StackMap c = (StackMap) clone();
  92.         c.table = new StackMapEntry[table.length];
  93.         Arrays.setAll(c.table, i -> table[i].copy());
  94.         c.setConstantPool(constantPool);
  95.         return c;
  96.     }

  97.     /**
  98.      * Dump stack map table attribute to file stream in binary format.
  99.      *
  100.      * @param file Output file stream
  101.      * @throws IOException if an I/O error occurs.
  102.      */
  103.     @Override
  104.     public void dump(final DataOutputStream file) throws IOException {
  105.         super.dump(file);
  106.         file.writeShort(table.length);
  107.         for (final StackMapEntry entry : table) {
  108.             entry.dump(file);
  109.         }
  110.     }

  111.     public int getMapLength() {
  112.         return table.length;
  113.     }

  114.     /**
  115.      * @return Array of stack map entries
  116.      */
  117.     public StackMapEntry[] getStackMap() {
  118.         return table;
  119.     }

  120.     /**
  121.      * @param table Array of stack map entries
  122.      */
  123.     public void setStackMap(final StackMapEntry[] table) {
  124.         this.table = table != null ? table : StackMapEntry.EMPTY_ARRAY;
  125.         int len = 2; // Length of 'number_of_entries' field prior to the array of stack maps
  126.         for (final StackMapEntry element : this.table) {
  127.             len += element.getMapEntrySize();
  128.         }
  129.         setLength(len);
  130.     }

  131.     /**
  132.      * @return String representation.
  133.      */
  134.     @Override
  135.     public String toString() {
  136.         final StringBuilder buf = new StringBuilder("StackMap(");
  137.         int runningOffset = -1; // no +1 on first entry
  138.         for (int i = 0; i < table.length; i++) {
  139.             runningOffset = table[i].getByteCodeOffset() + runningOffset + 1;
  140.             buf.append(String.format("%n@%03d %s", runningOffset, table[i]));
  141.             if (i < table.length - 1) {
  142.                 buf.append(", ");
  143.             }
  144.         }
  145.         buf.append(')');
  146.         return buf.toString();
  147.     }
  148. }