All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teavm.ast.optimization.Optimizer Maven / Gradle / Ivy

There is a newer version: 0.2.8
Show newest version
/*
 *  Copyright 2016 Alexey Andreev.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.teavm.ast.optimization;

import java.util.BitSet;
import org.teavm.ast.AsyncMethodNode;
import org.teavm.ast.AsyncMethodPart;
import org.teavm.ast.RegularMethodNode;
import org.teavm.common.Graph;
import org.teavm.model.BasicBlock;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReference;
import org.teavm.model.Program;
import org.teavm.model.Variable;
import org.teavm.model.util.AsyncProgramSplitter;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.NonSsaLivenessAnalyzer;
import org.teavm.model.util.ProgramUtils;
import org.teavm.model.util.UsageExtractor;

public class Optimizer {
    public void optimize(RegularMethodNode method, Program program, boolean friendlyToDebugger) {
        ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
        stats.analyze(program);
        applyParametersToWriteStats(stats, method.getReference());

        boolean[] preservedVars = new boolean[stats.writes.length];
        BreakEliminator breakEliminator = new BreakEliminator();
        breakEliminator.eliminate(method.getBody());
        if (friendlyToDebugger) {
            for (int i = 0; i < method.getVariables().size(); ++i) {
                if (method.getVariables().get(i).getName() != null) {
                    preservedVars[i] = true;
                }
            }
        }
        OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
                stats.constants, friendlyToDebugger);
        method.getBody().acceptVisitor(optimizer);
        method.setBody(optimizer.resultStmt);
        int paramCount = method.getReference().parameterCount();

        UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
        method.getBody().acceptVisitor(unusedEliminator);
        method.getVariables().clear();
        method.getVariables().addAll(unusedEliminator.getReorderedVariables());

        method.getBody().acceptVisitor(new RedundantLabelEliminator());
        method.getBody().acceptVisitor(new RedundantReturnElimination());

        for (int i = 0; i < method.getVariables().size(); ++i) {
            method.getVariables().get(i).setIndex(i);
        }
    }

    public void optimize(AsyncMethodNode method, AsyncProgramSplitter splitter, boolean friendlyToDebugger) {
        NonSsaLivenessAnalyzer liveness = new NonSsaLivenessAnalyzer();
        liveness.analyze(splitter.getOriginalProgram(), method.getReference().getDescriptor());

        Graph cfg = ProgramUtils.buildControlFlowGraph(splitter.getOriginalProgram());
        boolean[] preservedVars = new boolean[method.getVariables().size()];
        for (int i = 0; i < splitter.size(); ++i) {
            findEscapingLiveVars(liveness, cfg, splitter, i, preservedVars);
        }

        for (int i = 0; i < splitter.size(); ++i) {
            ReadWriteStatsBuilder stats = new ReadWriteStatsBuilder(method.getVariables().size());
            stats.analyze(splitter.getProgram(i));
            applyParametersToWriteStats(stats, method.getReference());

            AsyncMethodPart part = method.getBody().get(i);
            BreakEliminator breakEliminator = new BreakEliminator();
            breakEliminator.eliminate(part.getStatement());
            OptimizingVisitor optimizer = new OptimizingVisitor(preservedVars, stats.writes, stats.reads,
                    stats.constants, friendlyToDebugger);
            part.getStatement().acceptVisitor(optimizer);
            part.setStatement(optimizer.resultStmt);
        }

        int paramCount = method.getReference().parameterCount();
        UnusedVariableEliminator unusedEliminator = new UnusedVariableEliminator(paramCount, method.getVariables());
        for (AsyncMethodPart part : method.getBody()) {
            part.getStatement().acceptVisitor(unusedEliminator);
        }
        method.getVariables().clear();
        method.getVariables().addAll(unusedEliminator.getReorderedVariables());

        RedundantLabelEliminator labelEliminator = new RedundantLabelEliminator();
        for (AsyncMethodPart part : method.getBody()) {
            part.getStatement().acceptVisitor(labelEliminator);
        }

        for (int i = 0; i < method.getVariables().size(); ++i) {
            method.getVariables().get(i).setIndex(i);
        }
    }

    private void applyParametersToWriteStats(ReadWriteStatsBuilder stats, MethodReference method) {
        for (int i = 0; i <= method.parameterCount(); ++i) {
            stats.writes[i]++;
        }
    }

    private void findEscapingLiveVars(NonSsaLivenessAnalyzer liveness, Graph cfg, AsyncProgramSplitter splitter,
            int partIndex, boolean[] output) {
        Program originalProgram = splitter.getOriginalProgram();
        Program program = splitter.getProgram(partIndex);
        int[] successors = splitter.getBlockSuccessors(partIndex);
        Instruction[] splitPoints = splitter.getSplitPoints(partIndex);
        int[] originalBlocks = splitter.getOriginalBlocks(partIndex);

        for (int i = 0; i < program.basicBlockCount(); ++i) {
            if (successors[i] < 0 || originalBlocks[i] < 0) {
                continue;
            }

            // Determine live-out vars
            BitSet liveVars = new BitSet();
            for (int succ : cfg.outgoingEdges(originalBlocks[i])) {
                liveVars.or(liveness.liveIn(succ));
            }

            // Remove from live set all variables that are defined in these blocks
            DefinitionExtractor defExtractor = new DefinitionExtractor();
            UsageExtractor useExtractor = new UsageExtractor();
            BasicBlock block = originalProgram.basicBlockAt(originalBlocks[i]);
            Instruction splitPoint = splitPoints[i].getPrevious();
            for (Instruction insn = block.getLastInstruction(); insn != splitPoint; insn = insn.getPrevious()) {
                insn.acceptVisitor(defExtractor);
                insn.acceptVisitor(useExtractor);
                for (Variable var : defExtractor.getDefinedVariables()) {
                    liveVars.clear(var.getIndex());
                }
                for (Variable var : useExtractor.getUsedVariables()) {
                    liveVars.set(var.getIndex());
                }
            }

            // Add live variables to output
            for (int j = liveVars.nextSetBit(0); j >= 0; j = liveVars.nextSetBit(j + 1)) {
                output[j] = true;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy