TtlForkJoinTransformlet.java 3.8 KB
Newer Older
1
package com.alibaba.ttl.threadpool.agent.internal.transformlet.impl;
2

3
import com.alibaba.ttl.threadpool.agent.internal.logging.Logger;
4
import com.alibaba.ttl.threadpool.agent.internal.transformlet.JavassistTransformlet;
5 6 7 8 9
import javassist.*;

import java.io.IOException;
import java.lang.reflect.Modifier;

oldratlee's avatar
oldratlee 已提交
10
import static com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.getCtClass;
11
import static com.alibaba.ttl.threadpool.agent.internal.transformlet.impl.Utils.signatureOfMethod;
oldratlee's avatar
oldratlee 已提交
12

13 14 15 16 17 18 19 20 21 22
/**
 * TTL {@link JavassistTransformlet} for {@link java.util.concurrent.ForkJoinTask}.
 *
 * @author Jerry Lee (oldratlee at gmail dot com)
 * @author wuwen5 (wuwen.55 at aliyun dot com)
 * @see java.util.concurrent.ForkJoinPool
 * @see java.util.concurrent.ForkJoinTask
 * @since 2.5.1
 */
public class TtlForkJoinTransformlet implements JavassistTransformlet {
23
    private static final Logger logger = Logger.getLogger(TtlForkJoinTransformlet.class);
24 25 26 27 28
    private static final String FORK_JOIN_TASK_CLASS_NAME = "java.util.concurrent.ForkJoinTask";
    private static final String TTL_RECURSIVE_ACTION_CLASS_NAME = "com.alibaba.ttl.TtlRecursiveAction";
    private static final String TTL_RECURSIVE_TASK_CLASS_NAME = "com.alibaba.ttl.TtlRecursiveTask";

    @Override
oldratlee's avatar
oldratlee 已提交
29 30 31 32 33 34 35
    public byte[] doTransform(String className, byte[] classFileBuffer, ClassLoader loader) throws IOException, NotFoundException, CannotCompileException {
        if (FORK_JOIN_TASK_CLASS_NAME.equals(className)) {
            final CtClass clazz = getCtClass(classFileBuffer, loader);
            updateForkJoinTaskClass(clazz);
            return clazz.toBytecode();
        }
        return null;
36 37 38 39 40 41 42
    }

    private void updateForkJoinTaskClass(final CtClass clazz) throws CannotCompileException, NotFoundException {
        // add new field
        final String className = clazz.getName();

        final String capturedFieldName = "captured$field$add$by$ttl";
oldratlee's avatar
oldratlee 已提交
43
        final CtField capturedField = CtField.make("private final Object " + capturedFieldName + ";", clazz);
44 45 46
        clazz.addField(capturedField, "com.alibaba.ttl.TransmittableThreadLocal.Transmitter.capture();");
        logger.info("add new field " + capturedFieldName + " to class " + className);

oldratlee's avatar
oldratlee 已提交
47 48
        final CtMethod doExecMethod = clazz.getDeclaredMethod("doExec", new CtClass[0]);
        final CtMethod new_doExecMethod = CtNewMethod.copy(doExecMethod, clazz, null);
49 50

        // rename original doExec method, and set to private method(avoid reflect out renamed method unexpectedly)
oldratlee's avatar
oldratlee 已提交
51
        final String original_doExec_method_rename = "original$" + doExecMethod.getName()+ "$method$renamed$by$ttl";
52 53 54 55 56 57 58 59 60
        doExecMethod.setName(original_doExec_method_rename);
        doExecMethod.setModifiers(doExecMethod.getModifiers() & ~Modifier.PUBLIC /* remove public */ | Modifier.PRIVATE /* add private */);

        // set new doExec method implementation
        final String code = "{\n" +
                // do nothing/directly return, if is TTL ForkJoinTask instance
                "if (this instanceof " + TTL_RECURSIVE_ACTION_CLASS_NAME + " || this instanceof " + TTL_RECURSIVE_TASK_CLASS_NAME + ") {\n" +
                "    return " + original_doExec_method_rename + "($$);\n" +
                "}\n" +
oldratlee's avatar
oldratlee 已提交
61
                "Object backup = com.alibaba.ttl.TransmittableThreadLocal.Transmitter.replay(" + capturedFieldName + ");\n" +
62 63 64 65 66 67 68
                "try {\n" +
                "    return " + original_doExec_method_rename + "($$);\n" +
                "} finally {\n" +
                "    com.alibaba.ttl.TransmittableThreadLocal.Transmitter.restore(backup);\n" +
                "}\n" + "}";
        new_doExecMethod.setBody(code);
        clazz.addMethod(new_doExecMethod);
oldratlee's avatar
oldratlee 已提交
69
        logger.info("insert code around method " + signatureOfMethod(doExecMethod) + " of class " + className + ": " + code);
70 71
    }
}