Package joust.utils.compiler

Source Code of joust.utils.compiler.JavacBrutaliser

package joust.utils.compiler;

import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.CompileStates;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.comp.Todo;
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Pair;
import joust.JOUST;
import joust.optimisers.runnables.OptimisationRunnable;
import joust.utils.ReflectionUtils;
import joust.utils.logging.LogUtils;
import lombok.experimental.ExtensionMethod;
import lombok.extern.java.Log;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Queue;
import java.util.logging.Logger;

import static com.sun.tools.javac.tree.JCTree.*;
import static joust.utils.ReflectionUtils.*;
import static joust.utils.compiler.StaticCompilerUtils.javaCompiler;
import static joust.utils.compiler.OptimisationPhaseManager.EventType.*;

/**
* The class we don't like to talk about. Nothing to see here.
*/
@Log
@ExtensionMethod({Logger.class, LogUtils.LogExtensions.class})
public final class JavacBrutaliser extends OptimisationRunnable {
    /**
     * Convince javac to desugar everything for us.
     * Essentially, what we're doing is:
     * desugar(flow(attribute(todo)))
     * as per the comparable line in JavaCompiler.java:compile2.
     *
     * The difference of course being that we're doing this from
     * annotation processing land. This is okay, since
     * the very next thing javac is going to do after annotation
     * processing is call compile2. Provided we call this at the very end
     * of the very final annotation processing round and have javac exit
     * immediately from compile2, the world will probably not end.
     */
    static void shortCircuitCompiler() {
        Class<JavaCompiler> jCompilerClass = JavaCompiler.class;

        // Obtain reflective access to the methods called in compile2
        Method attributeMethod =
            getAccessibleMethod(jCompilerClass, "attribute", Queue.class);
        Method flowMethod =
            getAccessibleMethod(jCompilerClass, "flow", Queue.class);
        Method desugarMethod =
            getAccessibleMethod(jCompilerClass, "desugar", Queue.class);
        Method generateMethod =
            getAccessibleMethod(jCompilerClass, "generate", Queue.class);

        try {
            log.info("Attribution.");
            Object attributed = attributeMethod.invoke(javaCompiler, javaCompiler.todo);
            OptimisationPhaseManager.dispatchEvent(AFTER_ATTRIBUTION);

            log.info("Flow.");
            Object flowed = flowMethod.invoke(javaCompiler, attributed);
            OptimisationPhaseManager.dispatchEvent(AFTER_FLOW);

            log.info("Desugar.");
            Object desugared = desugarMethod.invoke(javaCompiler, flowed);

            // Capture the environments with attribution results for JOUST.
            JOUST.environmentsToProcess =
                (Queue<Pair<Env<AttrContext>, JCClassDecl>>) desugared;
            OptimisationPhaseManager.dispatchEvent(AFTER_DESUGAR);

            log.info("Generate.");
            generateMethod.invoke(javaCompiler, desugared);
            OptimisationPhaseManager.dispatchEvent(AFTER_GENERATE);

            log.info("Done.");
        } catch (IllegalAccessException e) {
            log.fatal("Unable to run compiler phases early!", e);
        } catch (InvocationTargetException e) {
            log.fatal("Unable to run compiler phases early!", e);
        }
    }

    @Override
    public void run() {
        // Get the post-annotation-processing context (javac sometimes
        // reassigns it during annotation processing.)
        Context finalContext = JOUST.environ.getContext();
        StaticCompilerUtils.uninit();
        StaticCompilerUtils.initWithContext(finalContext);

        List<JCCompilationUnit> compilationUnitList = List.nil();
        for (JCCompilationUnit unit : JOUST.conventionalTrees) {
            compilationUnitList = compilationUnitList.append(unit);
        }

        // Ensure all trees in this job are on the todo list.
        javaCompiler.enterTreesIfNeeded(compilationUnitList);

        shortCircuitCompiler();

        // Since we're taking control of the compilation phases after
        // annotation processing by ourselves, we want the compiler to not
        // attempt to run those phases itself when it returns. Setting this
        // causes the compiler the exist immediately after it finishes
        // annotation processing.
        javaCompiler.shouldStopPolicyIfNoError = CompileStates.CompileState.INIT;
    }

    @Override
    public String getName() {
        return NAME_CORE;
    }
}
TOP

Related Classes of joust.utils.compiler.JavacBrutaliser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.