co.paralleluniverse.fibers.instrument.Retransform Maven / Gradle / Ivy
/*
* Quasar: lightweight threads and actors for the JVM.
* Copyright (c) 2013-2016, Parallel Universe Software Co. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 3.0
* as published by the Free Software Foundation.
*/
package co.paralleluniverse.fibers.instrument;
import co.paralleluniverse.concurrent.util.MapUtil;
import java.io.PrintWriter;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.util.Textifier;
import org.objectweb.asm.util.TraceClassVisitor;
/**
*
* @author pron
*/
public class Retransform {
static volatile Instrumentation instrumentation;
static volatile QuasarInstrumentor instrumentor;
static volatile Set> classLoaders = Collections.newSetFromMap(MapUtil., Boolean>newConcurrentHashMap());
private static final CopyOnWriteArrayList listeners = new CopyOnWriteArrayList<>();
public static void retransform(Class> clazz) throws UnmodifiableClassException {
instrumentation.retransformClasses(clazz);
}
public static void redefine(Collection classDefinitions) {
try {
instrumentation.redefineClasses(classDefinitions.toArray(new ClassDefinition[0]));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static MethodDatabase getMethodDB(ClassLoader cl) {
return instrumentor.getMethodDatabase(cl);
}
public static QuasarInstrumentor getInstrumentor() {
return instrumentor;
}
public static boolean isInstrumented(Class clazz) {
return SuspendableHelper.isInstrumented(clazz);
}
// public static boolean isInstrumented(String className) {
// for (Iterator> it = classLoaders.iterator(); it.hasNext();) {
// final WeakReference ref = it.next();
// final ClassLoader loader = ref.get();
// if (loader == null)
// it.remove();
// else {
// try {
// if (isInstrumented(Class.forName(className, false, loader)))
// return true;
// } catch (ClassNotFoundException ex) {
// }
// }
// }
// return false;
// }
public static void addWaiver(String className, String methodName) {
SuspendableHelper.addWaiver(className, methodName);
}
public static boolean isWaiver(String className, String methodName) {
return SuspendableHelper.isWaiver(className, methodName);
}
public static Boolean isSuspendable(ClassLoader cl, String className, String methodName) {
final MethodDatabase.ClassEntry ce = getMethodDB(cl).getClassEntry(className);
if (ce == null)
return null;
return ce.isSuspendable(methodName);
}
static void beforeTransform(String className, Class clazz, byte[] data) {
for (ClassLoadListener listener : listeners)
listener.beforeTransform(className, clazz, data);
}
static void afterTransform(String className, Class clazz, byte[] data) {
for (ClassLoadListener listener : listeners)
listener.afterTransform(className, clazz, data);
}
public static void dumpClass(String className, byte[] data) {
System.err.println("DUMP OF CLASS: " + className);
ClassReader cr = new ClassReader(data);
ClassVisitor cv = new TraceClassVisitor(null, new Textifier(), new PrintWriter(System.err));
cr.accept(cv, ClassReader.SKIP_FRAMES);
System.out.println("=================");
}
public static void addClassLoadListener(ClassLoadListener listener) {
listeners.addIfAbsent(listener);
}
public interface ClassLoadListener {
void beforeTransform(String className, Class clazz, byte[] data);
void afterTransform(String className, Class clazz, byte[] data);
}
}