下面列出了org.objectweb.asm.ClassWriter#COMPUTE_FRAMES 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
/**
* Creates a new class prepared to be loaded into the {@link ClassLoader}.
*
* @param type The type of class to implement
* @param name The name of the class
* @param exceptionType The exception type to throw for all methods
* @return The generated class
*/
public byte[] createClass(final Class<?> type, final String name, final Class<?> exceptionType) {
checkNotNull(type, "type");
checkNotNull(name, "name");
checkNotNull(exceptionType, "exception");
checkState(type.isInterface(), String.format("Class %s is not an interface!", type));
checkState(Throwable.class.isAssignableFrom(exceptionType), String.format("Class %s does not extend Throwable!", exceptionType));
String internalName = name.replace('.', '/');
List<Method> methods = this.getInterfaceMethods(type);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, internalName, null, Type.getInternalName(Object.class), new String[] {Type.getInternalName(type)});
this.generateConstructor(cw, internalName);
this.generateMethods(cw, internalName, methods, exceptionType);
cw.visitEnd();
return cw.toByteArray();
}
public byte[] transform(byte[] original, Collection<String> retransformClasses) {
ClassReader reader = new ClassReader(original);
ClassWriter writer = new OfflineClassWriter(classHierarchy, reader, ClassWriter.COMPUTE_FRAMES);
ContinuableClassVisitor visitor = new ContinuableClassVisitor(
writer, /* BytecodeDebugUtils.decorateClassVisitor(cw, true, * System.err) -- DUMP*/
classHierarchy,
cciResolver,
original
);
cciResolver.reset(retransformClasses);
try {
reader.accept(visitor, ClassReader.SKIP_FRAMES);
} catch (StopException ex) {
// Preliminary stop visiting non-continuable class
return null;
}
if (visitor.skipEnchancing()) {
return null;
}
byte[] bytecode = writer.toByteArray();
// BytecodeDebugUtils.dumpClass(bytecode);
return bytecode;
}
private byte[] transformClass(byte[] basicClass, Consumer<ClassNode> transformer) {
ClassReader reader = new ClassReader(basicClass);
ClassNode classNode = new ClassNode();
reader.accept(classNode, 0);
transformer.accept(classNode);
SafeClassWriter writer = new SafeClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES) {
@Override
protected String getCommonSuperClass(final String type1, final String type2) {
// the default asm merge uses Class.forName(), this prevents that.
return "java/lang/Object";
}
};
classNode.accept(writer);
return writer.toByteArray();
}
/**
* Generates and returns the bytecode for an exception class.
*
* @param name The name of the class to generate.
* @param superName The name of the superclass.
* @return The bytecode for the new class.
*/
public static byte[] generateExceptionClass(String name, String superName) {
ClassWriter out = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
// This class only exists to be a type - the superclasses always do everything.
// (common access for all classes we generate - public and "super", meaning post-1.1 invokestatic).
int access = Opcodes.ACC_PUBLIC | Opcodes.ACC_SUPER;
// We ignore generics, so null signature.
String signature = null;
// We implement no interfaces.
String[] interfaces = new String[0];
out.visit(CLASS_VERSION, access, name, signature, superName, interfaces);
// Generate the constructors.
populateExceptionConstructors(out, superName);
// Finish this and dump the bytes.
out.visitEnd();
return out.toByteArray();
}
byte[] compile(final String name) {
// class header
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_7, ACC_PUBLIC, name, null, "java/lang/Object", null);
// eval method type
StringBuilder desc = new StringBuilder("(");
for (int i = 0; i <= getMaxVarIndex(); ++i) {
desc.append("Ljava/lang/Object;");
}
desc.append(")Ljava/lang/Object;");
// eval method
MethodVisitor mv =
cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "eval", desc.toString(), null, null);
compile(mv);
mv.visitInsn(ARETURN);
// max stack and max locals automatically computed
mv.visitMaxs(0, 0);
mv.visitEnd();
return cw.toByteArray();
}
private static byte[] transform(byte[] serverClass, boolean isObfuscated, transformType type)
{
System.out.println("MALMO: Attempting to transform MinecraftServer");
try
{
ClassNode cnode = new ClassNode();
ClassReader creader = new ClassReader(serverClass);
creader.accept(cnode, 0);
switch (type)
{
case SERVER:
overclockServer(cnode, isObfuscated);
break;
case RENDERER:
overclockRenderer(cnode, isObfuscated);
break;
case OTHERPLAYER:
removeInterpolation(cnode, isObfuscated);
break;
case TEXTURES:
insertTextureHandler(cnode, isObfuscated);
}
ClassWriter cwriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
cnode.accept(cwriter);
return cwriter.toByteArray();
}
catch (Exception e)
{
System.out.println("MALMO FAILED to transform MinecraftServer - overclocking not available!");
}
return serverClass;
}
public byte[] transform() {
ClassReader cr = new ClassReader(code);
ClassWriter cw = new ConcClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES, clloader.getDetector());//NOT doing frames etc here, ok i guess as nothing changes
ReflecClassVisitor mma = new ReflecClassVisitor(cw);
cr.accept(mma, 0);
return cw.toByteArray();
}
private byte[] buildOptimizedJar(Set<String> visitedClasses, Map<String, byte[]> classMap, String mainClassName) {
if (loggingEnabled) {
System.out.println("Need to remove " + (classMap.entrySet().size() - visitedClasses.size()) + " out of " + classMap.entrySet().size() + " classes.");
classMap.forEach((key, value) -> {
if (!visitedClasses.contains(key)) {
System.out.println(" - " + key);
}
});
}
classMap.entrySet().removeIf(e -> !visitedClasses.contains(e.getKey()));
// update outer class bytes of removed inner classes
for (String className : visitedClasses) {
ClassReader reader = new ClassReader(classMap.get(className));
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM6, writer) {
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
if (visitedClasses.contains(name)) {
super.visitInnerClass(name, outerName, innerName, access);
}
}
};
reader.accept(classVisitor, 0);
classMap.replace(className, writer.toByteArray());
}
assertTrue(classMap.entrySet().size() == visitedClasses.size());
byte[] mainClassBytes = classMap.get(mainClassName);
classMap.remove(mainClassName, mainClassBytes);
return JarBuilder.buildJarForExplicitClassNamesAndBytecode(mainClassName, mainClassBytes, classMap);
}
default byte[] transform(byte[] input, String classname, BuildContext context) {
ClassReader reader = new ClassReader(input);
ClassNode cn = new ClassNode();
reader.accept(cn, 0);
transform(cn, classname, context);
SafeClassWriter writer = new SafeClassWriter(context.task.reader, ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
cn.accept(writer);
return writer.toByteArray();
}
@Override
public byte[] transform(String name, String transformedName,
byte[] basicClass)
{
if(!visitors.containsKey(transformedName))
return basicClass;
System.out.println(
"Transforming " + transformedName + ", obfuscated=" + obfuscated);
try
{
ClassReader reader = new ClassReader(basicClass);
ClassWriter writer = new ClassWriter(
ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
ClassVisitor visitor = visitors.get(transformedName)
.getConstructor(ClassVisitor.class, boolean.class)
.newInstance(writer, obfuscated);
reader.accept(visitor, 0);
return writer.toByteArray();
}catch(Exception e)
{
e.printStackTrace();
return basicClass;
}
}
@Override
public byte[] transform(String s, String s1, byte[] bytes) {
LogUtil.startClass("EntityPlayerSP (%s)", Names.abstractClientPlayer.getName());
ClassReader reader = new ClassReader(bytes);
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
ClassPatcher visitor = new ClassPatcher(writer);
reader.accept(visitor, 0);
LogUtil.endClass();
return writer.toByteArray();
}
@SuppressWarnings("unchecked")
public <T extends TypeEntry> void emitOuterType(T ast) {
ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
this.cw = writer;
if (VERIFY_EMITTED_BYTECODE) {
this.cw = new CheckClassAdapter(this.cw);
}
AstEmitter<AbstractEmitterContext, T> emitter = (AstEmitter<AbstractEmitterContext, T>) this.set.getAstEmitter(ast.getClass());
if (emitter == null) {
throw new IllegalArgumentException("No emitter for ast entry " + ast.getClass().getName());
}
emitter.emit(this, ast);
this.cw.visitEnd();
byte[] clazz = writer.toByteArray();
if (DUMP_INSTRUCTIONS_AFTER_WRITE) {
ClassReader cr = new ClassReader(clazz);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);
List<MethodNode> methods = cn.methods;
for (MethodNode mn : methods) {
System.out.println("Method: " + mn.name + mn.desc);
Printer printer = new Textifier();
TraceMethodVisitor mp = new TraceMethodVisitor(printer);
for (Iterator<AbstractInsnNode> it = mn.instructions.iterator(); it.hasNext();) {
AbstractInsnNode insn = it.next();
insn.accept(mp);
}
StringWriter sw = new StringWriter();
printer.print(new PrintWriter(sw));
String s = sw.toString();
if (s.endsWith("\n")) {
s = s.substring(0, s.length() - 1);
}
System.out.println(s);
mn.instructions.accept(mp);
}
}
try {
this.out.write(clazz);
} catch (IOException e) {
Throwables.propagate(e);
}
}
public HashMap<String, byte[]> transform(String name, ConcClassUtil clloader) {
ClassReader cr = new ClassReader(this.inputClassBytes);
//calculate the maxlocals for each method
HashMap<String, Integer> maxlocalMap = this.mfl.getMaxlocalMap(name, cr);
//find private constructors used within nested static functions or classes
UsedPrivConstruFinder upcf = new UsedPrivConstruFinder();
cr.accept(upcf, 0);
HashSet<OwnerNameDesc> shouldbeForcedPublic = upcf.shouldbeForcedPublic;
HashSet<OwnerNameDesc> shouldbeForcedPublicField = upcf.shouldbeForcedPublicField;
ClassWriter cw = new ConcClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS, clloader.getDetector());// TODO: turn off compute frames?
// cv forwards all events to cw
StaticRedirector staticRedirector = new StaticRedirector(this.staticLambdaClasses, cw, maxlocalMap, clloader, shouldbeForcedPublic, shouldbeForcedPublicField);
cr.accept(staticRedirector, 0);
globalizerClasses.put(name, cw.toByteArray());
//TODO: only redirect if in staticLambdaClasses
if(staticLambdaClasses == null || staticLambdaClasses.contains(name)) {
HashSet<OwnerNameDesc> methodsWhichWereForcedPublic = staticRedirector.methodsWhichWereForcedPublic;
if(!staticRedirector.origClassClinitToNewOne.isEmpty()){
for(String clsName : staticRedirector.origClassClinitToNewOne.keySet()){
String globName = staticRedirector.origClassClinitToNewOne.get(clsName);
ClassWriter gcw = new ConcClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS, clloader.getDetector() );// TODO: turn off compute frames?
StaticFinalVariableFinder sfvf = new StaticFinalVariableFinder();
cr.accept(sfvf, 0);
ArrayList<FieldVisitorHolder> staticFinalVars = sfvf.staticFinalVars;
GlobalClassGennerator gcg = new GlobalClassGennerator(this.staticLambdaClasses, gcw, clsName, globName, maxlocalMap, clloader, methodsWhichWereForcedPublic, staticFinalVars);
cr.accept(gcg, 0);
globalizerClasses.put(globName, gcw.toByteArray());
}
}
}
return globalizerClasses; // b2 represents the same class as b1
}
private Class<?> createHandler(Method callback) {
// ClassName$methodName_EventClass_XXX
String name = objName + "$" + callback.getName() + "_" + callback.getParameters()[0].getType().getSimpleName() + "_" + (ID++);
String eventType = Type.getInternalName(callback.getParameterTypes()[0]);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
MethodVisitor mv;
String desc = name.replace(".", "/");
String instanceClassName = instance.getClass().getName().replace(".", "/");
cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER, desc, null, "java/lang/Object", new String[]{ "cc/hyperium/event/EventSubscriber$EventHandler" });
cw.visitSource(".dynamic", null);
{
cw.visitField(ACC_PUBLIC, "instance", "Ljava/lang/Object;", null, null).visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Object;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, desc, "instance", "Ljava/lang/Object;");
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, "handle", "(Ljava/lang/Object;)V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, desc, "instance", "Ljava/lang/Object;");
mv.visitTypeInsn(CHECKCAST, instanceClassName);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, eventType);
mv.visitMethodInsn(INVOKEVIRTUAL, instanceClassName, callback.getName(), Type.getMethodDescriptor(callback), false);
mv.visitInsn(RETURN);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
cw.visitEnd();
byte[] handlerClassBytes = cw.toByteArray();
return LOADER.define(name, handlerClassBytes);
}
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER,
"com/beetl/performance/lab/asm/UserAsmAccessor1", null,
"java/lang/Object",
new String[] { "com/beetl/performance/lab/asm/Access" });
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",
"()V");
mv.visitInsn(RETURN);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(
ACC_PUBLIC,
"get",
"(Ljava/lang/Object;I)Ljava/lang/Object;",
null,
new String[] { "com/beetl/performance/lab/asm/ASMCastException" });
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, "java/lang/Exception");
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, 3);
mv.visitLabel(l0);
mv.visitVarInsn(ALOAD, 1);
mv.visitTypeInsn(CHECKCAST, "com/beetl/performance/lab/User");
mv.visitVarInsn(ASTORE, 3);
mv.visitLabel(l1);
Label l3 = new Label();
mv.visitJumpInsn(GOTO, l3);
mv.visitLabel(l2);
mv.visitFrame(Opcodes.F_FULL, 4, new Object[] {
"com/beetl/performance/lab/asm/UserAsmAccessor",
"java/lang/Object", Opcodes.INTEGER,
"com/beetl/performance/lab/User" }, 1,
new Object[] { "java/lang/Exception" });
mv.visitVarInsn(ASTORE, 4);
mv.visitTypeInsn(NEW,
"com/beetl/performance/lab/asm/ASMCastException");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL,
"com/beetl/performance/lab/asm/ASMCastException", "<init>",
"()V");
mv.visitInsn(ATHROW);
mv.visitLabel(l3);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ILOAD, 2);
Label l4 = new Label();
Label l5 = new Label();
Label l6 = new Label();
mv.visitTableSwitchInsn(1, 2, l6, new Label[] { l4, l5 });
mv.visitLabel(l4);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "com/beetl/performance/lab/User",
"getName", "()Ljava/lang/String;");
mv.visitInsn(ARETURN);
mv.visitLabel(l5);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, "com/beetl/performance/lab/User",
"getId", "()I");
mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf",
"(I)Ljava/lang/Integer;");
mv.visitInsn(ARETURN);
mv.visitLabel(l6);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException",
"<init>", "()V");
mv.visitInsn(ATHROW);
mv.visitMaxs(2, 5);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
private byte[] mergeClasses(byte[] baseClass, byte[] classToMerge) throws IOException {
// read the classes into ClassNode objects
ClassNode baseClassNode = BytecodeUtils.getClassNode(baseClass);
ClassNode classToMergeClassNode = BytecodeUtils.getClassNode(classToMerge);
// get a list of base methods conflicting with methods to merge
BaseMethodsIdentifier baseMethodsIdentifier = new BaseMethodsIdentifier(baseClassNode);
LinkedList<MethodNode> baseMethods = baseMethodsIdentifier.getBaseMethods();
// identify methods to insert or replace
DefineIdentifier defineMethodsIdentifier = new DefineIdentifier(classToMergeClassNode);
LinkedList<DefineMethodAnnotation> methodsToDefine = defineMethodsIdentifier.getDefineMethodAnnotations();
// identify methods to merge
MergeIdentifier mergeIdentifier = new MergeIdentifier(classToMergeClassNode);
LinkedList<MergeMethodAnnotation> methodToMergeAnnotations = mergeIdentifier.getMergeMethodAnnotations();
// rename base methods that should be preserved
LinkedList<String> renamedMethods = new LinkedList<String>();
for(MergeMethodAnnotation methodToMergeAnnotation : methodToMergeAnnotations){
MethodNode methodToMerge = methodToMergeAnnotation.getMethodNode();
boolean foundTargetMethod = false;
for(MethodNode baseMethod : baseMethods){
if(methodToMerge.signature != null && baseMethod.signature != null){
if(methodToMerge.signature.equals(baseMethod.signature)){
if(methodToMerge.name.equals(baseMethod.name) && methodToMerge.desc.equals(baseMethod.desc)){
renamedMethods.add(baseClassNode.name + "." + renameMethod(baseMethod));
foundTargetMethod = true;
continue;
}
}
} else {
// signature was null, fall back to name and description only
if(methodToMerge.name.equals(baseMethod.name) && methodToMerge.desc.equals(baseMethod.desc)){
renamedMethods.add(baseClassNode.name + "." + renameMethod(baseMethod));
foundTargetMethod = true;
continue;
}
}
}
if(!foundTargetMethod){
Log.warning("Target method " + methodToMerge.desc.toString() + " does not exist! Runtime behavior may not be correct.");
}
}
// purge defined methods that were already there
// adapt a ClassWriter with the PurgeAdapter
ClassWriter classWriter = new ClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
Set<MethodNode> methodsToPurge = new HashSet<MethodNode>();
for(DefineMethodAnnotation methodToDefine : methodsToDefine){
methodsToPurge.add(methodToDefine.getMethodNode());
}
Set<FieldNode> fieldsToPurge = new HashSet<FieldNode>();
PurgeAdapter purgeAdapter = new PurgeAdapter(classWriter, methodsToPurge, fieldsToPurge);
ClassReader purgedBaseClassReader = new ClassReader(BytecodeUtils.writeClass(baseClassNode));
purgedBaseClassReader.accept(purgeAdapter, ClassReader.EXPAND_FRAMES);
baseClassNode = BytecodeUtils.getClassNode(classWriter.toByteArray());
// merge the classes
// adapt a ClassWriter with the MergeAdapter
// modifiedBaseClass, classToMerge -> MergeAdapter -> ClassWriter
classWriter = new ClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
MergeAdapter mergeAdapter = new MergeAdapter(classWriter, classToMergeClassNode, mergeRenamePrefix, renamedMethods);
ClassReader modifiedBaseClassReader = new ClassReader(BytecodeUtils.writeClass(baseClassNode));
modifiedBaseClassReader.accept(mergeAdapter, ClassReader.EXPAND_FRAMES);
return classWriter.toByteArray();
}
public static byte[] makeExample() throws Throwable {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_7, ACC_PUBLIC | ACC_SUPER, "ComplexIndy", null, "java/lang/Object", null);
MethodVisitor mv;
{
mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "gwtTest", "(Ljava/lang/Object;)Ljava/lang/String;", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitInvokeDynamicInsn("gwtBootstrap", "(Ljava/lang/Object;)Ljava/lang/String;",
new Handle(
H_INVOKESTATIC,
"BootstrapMethods",
"fibBootstrap",
Type.getType(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"
).getDescriptor())
);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC | ACC_STATIC, "fibIndy", "(I)I", null, null);
mv.visitCode();
mv.visitVarInsn(ILOAD, 0);
mv.visitInvokeDynamicInsn("fibBootstrap", "(I)I",
new Handle(
H_INVOKESTATIC,
"BootstrapMethods",
"fibBootstrap",
Type.getType(
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"
).getDescriptor())
);
mv.visitInsn(IRETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
@Override
public byte[] transform(String name, String realName, byte[] bytes) {
if (transformingLevel > 0) {
LOGGER.warn("Reentrant class loaded {} at level {}", realName, transformingLevel);
}
++transformingLevel;
if (transformingClasses.containsKey(realName)) {
ClassTransformer transformer = transformingClasses.get(realName);
try {
LOGGER.info("Transforming class " + realName);
ClassNode classNode = new ClassNode();
ClassReader classReader = new ClassReader(bytes);
classReader.accept(classNode, 0);
transformer.transform(classNode);
ClassWriter classWriter =
new NoClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
// let gc clean this up
transformingClasses.remove(realName);
bytes = classWriter.toByteArray();
} catch (Exception e) {
LOGGER.error(
e.getClass().getSimpleName()
+ " thrown from transforming class "
+ realName
+ ": "
+ e.getMessage());
ASMStackLogger.printStackTrace(e);
}
}
--transformingLevel;
return bytes;
}
/**
* Writes a class to a byte array
* @param classNode
* @param classFile
* @throws IOException
*/
public static byte[] writeClass(ClassNode classNode) throws IOException {
ClassWriter classWriter = new ClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}
/**
* Writes a class to a byte array
* @param classNode
* @param classFile
* @throws IOException
*/
public static byte[] writeClass(ClassNode classNode) throws IOException {
ClassWriter classWriter = new ClassLoadingClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
classNode.accept(classWriter);
return classWriter.toByteArray();
}