Package joust.optimisers.unbox

Source Code of joust.optimisers.unbox.UnboxMapper

package joust.optimisers.unbox;

import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.Name;
import joust.utils.tree.functiontemplates.FunctionTemplate;
import joust.tree.annotatedtree.AJCTree;
import joust.utils.logging.LogUtils;
import joust.utils.tree.NameFactory;
import lombok.experimental.ExtensionMethod;
import lombok.extern.java.Log;

import java.util.logging.Logger;

import static com.sun.tools.javac.code.Symbol.*;
import static com.sun.tools.javac.code.Type.*;
import static joust.tree.annotatedtree.AJCTree.*;
import static joust.utils.compiler.StaticCompilerUtils.*;
import static joust.optimisers.unbox.UnboxingFunctionTemplates.functionTemplates;

@Log
@ExtensionMethod({Logger.class, LogUtils.LogExtensions.class})
public class UnboxMapper {
    private VarSymbol newSym;
    private final VarSymbol oldSym;

    // The parent symbol of the symbol being replaced.
    private final Symbol enclosingMethod;

    private Type unboxedType;

    public UnboxMapper(VarSymbol sym) {
        oldSym = sym;
        enclosingMethod = sym.owner;

        unboxedType = types.unboxedType(oldSym.type);
        if (unboxedType == noType) {
            log.fatal("Unable to find type for {}!", oldSym);
        }

        // Create a new variable definition for the new symbol.
        Name tempName = NameFactory.getName();
        newSym = new VarSymbol(0, tempName, unboxedType, enclosingMethod);
    }

    public AJCTree replacementTree(AJCTree tree) {
        if (tree instanceof AJCIdent) {
            return replacementIdent((AJCIdent) tree);
        } else if (tree instanceof AJCCall) {
            return replacementCall((AJCCall) tree);
        } else if (tree instanceof AJCAssign) {
            return replacementAssign((AJCAssign) tree);
        } else if (tree instanceof AJCVariableDecl) {
            return replacementVarDef((AJCVariableDecl) tree);
        }

        log.fatal("Unable to find replacement tree for {}:{}", tree, tree.getClass().getCanonicalName());
        return null;
    }

    private AJCTree replacementAssign(AJCAssign tree) {
        tree.setType(newSym.type);
        return tree;
    }

    public AJCVariableDecl replacementVarDef(AJCVariableDecl tree) {
        // Create an appropriately modified init tree.
        // If the init tree is a call to one of the valueOf methods, it can be replaced with the argument.
        // If it's any other expression, you need (oldExpr).intValue()  (Or such).
        AJCExpressionTree init = tree.getInit();

        // Declaration thereof. Translation of the init will occur later.
        AJCVariableDecl ret = treeMaker.VarDef(newSym, getConvertedInit(init, unboxedType));
        ret.setType(unboxedType);

        return ret;
    }

    private AJCExpressionTree getConvertedInit(AJCExpressionTree init, Type unboxedType) {
        if (newSym == null) {
            throw new IllegalStateException("Attempt to convert usages of a boxed symbol before converting the declaration.");
        }

        if (init.isEmptyExpression()) {
            return init;
        }

        log.debug("Tree: {}", init);
        log.debug("Current type: {}", init.getNodeType());
        log.debug("Target type : {}", unboxedType);
        if (types.isSameType(init.getNodeType(), unboxedType)) {
            return init;
        }

        if (init instanceof AJCCall) {
            AJCCall cast = (AJCCall) init;

            MethodSymbol calledMethod = cast.getTargetSymbol();

            // Check for valueOf.
            if ("valueOf".equals(calledMethod.name.toString())) {
                // Check it's the one that takes a single argument of type unboxedType.
                if (calledMethod.params.size() != 1) {
                    return getDefaultConvertedInit(init, unboxedType);
                }

                if (types.isSameType(calledMethod.params.head.type, unboxedType)) {
                    return cast.args.head;
                }
            }

            // TODO: Convert valueOf(String) to Integer.valueOf(String) and so on, instead of valueOf(String).intValue().
        }

        return getDefaultConvertedInit(init, unboxedType);
    }

    /**
     * Return (init).intValue() (Or such, for the appropriate required type.)
     */
    private AJCExpressionTree getDefaultConvertedInit(AJCExpressionTree init, Type unboxedType) {
        log.info("unboxedType: {}", unboxedType);
        MethodSymbol xValue = UnboxingFunctionTemplates.unboxedValueFunctions.get(unboxedType);
        log.debug("xValue: {}", xValue);
        AJCIdent<MethodSymbol> methodIdent = treeMaker.Ident(xValue);
        log.debug("ident: {}", methodIdent);
        AJCCall ret = treeMaker.Call(treeMaker.Select(init, xValue), List.<AJCExpressionTree>nil());
        ret.setType(unboxedType);
        log.debug("ret: {}", ret);
        return ret;
    }

    public AJCIdent replacementIdent(AJCIdent that) {
        // If it's a reference to the old symbol, replace it.
        if (that.getTargetSymbol() == oldSym) {
            log.debug("New sym type: {}", newSym.type);
            return treeMaker.Ident(newSym);
        }

        return that;
    }

    protected AJCExpressionTree replacementCall(AJCCall that) {
        if (newSym == null) {
            throw new IllegalStateException("Attempt to convert usages of a boxed symbol before converting the declaration.");
        }

        MethodSymbol calledMethod = that.getTargetSymbol();
        FunctionTemplate template = functionTemplates.get(calledMethod);

        if (template == null) {
            return null;
        }

        if (template.isStatic) {
            AJCExpressionTree replacement = template.instantiate(
                    that.args.toArray(
                            new AJCExpressionTree[that.args.size()]
                    )
            );

            log.info("Replacing {} with {}", that, replacement);
            return replacement;
        } else {
            // For nonstatics, the first argument to the template is the callee.
            List<AJCExpressionTree> newArgs = that.args;
            newArgs = newArgs.prepend(treeMaker.Ident(newSym));

            AJCExpressionTree replacement = template.instantiate(
                    newArgs.toArray(
                            new AJCExpressionTree[newArgs.size()]
                    )
            );

            log.info("Replacing {} with {}", that, replacement);
            return replacement;
        }
    }
}
TOP

Related Classes of joust.optimisers.unbox.UnboxMapper

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.