/** Generate class bytes for java.lang.Runnable implementation and return the same. */ public byte[] generate(Method method, String className) { int modifiers = method.getModifiers(); // make sure that the method is public static // and accepts no arguments if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers) || method.getParameterTypes().length != 0) { throw new IllegalArgumentException(); } Class clazz = method.getDeclaringClass(); modifiers = clazz.getModifiers(); // make sure that the class is public as well if (!Modifier.isPublic(modifiers)) { throw new IllegalArgumentException(); } ClassWriter cw = InstrumentUtils.newClassWriter(); cw.visit( V1_1, ACC_PUBLIC, className, null, "java/lang/Object", new String[] {"java/lang/Runnable"}); // creates a MethodWriter for the (implicit) constructor MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); // pushes the 'this' variable mw.visitVarInsn(ALOAD, 0); // invokes the super class constructor mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); mw.visitInsn(RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); // creates a MethodWriter for the 'main' method mw = cw.visitMethod(ACC_PUBLIC, "run", "()V", null, null); // invokes the given method mw.visitMethodInsn( INVOKESTATIC, Type.getInternalName(method.getDeclaringClass()), method.getName(), Type.getMethodDescriptor(method)); mw.visitInsn(RETURN); mw.visitMaxs(1, 1); mw.visitEnd(); return cw.toByteArray(); }
/** * Checks the type compatibility<br> * Two types are compatible when and only when: * * <ol> * <li>They are exactly the same * <li>The left parameter is {@linkplain Object} or {@linkplain AnyType} and the right parameter * is either {@linkplain Object} or an array * <li>The left parameter is assignable from the right one (is a superclass of the right one) * </ol> * * @param left The left type parameter * @param right The right type parameter * @return Returns true if a value of the left {@linkplain Type} can hold the value of the right * {@linkplain Type} */ public static boolean isCompatible(Type left, Type right) { if (left.equals(right)) { return true; } else if (isArray(left)) { return false; } else if (isObjectOrAnyType(left)) { int sort2 = right.getSort(); return (sort2 == Type.OBJECT || sort2 == Type.ARRAY); } else if (isPrimitive(left)) { // a primitive type requires strict equality return left.equals(right); } else { ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (cl == null) { cl = ClassLoader.getSystemClassLoader(); } // those classes should already have been loaded at this point Class clzLeft, clzRight; try { clzLeft = cl.loadClass(left.getClassName()); } catch (Throwable e) { clzLeft = Object.class; } // anything is assignable to Object if (clzLeft == Object.class) { return true; } try { clzRight = cl.loadClass(right.getClassName()); } catch (Throwable e) { clzRight = Object.class; } return (clzLeft.isAssignableFrom(clzRight)); } }
public static void main(String[] args) throws Exception { if (args.length != 1) { System.err.println("Usage: java com.sun.btrace.runtime.RunnableGenartor <class>"); System.exit(1); } Class clazz = Class.forName(args[0]); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { int modifiers = method.getModifiers(); int index = 0; RunnableGenerator gen = new RunnableGeneratorImpl(); if (Modifier.isStatic(modifiers) || Modifier.isPublic(modifiers) || method.getParameterTypes().length == 0) { try { final String className = "Runnable$" + index; final byte[] bytes = gen.generate(method, className); ClassLoader loader = new ClassLoader() { public Class findClass(String name) throws ClassNotFoundException { if (name.equals(className)) { return defineClass(className, bytes, 0, bytes.length); } throw new ClassNotFoundException(name); } }; Runnable r = (Runnable) loader.loadClass(className).newInstance(); new Thread(r).start(); } catch (Exception exp) { exp.printStackTrace(); } } index++; } }