Commit 2af7508d authored by Eric Bruneton's avatar Eric Bruneton

Improve the quality of the code related to ConstantDynamic.

parent 07272db0
Pipeline #1455 passed with stage
in 3 minutes and 56 seconds
......@@ -29,7 +29,7 @@ package org.objectweb.asm.tree.analysis;
import java.util.List;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
......@@ -154,8 +154,8 @@ public class BasicInterpreter extends Interpreter<BasicValue> implements Opcodes
}
} else if (value instanceof Handle) {
return newValue(Type.getObjectType("java/lang/invoke/MethodHandle"));
} else if (value instanceof Condy) {
return newValue(Type.getType(((Condy)value).getDescriptor()));
} else if (value instanceof ConstantDynamic) {
return newValue(Type.getType(((ConstantDynamic)value).getDescriptor()));
} else {
throw new AnalyzerException(insn, "Illegal LDC value " + value);
}
......
......@@ -32,7 +32,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
......@@ -399,8 +399,8 @@ public class AnalyzerAdapter extends MethodVisitor {
}
} else if (cst instanceof Handle) {
push("java/lang/invoke/MethodHandle");
} else if (cst instanceof Condy) {
pushDesc(((Condy)cst).getDescriptor());
} else if (cst instanceof ConstantDynamic) {
pushDesc(((ConstantDynamic) cst).getDescriptor());
} else {
throw new IllegalArgumentException();
}
......
......@@ -28,7 +28,7 @@
package org.objectweb.asm.commons;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
......@@ -629,7 +629,7 @@ public class InstructionAdapter extends MethodVisitor {
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException();
}
if (api < Opcodes.ASM7 && value instanceof Condy) {
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException();
}
if (value instanceof Integer) {
......@@ -662,8 +662,8 @@ public class InstructionAdapter extends MethodVisitor {
tconst((Type) value);
} else if (value instanceof Handle) {
hconst((Handle) value);
} else if (value instanceof Condy) {
cconst((Condy) value);
} else if (value instanceof ConstantDynamic) {
cconst((ConstantDynamic) value);
} else {
throw new IllegalArgumentException();
}
......@@ -750,8 +750,8 @@ public class InstructionAdapter extends MethodVisitor {
mv.visitLdcInsn(handle);
}
public void cconst(final Condy condy) {
mv.visitLdcInsn(condy);
public void cconst(final ConstantDynamic constantDynamic) {
mv.visitLdcInsn(constantDynamic);
}
public void load(final int var, final Type type) {
......
......@@ -33,7 +33,7 @@ import java.util.List;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
......@@ -665,7 +665,7 @@ public class MethodNode extends MethodVisitor {
AbstractInsnNode insn = instructions.get(i);
if (insn instanceof LdcInsnNode) {
Object value = ((LdcInsnNode) insn).cst;
if (value instanceof Condy) {
if (value instanceof ConstantDynamic) {
throw new UnsupportedClassVersionException();
}
}
......
......@@ -33,7 +33,7 @@ import java.util.HashMap;
import java.util.Map;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
......@@ -163,7 +163,7 @@ public class ASMifier extends Printer {
text.add("import org.objectweb.asm.Attribute;\n");
text.add("import org.objectweb.asm.ClassReader;\n");
text.add("import org.objectweb.asm.ClassWriter;\n");
text.add("import org.objectweb.asm.Condy;\n");
text.add("import org.objectweb.asm.ConstantDynamic;\n");
text.add("import org.objectweb.asm.FieldVisitor;\n");
text.add("import org.objectweb.asm.Handle;\n");
text.add("import org.objectweb.asm.Label;\n");
......@@ -1361,17 +1361,17 @@ public class ASMifier extends Printer {
stringBuilder.append(handle.getName()).append("\", \"");
stringBuilder.append(handle.getDesc()).append("\", ");
stringBuilder.append(handle.isInterface()).append(")");
} else if (value instanceof Condy) {
stringBuilder.append("new Condy(\"");
Condy c = (Condy) value;
stringBuilder.append(c.getName()).append("\", \"");
stringBuilder.append(c.getDescriptor()).append("\", ");
appendConstant(c.getBootrapMethod());
} else if (value instanceof ConstantDynamic) {
stringBuilder.append("new ConstantDynamic(\"");
ConstantDynamic constantDynamic = (ConstantDynamic) value;
stringBuilder.append(constantDynamic.getName()).append("\", \"");
stringBuilder.append(constantDynamic.getDescriptor()).append("\", ");
appendConstant(constantDynamic.getBootstrapMethod());
stringBuilder.append(", new Object[] {");
Object[] bootstrapArguments = c.getBootstrapArguments();
for (int i = 0; i < bootstrapArguments.length; ++i) {
appendConstant(bootstrapArguments[i]);
if (i != bootstrapArguments.length - 1) {
Object[] bootstrapMethodArguments = constantDynamic.getBootstrapMethodArguments();
for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
appendConstant(bootstrapMethodArguments[i]);
if (i != bootstrapMethodArguments.length - 1) {
stringBuilder.append(", ");
}
}
......
......@@ -38,7 +38,7 @@ import java.util.Set;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
......@@ -776,7 +776,7 @@ public class CheckMethodAdapter extends MethodVisitor {
&& bootstrapMethodHandle.getTag() != Opcodes.H_NEWINVOKESPECIAL) {
throw new IllegalArgumentException("invalid handle tag " + bootstrapMethodHandle.getTag());
}
for (Object bootstrapMethodArgument: bootstrapMethodArguments) {
for (Object bootstrapMethodArgument : bootstrapMethodArguments) {
checkLdcConstant(bootstrapMethodArgument);
}
super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, bootstrapMethodArguments);
......@@ -1185,7 +1185,7 @@ public class CheckMethodAdapter extends MethodVisitor {
}
} else if (value instanceof Handle) {
if ((version & 0xFFFF) < Opcodes.V1_7) {
throw new IllegalArgumentException("ldc of a handle requires at least version 1.7");
throw new IllegalArgumentException("ldc of a Handle requires at least version 1.7");
}
Handle handle = (Handle) value;
int tag = handle.getTag();
......@@ -1199,17 +1199,17 @@ public class CheckMethodAdapter extends MethodVisitor {
checkMethodDescriptor(handle.getDesc());
}
checkMethodIdentifier(this.version, handle.getName(), "handle name");
} else if (value instanceof Condy) {
if ((version & 0xFFFF) < Opcodes.V11) {
throw new IllegalArgumentException("ldc of a handle requires at least version 1.7");
}
Condy condy = (Condy) value;
checkMethodIdentifier(this.version, condy.getName(), "constant dynamic name");
checkDescriptor(condy.getDescriptor(), false);
checkLdcConstant(condy.getBootrapMethod());
for (Object bootstrapArgument: condy.getBootstrapArguments()) {
checkLdcConstant(bootstrapArgument);
}
} else if (value instanceof ConstantDynamic) {
if ((version & 0xFFFF) < Opcodes.V11) {
throw new IllegalArgumentException("ldc of a ConstantDynamic requires at least version 11");
}
ConstantDynamic constantDynamic = (ConstantDynamic) value;
checkMethodIdentifier(this.version, constantDynamic.getName(), "constant dynamic name");
checkDescriptor(constantDynamic.getDescriptor(), false);
checkLdcConstant(constantDynamic.getBootstrapMethod());
for (Object bootstrapArgument : constantDynamic.getBootstrapMethodArguments()) {
checkLdcConstant(bootstrapArgument);
}
} else {
checkConstant(value);
}
......
......@@ -35,7 +35,7 @@ import java.util.List;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Condy;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Label;
import org.objectweb.asm.Opcodes;
......@@ -930,8 +930,8 @@ public abstract class Printer {
* Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
* Type} of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes whose version is
* 49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle
* constants, for classes whose version is 51 or a {@link Condy} for a constant dynamic for
* classes whose version is 55.
* constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant
* dynamic for classes whose version is 55.
*/
public abstract void visitLdcInsn(Object value);
......
......@@ -106,19 +106,20 @@ public class ClassReader {
private final int[] cpInfoOffsets;
/**
* The String or Condy objects respectively corresponding to the CONSTANT_Utf8 and
* CONSTANT_Dynamic items. This cache avoids multiple parsing of those constant pool items.
* The value of each cp_info entry of the ClassFile's constant_pool array, <i>for Constant_Utf8
* and Constant_Dynamic constants only</i>. The value of constant pool entry i is given by
* cpInfoValues[i]. This cache avoids multiple parsing of those constant pool items.
*/
private final Object[] cacheValues;
private final Object[] cpInfoValues;
/**
* The start offsets in {@link ClassReader#b} of each element of the bootstrap_methods array (in
* the BootstrapMethod attribute).
* The start offsets in {@link #b} of each element of the bootstrap_methods array (in the
* BootstrapMethods attribute).
*
* @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.23">JVMS
* 4.7.23</a>
*/
int[] bootstrapMethodOffsets;
private final int[] bootstrapMethodOffsets;
/**
* A conservative estimate of the maximum length of the strings contained in the constant pool of
......@@ -175,7 +176,7 @@ public class ClassReader {
// minor_version and major_version fields, which use 4, 2 and 2 bytes respectively.
int constantPoolCount = readUnsignedShort(classFileOffset + 8);
cpInfoOffsets = new int[constantPoolCount];
cacheValues = new Object[constantPoolCount];
cpInfoValues = new Object[constantPoolCount];
// Compute the offset of each constant pool entry, as well as a conservative estimate of the
// maximum length of the constant pool strings. The first constant pool entry is after the
// magic, minor_version, major_version and constant_pool_count fields, which use 4, 2, 2 and 2
......@@ -233,6 +234,7 @@ public class ClassReader {
// Read the BootstrapMethods attribute, if any (only get the offset of each method).
int currentAttributeOffset = getFirstAttributeOffset();
int[] currentBootstrapMethodOffsets = null;
for (int i = readUnsignedShort(currentAttributeOffset - 2); i > 0; --i) {
// Read the attribute_info's attribute_name and attribute_length fields.
String attributeName = readUTF8(currentAttributeOffset, new char[maxStringLength]);
......@@ -240,11 +242,11 @@ public class ClassReader {
currentAttributeOffset += 6;
if (Constants.BOOTSTRAP_METHODS.equals(attributeName)) {
// Read the num_bootstrap_methods field and create an array of this size.
bootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
currentBootstrapMethodOffsets = new int[readUnsignedShort(currentAttributeOffset)];
// Compute and store the offset of each 'bootstrap_methods' array field entry.
int currentBootstrapMethodOffset = currentAttributeOffset + 2;
for (int j = 0; j < bootstrapMethodOffsets.length; ++j) {
bootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
for (int j = 0; j < currentBootstrapMethodOffsets.length; ++j) {
currentBootstrapMethodOffsets[j] = currentBootstrapMethodOffset;
// Skip the bootstrap_method_ref and num_bootstrap_arguments fields (2 bytes each),
// as well as the bootstrap_arguments array field (of size num_bootstrap_arguments * 2).
currentBootstrapMethodOffset +=
......@@ -253,6 +255,7 @@ public class ClassReader {
}
currentAttributeOffset += attributeLength;
}
this.bootstrapMethodOffsets = currentBootstrapMethodOffsets;
}
/**
......@@ -2209,15 +2212,16 @@ public class ClassReader {
int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
Handle handle =
(Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
Object[] boostrapMethodArguments =
Object[] bootstrapMethodArguments =
new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
bootstrapMethodOffset += 4;
for (int i = 0; i < boostrapMethodArguments.length; i++) {
boostrapMethodArguments[i] =
for (int i = 0; i < bootstrapMethodArguments.length; i++) {
bootstrapMethodArguments[i] =
readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
bootstrapMethodOffset += 2;
}
methodVisitor.visitInvokeDynamicInsn(name, descriptor, handle, boostrapMethodArguments);
methodVisitor.visitInvokeDynamicInsn(
name, descriptor, handle, bootstrapMethodArguments);
currentOffset += 5;
break;
}
......@@ -3366,13 +3370,12 @@ public class ClassReader {
* @return the String corresponding to the specified CONSTANT_Utf8 entry.
*/
final String readUTF(final int constantPoolEntryIndex, final char[] charBuffer) {
String value = (String) cacheValues[constantPoolEntryIndex];
if (value != null) {
return value;
String value = (String) cpInfoValues[constantPoolEntryIndex];
if (value == null) {
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
value = readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
cpInfoValues[constantPoolEntryIndex] = value;
}
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
value = readUTF(cpInfoOffset + 2, readUnsignedShort(cpInfoOffset), charBuffer);
cacheValues[constantPoolEntryIndex] = value;
return value;
}
......@@ -3475,42 +3478,29 @@ public class ClassReader {
* pool table.
* @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
* large. It is not automatically resized.
* @return the Condy corresponding to the specified CONSTANT_Dynamic entry.
* @return the ConstantDynamic corresponding to the specified CONSTANT_Dynamic entry.
*/
private Condy readConstantDynamic(final int constantPoolEntryIndex, final char[] charBuffer) {
Condy condy = (Condy) cacheValues[constantPoolEntryIndex];
if (condy != null) {
return condy;
}
int offset = cpInfoOffsets[constantPoolEntryIndex];
condy = decodeConstantDynamic(offset, charBuffer);
cacheValues[constantPoolEntryIndex] = condy;
return condy;
}
/**
* Reads a CONSTANT_Dynamic constant pool entry at a constant pool offset.
*
* @param offset the start offset of an unsigned short value in {@link #b}, whose value is the
* index of a CONSTANT_Dynamic entry in class's constant pool table.
* @param charBuffer the buffer to be used to read the string. This buffer must be sufficiently
* large. It is not automatically resized.
* @return the Condy corresponding to the specified CONSTANT_Dynamic entry.
*/
private Condy decodeConstantDynamic(final int offset, final char[] charBuffer) {
int bsmIndex = bootstrapMethodOffsets[readUnsignedShort(offset)];
Handle bsm = (Handle) readConst(readUnsignedShort(bsmIndex), charBuffer);
int bsmArgCount = readUnsignedShort(bsmIndex + 2);
Object[] bsmArgs = new Object[bsmArgCount];
bsmIndex += 4;
for (int i = 0; i < bsmArgCount; i++) {
bsmArgs[i] = readConst(readUnsignedShort(bsmIndex), charBuffer);
bsmIndex += 2;
}
int cpOffset = cpInfoOffsets[readShort(offset + 2)];
String name = readUTF8(cpOffset, charBuffer);
String desc = readUTF8(cpOffset + 2, charBuffer);
return new Condy(name, desc, bsm, bsmArgs);
private ConstantDynamic readConstantDynamic(
final int constantPoolEntryIndex, final char[] charBuffer) {
ConstantDynamic constantDynamic = (ConstantDynamic) cpInfoValues[constantPoolEntryIndex];
if (constantDynamic == null) {
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
int nameAndTypeCpInfoOffset = cpInfoOffsets[readUnsignedShort(cpInfoOffset + 2)];
String name = readUTF8(nameAndTypeCpInfoOffset, charBuffer);
String descriptor = readUTF8(nameAndTypeCpInfoOffset + 2, charBuffer);
int bootstrapMethodOffset = bootstrapMethodOffsets[readUnsignedShort(cpInfoOffset)];
Handle handle = (Handle) readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
Object[] bootstrapMethodArguments = new Object[readUnsignedShort(bootstrapMethodOffset + 2)];
bootstrapMethodOffset += 4;
for (int i = 0; i < bootstrapMethodArguments.length; i++) {
bootstrapMethodArguments[i] =
readConst(readUnsignedShort(bootstrapMethodOffset), charBuffer);
bootstrapMethodOffset += 2;
}
constantDynamic = new ConstantDynamic(name, descriptor, handle, bootstrapMethodArguments);
cpInfoValues[constantPoolEntryIndex] = constantDynamic;
}
return constantDynamic;
}
/**
......@@ -3523,8 +3513,8 @@ public class ClassReader {
* @param charBuffer the buffer to be used to read strings. This buffer must be sufficiently
* large. It is not automatically resized.
* @return the {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String},
* {@link Type}, {@link Handle} or {@link Condy} corresponding to the specified constant pool
* entry.
* {@link Type}, {@link Handle} or {@link ConstantDynamic} corresponding to the specified
* constant pool entry.
*/
public Object readConst(final int constantPoolEntryIndex, final char[] charBuffer) {
int cpInfoOffset = cpInfoOffsets[constantPoolEntryIndex];
......
......@@ -779,7 +779,7 @@ public class ClassWriter extends ClassVisitor {
* @param bootstrapMethodArguments the bootstrap method constant arguments.
* @return the index of a new or already existing dynamic constant reference item.
*/
public int newCondy(
public int newConstantDynamic(
final String name,
final String descriptor,
final Handle bootstrapMethodHandle,
......
// ASM: a very small and fast Java bytecode manipulation framework
// Copyright (c) 2000-2011 INRIA, France Telecom
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// 3. Neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
// THE POSSIBILITY OF SUCH DAMAGE.
package org.objectweb.asm;
import java.util.Arrays;
/**
* A constant whose value is computed at runtime, with a bootstrap method.
*
* @author Remi Forax
*/
public final class ConstantDynamic {
/** The constant name (can be arbitrary). */
private final String name;
/** The constant type (must be a field descriptor). */
private final String descriptor;
/** The bootstrap method to use to compute the constant value at runtime. */
private final Handle bootstrapMethod;
/**
* The arguments to pass to the bootstrap method, in order to compute the constant value at
* runtime.
*/
private final Object[] bootstrapMethodArguments;
/**
* Constructs a new {@link ConstantDynamic}.
*
* @param name the constant name (can be arbitrary).
* @param descriptor the constant type (must be a field descriptor).
* @param bootstrapMethod the bootstrap method to use to compute the constant value at runtime.
* @param bootstrapMethodArguments the arguments to pass to the bootstrap method, in order to
* compute the constant value at runtime.
*/
public ConstantDynamic(
final String name,
final String descriptor,
final Handle bootstrapMethod,
final Object... bootstrapMethodArguments) {
this.name = name;
this.descriptor = descriptor;
this.bootstrapMethod = bootstrapMethod;
this.bootstrapMethodArguments = bootstrapMethodArguments;
}
/**
* Returns the name of this constant.
*
* @return the name of this constant.
*/
public String getName() {
return name;
}
/**
* Returns the type of this constant.
*
* @return the type of this constant, as a field descriptor.
*/
public String getDescriptor() {
return descriptor;
}
/**
* Returns the bootstrap method used to compute the value of this constant.
*
* @return the bootstrap method used to compute the value of this constant.
*/
public Handle getBootstrapMethod() {
return bootstrapMethod;
}
/**
* Returns the arguments to pass to the bootstrap method, in order to compute the value of this
* constant.
*
* @return the arguments to pass to the bootstrap method, in order to compute the value of this
* constant.
*/
public Object[] getBootstrapMethodArguments() {
return bootstrapMethodArguments;
}
@Override
public boolean equals(final Object object) {
if (object == this) {
return true;
}
if (!(object instanceof ConstantDynamic)) {
return false;
}
ConstantDynamic constantDynamic = (ConstantDynamic) object;
return name.equals(constantDynamic.name)
&& descriptor.equals(constantDynamic.descriptor)
&& bootstrapMethod.equals(constantDynamic.bootstrapMethod)
&& Arrays.equals(bootstrapMethodArguments, constantDynamic.bootstrapMethodArguments);
}
@Override
public int hashCode() {
return name.hashCode()
^ Integer.rotateLeft(descriptor.hashCode(), 8)
^ Integer.rotateLeft(bootstrapMethod.hashCode(), 16)
^ Integer.rotateLeft(Arrays.hashCode(bootstrapMethodArguments), 24);
}
@Override
public String toString() {
return name
+ " : "
+ descriptor
+ ' '
+ bootstrapMethod
+ ' '
+ Arrays.toString(bootstrapMethodArguments);
}
}
......@@ -42,19 +42,19 @@ public final class Handle {
* Opcodes#H_INVOKEVIRTUAL}, {@link Opcodes#H_INVOKESTATIC}, {@link Opcodes#H_INVOKESPECIAL},
* {@link Opcodes#H_NEWINVOKESPECIAL} or {@link Opcodes#H_INVOKEINTERFACE}.
*/
final int tag;
private final int tag;
/** The internal name of the class that owns the field or method designated by this handle. */
final String owner;
private final String owner;
/** The name of the field or method designated by this handle. */
final String name;
private final String name;
/** The descriptor of the field or method designated by this handle. */
final String descriptor;
private final String descriptor;
/** Whether the owner is an interface or not. */
final boolean isInterface;
private final boolean isInterface;
/**
* Constructs a new field or method handle.
......
......@@ -442,8 +442,8 @@ public abstract class MethodVisitor {
* @param bootstrapMethodHandle the bootstrap method.
* @param bootstrapMethodArguments the bootstrap method constant arguments. Each argument must be
* an {@link Integer}, {@link Float}, {@link Long}, {@link Double}, {@link String}, {@link
* Type}, {@link Handle} or {@link Condy} value. This method is allowed to modify the content
* of the array so a caller should expect that this array may change.
* Type}, {@link Handle} or {@link ConstantDynamic} value. This method is allowed to modify
* the content of the array so a caller should expect that this array may change.
*/
public void visitInvokeDynamicInsn(
final String name,
......@@ -529,8 +529,8 @@ public abstract class MethodVisitor {
* Integer}, a {@link Float}, a {@link Long}, a {@link Double}, a {@link String}, a {@link
* Type} of OBJECT or ARRAY sort for <tt>.class</tt> constants, for classes whose version is
* 49, a {@link Type} of METHOD sort for MethodType, a {@link Handle} for MethodHandle
* constants, for classes whose version is 51 or a {@link Condy} for a constant dynamic for
* classes whose version is 55.
* constants, for classes whose version is 51 or a {@link ConstantDynamic} for a constant
* dynamic for classes whose version is 55.
*/
public void visitLdcInsn(final Object value) {
if (api < Opcodes.ASM5
......@@ -538,7 +538,7 @@ public abstract class MethodVisitor {
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException(REQUIRES_ASM5);
}
if (api < Opcodes.ASM7 && value instanceof Condy) {
if (api < Opcodes.ASM7 && value instanceof ConstantDynamic) {
throw new UnsupportedOperationException("This feature requires ASM7");
}
if (mv != null) {
......
......@@ -254,7 +254,7 @@ final class SymbolTable {
case Symbol.CONSTANT_INVOKE_DYNAMIC_TAG:
nameAndTypeItemOffset =
classReader.getItem(classReader.readUnsignedShort(itemOffset + 2));
addConstantBootstrapReference(
addConstantDynamicOrInvokeDynamicReference(
itemTag,
itemIndex,
classReader.readUTF8(nameAndTypeItemOffset, charBuffer),
......@@ -499,11 +499,18 @@ final class SymbolTable {
} else if (value instanceof Handle) {
Handle handle = (Handle) value;
return addConstantMethodHandle(
handle.tag, handle.owner, handle.name, handle.descriptor, handle.isInterface);
} else if (value instanceof Condy) {
Condy condy = (Condy) value;
handle.getTag(),
handle.getOwner(),
handle.getName(),
handle.getDesc(),
handle.isInterface());
} else if (value instanceof ConstantDynamic) {
ConstantDynamic constantDynamic = (ConstantDynamic) value;
return addConstantDynamic(
condy.name, condy.descriptor, condy.bootstrapMethod, condy.bootstrapArguments);
constantDynamic.getName(),
constantDynamic.getDescriptor(),
constantDynamic.getBootstrapMethod(),
constantDynamic.getBootstrapMethodArguments());
} else {
throw new IllegalArgumentException("value " + value);
}
......@@ -888,7 +895,7 @@ final class SymbolTable {
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
return addConstantBootstrapReference(
return addConstantDynamicOrInvokeDynamicReference(
Symbol.CONSTANT_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
}
......@@ -909,7 +916,7 @@ final class SymbolTable {
final Handle bootstrapMethodHandle,
final Object... bootstrapMethodArguments) {
Symbol bootstrapMethod = addBootstrapMethod(bootstrapMethodHandle, bootstrapMethodArguments);
return addConstantBootstrapReference(
return addConstantDynamicOrInvokeDynamicReference(
Symbol.CONSTANT_INVOKE_DYNAMIC_TAG, name, descriptor, bootstrapMethod.index);
}
......@@ -925,7 +932,7 @@ final class SymbolTable {
* @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
* @return a new or already existing Symbol with the given value.
*/
private Symbol addConstantBootstrapReference(
private Symbol addConstantDynamicOrInvokeDynamicReference(
final int tag, final String name, final String descriptor, final int bootstrapMethodIndex) {
int hashCode = hash(tag, name, descriptor, bootstrapMethodIndex);
Entry entry = get(hashCode);
......@@ -953,11 +960,11 @@ final class SymbolTable {
* Symbol#CONSTANT_INVOKE_DYNAMIC_TAG}.
* @param index the constant pool index of the new Symbol.
* @param name a method name.
* @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG) or a method descriptor for
* @param descriptor a field descriptor for CONSTANT_DYNAMIC_TAG or a method descriptor for
* CONSTANT_INVOKE_DYNAMIC_TAG.
* @param bootstrapMethodIndex the index of a bootstrap method in the BootstrapMethods attribute.
*/
private void addConstantBootstrapReference(
private void addConstantDynamicOrInvokeDynamicReference(
final int index,
final int tag,
final String name,
......@@ -1048,11 +1055,10 @@ final class SymbolTable {
bootstrapMethodsAttribute = bootstrapMethods = new ByteVector();
}
// CONDY can be recursive (and INDY can have CONDY bootstrap method arguments)
// so reserve them as constant pool constant first so the call to
// addConstant() when writing will only use already existing constants
// This loop can also stackoverflow if a CONDY reference itself,
// let burn into flame at that point