001// ASM: a very small and fast Java bytecode manipulation framework
002// Copyright (c) 2000-2011 INRIA, France Telecom
003// All rights reserved.
004//
005// Redistribution and use in source and binary forms, with or without
006// modification, are permitted provided that the following conditions
007// are met:
008// 1. Redistributions of source code must retain the above copyright
009//    notice, this list of conditions and the following disclaimer.
010// 2. Redistributions in binary form must reproduce the above copyright
011//    notice, this list of conditions and the following disclaimer in the
012//    documentation and/or other materials provided with the distribution.
013// 3. Neither the name of the copyright holders nor the names of its
014//    contributors may be used to endorse or promote products derived from
015//    this software without specific prior written permission.
016//
017// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
018// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
019// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
020// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
021// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
022// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
023// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
024// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
025// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
026// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
027// THE POSSIBILITY OF SUCH DAMAGE.
028package org.springframework.asm;
029
030import java.util.Arrays;
031
032/**
033 * A constant whose value is computed at runtime, with a bootstrap method.
034 *
035 * @author Remi Forax
036 */
037public final class ConstantDynamic {
038
039  /** The constant name (can be arbitrary). */
040  private final String name;
041
042  /** The constant type (must be a field descriptor). */
043  private final String descriptor;
044
045  /** The bootstrap method to use to compute the constant value at runtime. */
046  private final Handle bootstrapMethod;
047
048  /**
049   * The arguments to pass to the bootstrap method, in order to compute the constant value at
050   * runtime.
051   */
052  private final Object[] bootstrapMethodArguments;
053
054  /**
055   * Constructs a new {@link ConstantDynamic}.
056   *
057   * @param name the constant name (can be arbitrary).
058   * @param descriptor the constant type (must be a field descriptor).
059   * @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
060   * @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
061   *     compute the constant value at runtime.
062   */
063  public ConstantDynamic(
064      final String name,
065      final String descriptor,
066      final Handle bootstrapMethod,
067      final Object... bootstrapMethodArguments) {
068    this.name = name;
069    this.descriptor = descriptor;
070    this.bootstrapMethod = bootstrapMethod;
071    this.bootstrapMethodArguments = bootstrapMethodArguments;
072  }
073
074  /**
075   * Returns the name of this constant.
076   *
077   * @return the name of this constant.
078   */
079  public String getName() {
080    return name;
081  }
082
083  /**
084   * Returns the type of this constant.
085   *
086   * @return the type of this constant, as a field descriptor.
087   */
088  public String getDescriptor() {
089    return descriptor;
090  }
091
092  /**
093   * Returns the bootstrap method used to compute the value of this constant.
094   *
095   * @return the bootstrap method used to compute the value of this constant.
096   */
097  public Handle getBootstrapMethod() {
098    return bootstrapMethod;
099  }
100
101  /**
102   * Returns the number of arguments passed to the bootstrap method, in order to compute the value
103   * of this constant.
104   *
105   * @return the number of arguments passed to the bootstrap method, in order to compute the value
106   *     of this constant.
107   */
108  public int getBootstrapMethodArgumentCount() {
109    return bootstrapMethodArguments.length;
110  }
111
112  /**
113   * Returns an argument passed to the bootstrap method, in order to compute the value of this
114   * constant.
115   *
116   * @param index an argument index, between 0 and {@link #getBootstrapMethodArgumentCount()}
117   *     (exclusive).
118   * @return the argument passed to the bootstrap method, with the given index.
119   */
120  public Object getBootstrapMethodArgument(final int index) {
121    return bootstrapMethodArguments[index];
122  }
123
124  /**
125   * Returns the arguments to pass to the bootstrap method, in order to compute the value of this
126   * constant. WARNING: this array must not be modified, and must not be returned to the user.
127   *
128   * @return the arguments to pass to the bootstrap method, in order to compute the value of this
129   *     constant.
130   */
131  Object[] getBootstrapMethodArgumentsUnsafe() {
132    return bootstrapMethodArguments;
133  }
134
135  /**
136   * Returns the size of this constant.
137   *
138   * @return the size of this constant, i.e., 2 for {@code long} and {@code double}, 1 otherwise.
139   */
140  public int getSize() {
141    char firstCharOfDescriptor = descriptor.charAt(0);
142    return (firstCharOfDescriptor == 'J' || firstCharOfDescriptor == 'D') ? 2 : 1;
143  }
144
145  @Override
146  public boolean equals(final Object object) {
147    if (object == this) {
148      return true;
149    }
150    if (!(object instanceof ConstantDynamic)) {
151      return false;
152    }
153    ConstantDynamic constantDynamic = (ConstantDynamic) object;
154    return name.equals(constantDynamic.name)
155        && descriptor.equals(constantDynamic.descriptor)
156        && bootstrapMethod.equals(constantDynamic.bootstrapMethod)
157        && Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
158  }
159
160  @Override
161  public int hashCode() {
162    return name.hashCode()
163        ^ Integer.rotateLeft(descriptor.hashCode(), 8)
164        ^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
165        ^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
166  }
167
168  @Override
169  public String toString() {
170    return name
171        + " : "
172        + descriptor
173        + ' '
174        + bootstrapMethod
175        + ' '
176        + Arrays.toString(bootstrapMethodArguments);
177  }
178}