All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mockit.external.asm.BootstrapMethods Maven / Gradle / Ivy

Go to download

JMockit is a Java toolkit for automated developer testing. It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking external APIs; JUnit (4 & 5) and TestNG test runners are supported. It also contains an advanced code coverage tool.

There is a newer version: 1.49
Show newest version
package mockit.external.asm;

import javax.annotation.*;

/**
 * Generates the "BootstrapMethods" attribute in a class file being written by a {@link ClassWriter}.
 */
final class BootstrapMethods
{
   @Nonnull private final ConstantPoolGeneration constantPool;

   /**
    * The number of entries in the BootstrapMethods attribute.
    */
   @Nonnegative private int bootstrapMethodsCount;

   /**
    * The BootstrapMethods attribute.
    */
   @Nullable private ByteVector bootstrapMethods;

   BootstrapMethods(@Nonnull ConstantPoolGeneration constantPool) { this.constantPool = constantPool; }

   /**
    * Adds an invokedynamic reference to the constant pool of the class being built.
    * Does nothing if the constant pool already contains a similar item.
    *
    * @param name    name of the invoked method.
    * @param desc    descriptor of the invoke method.
    * @param bsm     the bootstrap method.
    * @param bsmArgs the bootstrap method constant arguments.
    * @return a new or an already existing invokedynamic type reference item.
    */
   Item addInvokeDynamicReference(
      @Nonnull String name, @Nonnull String desc, @Nonnull Handle bsm, @Nonnull Object... bsmArgs
   ) {
      ByteVector methods = bootstrapMethods;

      if (methods == null) {
         methods = bootstrapMethods = new ByteVector();
      }

      int position = methods.length; // record current position

      int hashCode = bsm.hashCode();
      Item handleItem = constantPool.newHandleItem(bsm);
      methods.putShort(handleItem.index);

      int argsLength = bsmArgs.length;
      methods.putShort(argsLength);

      hashCode = putBSMArgs(hashCode, bsmArgs);

      byte[] data = methods.data;
      int length = (1 + 1 + argsLength) << 1; // (bsm + argCount + arguments)
      hashCode &= 0x7FFFFFFF;

      Item bsmItem = getBSMItem(position, hashCode, data, length);
      int bsmIndex;

      if (bsmItem != null) {
         bsmIndex = bsmItem.index;
         methods.length = position; // revert to old position
      }
      else {
         bsmIndex = bootstrapMethodsCount++;
         bsmItem = new Item(bsmIndex);
         bsmItem.set(position, hashCode);
         constantPool.put(bsmItem);
      }

      // Now, create the InvokeDynamic constant.
      Item result = constantPool.createInvokeDynamicConstant(name, desc, bsmIndex);
      return result;
   }

   private int putBSMArgs(int hashCode, @Nonnull Object[] bsmArgs) {
      @SuppressWarnings("ConstantConditions") @Nonnull ByteVector methods = bootstrapMethods;

      for (int i = 0; i < bsmArgs.length; i++) {
         Object bsmArg = bsmArgs[i];
         hashCode ^= bsmArg.hashCode();

         Item constItem = constantPool.newConstItem(bsmArg);
         methods.putShort(constItem.index);
      }

      return hashCode;
   }

   @Nullable
   private Item getBSMItem(@Nonnegative int position, int hashCode, @Nonnull byte[] data, @Nonnegative int length) {
      Item bsmItem = constantPool.getItem(hashCode);

   loop:
      while (bsmItem != null) {
         if (bsmItem.type != ConstantPoolItemType.BSM || bsmItem.hashCode != hashCode) {
            bsmItem = bsmItem.next;
            continue;
         }

         // Because the data encode the size of the argument we don't need to test if these size are equals.
         int resultPosition = bsmItem.intVal;

         for (int p = 0; p < length; p++) {
            if (data[position + p] != data[resultPosition + p]) {
               bsmItem = bsmItem.next;
               continue loop;
            }
         }

         break;
      }

      return bsmItem;
   }

   boolean hasMethods() { return bootstrapMethods != null; }

   @Nonnegative
   int getSize() {
      constantPool.newUTF8("BootstrapMethods");
      //noinspection ConstantConditions
      return 8 + bootstrapMethods.length;
   }

   void put(@Nonnull ByteVector out) {
      if (hasMethods()) {
         out.putShort(constantPool.newUTF8("BootstrapMethods"));
         //noinspection ConstantConditions
         out.putInt(bootstrapMethods.length + 2).putShort(bootstrapMethodsCount);
         out.putByteVector(bootstrapMethods);
      }
   }

   /**
    * Copies the bootstrap method data from the given {@link ClassReader}.
    */
   void copyBootstrapMethods(@Nonnull ClassReader cr, @Nonnull Item[] items, @Nonnull char[] c) {
      // Finds the "BootstrapMethods" attribute.
      int u = cr.getAttributesStartIndex();
      boolean found = false;

      for (int i = cr.readUnsignedShort(u); i > 0; i--) {
         String attrName = cr.readUTF8(u + 2, c);

         if ("BootstrapMethods".equals(attrName)) {
            found = true;
            break;
         }

         u += 6 + cr.readInt(u + 4);
      }

      if (!found) {
         return;
      }

      // Copies the bootstrap methods in the class writer.
      bootstrapMethodsCount = cr.readUnsignedShort(u + 8);

      for (int j = 0, v = u + 10; j < bootstrapMethodsCount; j++) {
         int position = v - u - 10;
         int hashCode = cr.readConst(cr.readUnsignedShort(v), c).hashCode();

         for (int k = cr.readUnsignedShort(v + 2); k > 0; k--) {
            hashCode ^= cr.readConst(cr.readUnsignedShort(v + 4), c).hashCode();
            v += 2;
         }

         v += 4;
         Item item = new Item(j);
         item.set(position, hashCode & 0x7FFFFFFF);
         int index = item.hashCode % items.length;
         item.next = items[index];
         items[index] = item;
      }

      int attrSize = cr.readInt(u + 4);
      bootstrapMethods = new ByteVector(attrSize + 62);
      bootstrapMethods.putByteArray(cr.b, u + 10, attrSize - 2);
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy