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

org.teavm.dependency.FastDependencyAnalyzer Maven / Gradle / Ivy

/*
 *  Copyright 2018 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.dependency;

import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_ENTER_METHOD;
import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_ENTER_SYNC_METHOD;
import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_METHOD;
import static org.teavm.dependency.AbstractInstructionAnalyzer.MONITOR_EXIT_SYNC_METHOD;
import java.util.HashMap;
import java.util.Map;
import org.teavm.common.ServiceRepository;
import org.teavm.diagnostics.Diagnostics;
import org.teavm.model.ClassReader;
import org.teavm.model.ClassReaderSource;
import org.teavm.model.ElementModifier;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReader;
import org.teavm.model.MethodReference;
import org.teavm.model.ProgramReader;
import org.teavm.model.ReferenceCache;
import org.teavm.model.ValueType;

public class FastDependencyAnalyzer extends DependencyAnalyzer {
    DependencyNode instancesNode;
    DependencyNode classesNode;
    private Map virtualCallConsumers = new HashMap<>();
    private Map subtypeNodes = new HashMap<>();

    public FastDependencyAnalyzer(ClassReaderSource classSource, ClassLoader classLoader,
            ServiceRepository services, Diagnostics diagnostics, ReferenceCache referenceCache,
            String[] platformTags) {
        super(classSource, classLoader, services, diagnostics, referenceCache, platformTags);

        instancesNode = new DependencyNode(this, null);
        classesNode = new DependencyNode(this, null);

        instancesNode.addConsumer(type -> {
            getSubtypeNode(type.getName()).propagate(type);
        });
    }

    @Override
    protected void processMethod(MethodDependency methodDep) {
        MethodReader method = methodDep.getMethod();
        ProgramReader program = method.getProgram();

        if (program != null) {
            var instructionAnalyzer = new FastInstructionAnalyzer(this);
            instructionAnalyzer.setCaller(method.getReference());
            for (var block : program.getBasicBlocks()) {
                block.readAllInstructions(instructionAnalyzer);

                for (var tryCatch : block.readTryCatchBlocks()) {
                    if (tryCatch.getExceptionType() != null) {
                        linkClass(tryCatch.getExceptionType());
                    }
                }
            }

            methodDep.variableNodes = new DependencyNode[program.variableCount()];
            for (int i = 0; i < methodDep.variableNodes.length; ++i) {
                methodDep.variableNodes[i] = instancesNode;
            }
        }

        if (method.hasModifier(ElementModifier.SYNCHRONIZED)) {
            processAsyncMethod();
        }
    }

    private void processAsyncMethod() {
        if (asyncSupported) {
            linkMethod(MONITOR_ENTER_METHOD).use();
        }

        linkMethod(MONITOR_ENTER_SYNC_METHOD).use();

        if (asyncSupported) {
            linkMethod(MONITOR_EXIT_METHOD).use();
        }

        linkMethod(MONITOR_EXIT_SYNC_METHOD).use();
    }

    @Override
    DependencyNode createParameterNode(MethodReference method, ValueType type, int index) {
        return instancesNode;
    }

    @Override
    DependencyNode createResultNode(MethodReference method) {
        return instancesNode;
    }

    @Override
    DependencyNode createThrownNode(MethodReference method) {
        return instancesNode;
    }

    @Override
    DependencyNode createFieldNode(FieldReference field, ValueType type) {
        return instancesNode;
    }

    @Override
    DependencyNode createArrayItemNode(DependencyNode parent) {
        return instancesNode;
    }

    @Override
    DependencyNode createClassValueNode(int degree, DependencyNode parent) {
        return classesNode;
    }

    private DependencyNode getSubtypeNode(String type) {
        if (type.equals("java.lang.Object")) {
            return instancesNode;
        }
        return subtypeNodes.computeIfAbsent(type, key -> {
            DependencyNode node = createNode();

            defer(() -> {
                int degree = 0;
                while (degree < key.length() && key.charAt(degree) == '[') {
                    degree++;
                }

                if (degree > 0) {
                    ValueType fullType = ValueType.parse(key);
                    if (fullType instanceof ValueType.Object) {
                        String prefix = key.substring(0, degree) + "L";
                        String className = ((ValueType.Object) fullType).getClassName();
                        ClassReader cls = getClassSource().get(className);
                        if (cls != null) {
                            if (cls.getParent() != null) {
                                node.connect(getSubtypeNode(prefix + cls.getParent().replace('.', '/') + ";"));
                            } else {
                                node.connect(getSubtypeNode("java.lang.Object"));
                            }
                            for (String itf : cls.getInterfaces()) {
                                node.connect(getSubtypeNode(prefix + itf.replace('.', '/') + ";"));
                            }
                        }
                    } else {
                        node.connect(getSubtypeNode("java.lang.Object"));
                    }
                } else {
                    ClassReader cls = getClassSource().get(key);
                    if (cls != null) {
                        if (cls.getParent() != null) {
                            node.connect(getSubtypeNode(cls.getParent()));
                        }
                        for (String itf : cls.getInterfaces()) {
                            node.connect(getSubtypeNode(itf));
                        }
                    }
                }
            });

            return node;
        });
    }

    FastVirtualCallConsumer getVirtualCallConsumer(MethodReference method) {
        return virtualCallConsumers.computeIfAbsent(method, key -> {
            FastVirtualCallConsumer consumer = new FastVirtualCallConsumer(instancesNode, key, this);
            defer(() -> {
                getSubtypeNode(method.getClassName()).addConsumer(consumer);
            });
            return consumer;
        });
    }

    @Override
    boolean domainOptimizationEnabled() {
        return false;
    }

    @Override
    public void cleanup(ClassSourcePacker classSourcePacker) {
        virtualCallConsumers.clear();
        subtypeNodes.clear();
        super.cleanup(classSourcePacker);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy