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

org.teavm.metaprogramming.impl.optimization.ArrayElimination Maven / Gradle / Ivy

/*
 *  Copyright 2017 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.metaprogramming.impl.optimization;

import org.teavm.common.DisjointSet;
import org.teavm.model.BasicBlock;
import org.teavm.model.Incoming;
import org.teavm.model.Instruction;
import org.teavm.model.MethodReference;
import org.teavm.model.Phi;
import org.teavm.model.Program;
import org.teavm.model.ValueType;
import org.teavm.model.Variable;
import org.teavm.model.instructions.AssignInstruction;
import org.teavm.model.instructions.ConstructArrayInstruction;
import org.teavm.model.instructions.DoubleConstantInstruction;
import org.teavm.model.instructions.FloatConstantInstruction;
import org.teavm.model.instructions.GetElementInstruction;
import org.teavm.model.instructions.IntegerConstantInstruction;
import org.teavm.model.instructions.LongConstantInstruction;
import org.teavm.model.instructions.NullConstantInstruction;
import org.teavm.model.instructions.PutElementInstruction;
import org.teavm.model.instructions.UnwrapArrayInstruction;
import org.teavm.model.util.DefinitionExtractor;
import org.teavm.model.util.PhiUpdater;
import org.teavm.model.util.UsageExtractor;

public class ArrayElimination {
    private Program program;
    private int[] varClasses;
    private int[] constantValues;
    private boolean[] constants;
    private boolean[] unsafeArrays;
    private int[] arraySizes;
    private boolean hasModifications;

    public void apply(Program program, MethodReference methodReference) {
        this.program = program;
        findVarClasses();
        findConstantVariables();
        findSafeArrays();
        removeSafeArrays();
        if (hasModifications) {
            Variable[] parameters = new Variable[methodReference.parameterCount() + 1];
            for (int i = 0; i < parameters.length; ++i) {
                parameters[i] = program.variableAt(i);
            }
            new PhiUpdater().updatePhis(program, parameters);
        }
    }

    private void findVarClasses() {
        DisjointSet varClasses = new DisjointSet();
        for (int i = 0; i < program.variableCount(); ++i) {
            varClasses.create();
        }
        for (BasicBlock block : program.getBasicBlocks()) {
            for (Instruction instruction : block) {
                int receiver;
                int assignee;
                if (instruction instanceof AssignInstruction) {
                    AssignInstruction assign = (AssignInstruction) instruction;
                    receiver = assign.getReceiver().getIndex();
                    assignee = assign.getAssignee().getIndex();
                } else if (instruction instanceof UnwrapArrayInstruction) {
                    UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) instruction;
                    receiver = unwrap.getReceiver().getIndex();
                    assignee = unwrap.getArray().getIndex();
                } else {
                    continue;
                }
                varClasses.union(receiver, assignee);
            }
        }
        this.varClasses = varClasses.pack(program.variableCount());
    }

    private void findConstantVariables() {
        int[] constantValuesByClasses = new int[program.variableCount()];
        boolean[] constantsByClasses = new boolean[program.variableCount()];
        for (BasicBlock block : program.getBasicBlocks()) {
            for (Instruction instruction : block) {
                if (instruction instanceof IntegerConstantInstruction) {
                    IntegerConstantInstruction constant = (IntegerConstantInstruction) instruction;
                    int receiver = varClasses[constant.getReceiver().getIndex()];
                    constantsByClasses[receiver] = true;
                    constantValuesByClasses[receiver] = constant.getConstant();
                }
            }
        }

        constantValues = new int[program.variableCount()];
        constants = new boolean[program.variableCount()];
        for (int i = 0; i < program.variableCount(); ++i) {
            constantValues[i] = constantValuesByClasses[varClasses[i]];
            constants[i] = constantsByClasses[varClasses[i]];
        }
    }

    private void findSafeArrays() {
        boolean[] unsafeArraysByClasses = new boolean[program.variableCount()];
        int[] arraySizesByClasses = new int[program.variableCount()];

        DefinitionExtractor defExtractor = new DefinitionExtractor();
        UsageExtractor useExtractor = new UsageExtractor();
        for (BasicBlock block : program.getBasicBlocks()) {
            for (Phi phi : block.getPhis()) {
                unsafeArraysByClasses[varClasses[phi.getReceiver().getIndex()]] = true;
                for (Incoming incoming : phi.getIncomings()) {
                    unsafeArraysByClasses[varClasses[incoming.getValue().getIndex()]] = true;
                }
            }
            for (Instruction instruction : block) {
                if (instruction instanceof GetElementInstruction) {
                    GetElementInstruction getElement = (GetElementInstruction) instruction;
                    unsafeArraysByClasses[varClasses[getElement.getReceiver().getIndex()]] = true;
                } else if (instruction instanceof PutElementInstruction) {
                    PutElementInstruction putElement = (PutElementInstruction) instruction;
                    unsafeArraysByClasses[varClasses[putElement.getValue().getIndex()]] = true;
                    if (!constants[putElement.getIndex().getIndex()]) {
                        unsafeArraysByClasses[varClasses[putElement.getIndex().getIndex()]] = true;
                    }
                } else if (instruction instanceof ConstructArrayInstruction) {
                    ConstructArrayInstruction construct = (ConstructArrayInstruction) instruction;
                    int receiver = varClasses[construct.getReceiver().getIndex()];
                    if (!constants[construct.getSize().getIndex()]) {
                        unsafeArraysByClasses[receiver] = true;
                    } else {
                        arraySizesByClasses[receiver] = constantValues[construct.getSize().getIndex()];
                    }
                } else {
                    if (instruction instanceof AssignInstruction || instruction instanceof UnwrapArrayInstruction) {
                        continue;
                    }
                    instruction.acceptVisitor(defExtractor);
                    instruction.acceptVisitor(useExtractor);
                    for (Variable var : defExtractor.getDefinedVariables()) {
                        unsafeArraysByClasses[varClasses[var.getIndex()]] = true;
                    }
                    for (Variable var : useExtractor.getUsedVariables()) {
                        unsafeArraysByClasses[varClasses[var.getIndex()]] = true;
                    }
                }
            }
        }

        unsafeArrays = new boolean[program.variableCount()];
        arraySizes = new int[program.variableCount()];
        for (int i = 0; i < program.variableCount(); ++i) {
            unsafeArrays[i] = unsafeArraysByClasses[varClasses[i]];
            arraySizes[i] = arraySizesByClasses[varClasses[i]];
        }
    }

    private void removeSafeArrays() {
        int[][] arrayItemsAsVariablesByClass = new int[program.variableCount()][];
        for (int i = 0; i < arrayItemsAsVariablesByClass.length; ++i) {
            int varClass = varClasses[i];
            if (arrayItemsAsVariablesByClass[varClass] != null || unsafeArrays[i]) {
                continue;
            }
            int size = arraySizes[i];
            arrayItemsAsVariablesByClass[varClass] = new int[size];
            for (int j = 0; j < size; ++j) {
                arrayItemsAsVariablesByClass[varClass][j] = program.createVariable().getIndex();
            }
        }

        int[][] arrayItemsAsVariables = new int[arrayItemsAsVariablesByClass.length][];
        for (int i = 0; i < arrayItemsAsVariables.length; ++i) {
            arrayItemsAsVariables[i] = arrayItemsAsVariablesByClass[varClasses[i]];
        }

        for (BasicBlock block : program.getBasicBlocks()) {
            for (Instruction instruction : block) {
                if (instruction instanceof GetElementInstruction) {
                    GetElementInstruction getElement = (GetElementInstruction) instruction;
                    int array = getElement.getArray().getIndex();
                    if (!unsafeArrays[array]) {
                        int index = constantValues[getElement.getIndex().getIndex()];
                        Variable var = program.variableAt(arrayItemsAsVariables[array][index]);
                        AssignInstruction assign = new AssignInstruction();
                        assign.setReceiver(getElement.getReceiver());
                        assign.setAssignee(var);
                        assign.setLocation(getElement.getLocation());
                        getElement.replace(assign);
                        hasModifications = true;
                    }
                } else if (instruction instanceof PutElementInstruction) {
                    PutElementInstruction putElement = (PutElementInstruction) instruction;
                    int array = putElement.getArray().getIndex();
                    if (!unsafeArrays[array]) {
                        int index = constantValues[putElement.getIndex().getIndex()];
                        Variable var = program.variableAt(arrayItemsAsVariables[array][index]);
                        AssignInstruction assign = new AssignInstruction();
                        assign.setReceiver(var);
                        assign.setAssignee(putElement.getValue());
                        assign.setLocation(putElement.getLocation());
                        putElement.replace(assign);
                        hasModifications = true;
                    }
                } else if (instruction instanceof ConstructArrayInstruction) {
                    ConstructArrayInstruction construct = (ConstructArrayInstruction) instruction;
                    if (!unsafeArrays[construct.getReceiver().getIndex()]) {
                        int[] vars = arrayItemsAsVariables[construct.getReceiver().getIndex()];
                        for (int i = 0; i < vars.length; ++i) {
                            Instruction constantInsn = createDefaultConstantInstruction(construct.getItemType(),
                                    program.variableAt(vars[i]));
                            constantInsn.setLocation(construct.getLocation());
                            construct.insertPrevious(constantInsn);
                        }
                        construct.delete();
                        hasModifications = true;
                    }
                } else if (instruction instanceof UnwrapArrayInstruction) {
                    UnwrapArrayInstruction unwrap = (UnwrapArrayInstruction) instruction;
                    if (!unsafeArrays[unwrap.getArray().getIndex()]) {
                        unwrap.delete();
                        hasModifications = true;
                    }
                } else if (instruction instanceof AssignInstruction) {
                    AssignInstruction assign = (AssignInstruction) instruction;
                    if (!unsafeArrays[assign.getAssignee().getIndex()]) {
                        assign.delete();
                        hasModifications = true;
                    }
                }
            }
        }
    }

    private Instruction createDefaultConstantInstruction(ValueType valueType, Variable receiver) {
        if (valueType instanceof ValueType.Primitive) {
            switch (((ValueType.Primitive) valueType).getKind()) {
                case BOOLEAN:
                case CHARACTER:
                case BYTE:
                case SHORT:
                case INTEGER: {
                    IntegerConstantInstruction result = new IntegerConstantInstruction();
                    result.setReceiver(receiver);
                    return result;
                }
                case LONG: {
                    LongConstantInstruction result = new LongConstantInstruction();
                    result.setReceiver(receiver);
                    return result;
                }
                case FLOAT: {
                    FloatConstantInstruction result = new FloatConstantInstruction();
                    result.setReceiver(receiver);
                    return result;
                }
                case DOUBLE: {
                    DoubleConstantInstruction result = new DoubleConstantInstruction();
                    result.setReceiver(receiver);
                    return result;
                }
            }
        }
        NullConstantInstruction result = new NullConstantInstruction();
        result.setReceiver(receiver);
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy