Commit a706a3b9 authored by Remi Forax's avatar Remi Forax

Remapper do not remap constant dynamic and handle correctly

parent 587e6821
......@@ -140,7 +140,7 @@ public class ClassRemapper extends ClassVisitor {
remapper.mapFieldName(className, name, descriptor),
remapper.mapDesc(descriptor),
remapper.mapSignature(signature, true),
remapper.mapValue(value));
(value == null) ? null : remapper.mapValue(value));
return fieldVisitor == null ? null : createFieldRemapper(fieldVisitor);
}
......
......@@ -28,7 +28,9 @@
package org.objectweb.asm.commons;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.signature.SignatureReader;
import org.objectweb.asm.signature.SignatureVisitor;
......@@ -144,9 +146,13 @@ public abstract class Remapper {
}
/**
* Returns the given value, remapped with this remapper.
* Returns the given value, remapped with this remapper. Possible values are {@link String},
* {@link Boolean}, {@link Byte}, {@link Short}, {@link Character}, {@link Integer}, {@link Long},
* {@link Double}, {@link Float}, {@link String}, {@link Type}, {@link Handle}, {@link
* ConstantDynamic} or arrays of primitive types .
*
* @param value an object. Only {@link Type} and {@link Handle} values are remapped.
* @param value an object. Only {@link Type}, {@link Handle} and {@link ConstantDynamic} values
* are remapped.
* @return the given value, remapped with this remapper.
*/
public Object mapValue(final Object value) {
......@@ -159,9 +165,25 @@ public abstract class Remapper {
handle.getTag(),
mapType(handle.getOwner()),
mapMethodName(handle.getOwner(), handle.getName(), handle.getDesc()),
mapMethodDesc(handle.getDesc()),
handle.getTag() <= Opcodes.H_PUTSTATIC
? mapDesc(handle.getDesc())
: mapMethodDesc(handle.getDesc()),
handle.isInterface());
}
if (value instanceof ConstantDynamic) {
ConstantDynamic constantDynamic = (ConstantDynamic) value;
Object[] bootstrapMethodArguments = constantDynamic.getBootstrapMethodArguments();
Object[] remappedBootstrapMethodArguments = new Object[bootstrapMethodArguments.length];
for (int i = 0; i < bootstrapMethodArguments.length; ++i) {
remappedBootstrapMethodArguments[i] = mapValue(bootstrapMethodArguments[i]);
}
String descriptor = constantDynamic.getDescriptor();
return new ConstantDynamic(
mapInvokeDynamicMethodName(constantDynamic.getName(), descriptor),
mapDesc(descriptor),
(Handle) mapValue(constantDynamic.getBootstrapMethod()),
remappedBootstrapMethodArguments);
}
return value;
}
......@@ -228,8 +250,8 @@ public abstract class Remapper {
}
/**
* Maps an invokedynamic method name to its new name. The default implementation of this method
* returns the given name, unchanged. Subclasses can override.
* Maps an invokedynamic or a constant dynamic method name to its new name. The default
* implementation of this method returns the given name, unchanged. Subclasses can override.
*
* @param name the name of the method.
* @param descriptor the descriptor of the method.
......
......@@ -37,9 +37,14 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.ConstantDynamic;
import org.objectweb.asm.Handle;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.test.AsmTest;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.util.CheckMethodAdapter;
/**
......@@ -67,7 +72,7 @@ public class ClassRemapperTest extends AsmTest {
new Remapper() {
@Override
public String mapModuleName(String name) {
public String mapModuleName(final String name) {
return "new." + name;
}
});
......@@ -78,6 +83,49 @@ public class ClassRemapperTest extends AsmTest {
assertEquals("new.pkg.C", ((ModuleHashesAttribute) classNode.attrs.get(0)).modules.get(0));
}
@Test
public void testRenameConstantDynamic() {
ClassNode classNode = new ClassNode();
ClassRemapper classRemapper =
new ClassRemapper(
Opcodes.ASM7_EXPERIMENTAL,
classNode,
new Remapper() {
@Override
public String mapInvokeDynamicMethodName(final String name, final String descriptor) {
return "new." + name;
}
@Override
public String map(final String internalName) {
if (internalName.equals("java/lang/String")) {
return "java/lang/Integer";
}
return internalName;
}
}) {
/* inner class so it can access to the protected constructor */
};
classRemapper.visit(Opcodes.V11, Opcodes.ACC_PUBLIC, "C", null, "java/lang/Object", null);
MethodVisitor methodVisitor =
classRemapper.visitMethod(Opcodes.ACC_PUBLIC, "hello", "()V", null, null);
methodVisitor.visitCode();
methodVisitor.visitLdcInsn(
new ConstantDynamic(
"foo",
"Ljava/lang/String;",
new Handle(Opcodes.H_INVOKESTATIC, "BSMHost", "bsm", "()Ljava/lang/String;", false)));
methodVisitor.visitInsn(Opcodes.POP);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
classRemapper.visitEnd();
ConstantDynamic constantDynamic =
(ConstantDynamic) ((LdcInsnNode) classNode.methods.get(0).instructions.get(0)).cst;
assertEquals("new.foo", constantDynamic.getName());
assertEquals("Ljava/lang/Integer;", constantDynamic.getDescriptor());
assertEquals("()Ljava/lang/Integer;", constantDynamic.getBootstrapMethod().getDesc());
}
/** Tests that classes transformed with a ClassRemapper can be loaded and instantiated. */
@ParameterizedTest
@MethodSource(ALL_CLASSES_AND_ALL_APIS)
......@@ -179,6 +227,27 @@ public class ClassRemapperTest extends AsmTest {
public String map(final String typeName) {
return typeName.equals(internalClassName) ? remappedInternalClassName : typeName;
}
@Override
public Object mapValue(Object value) {
if (value instanceof String
|| value instanceof Boolean
|| value instanceof Byte
|| value instanceof Short
|| value instanceof Character
|| value instanceof Integer
|| value instanceof Long
|| value instanceof Double
|| value instanceof Float
|| value instanceof Type
|| value instanceof Handle
|| value instanceof ConstantDynamic
|| value.getClass().isArray()) {
return super.mapValue(value);
}
// If this fails, add support for the new type in Remapper.mapValue(), if needed.
throw new IllegalArgumentException("Unsupported type of value: " + value);
}
}
private static void checkDescriptor(final String descriptor) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment