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

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

There is a newer version: 0.10.2
Show newest version
/*
 *  Copyright 2019 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 java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.teavm.callgraph.CallGraphNode;
import org.teavm.model.FieldReference;
import org.teavm.model.MethodReference;
import org.teavm.model.TextLocation;

class DefaultCallGraphNode implements CallGraphNode {
    private DefaultCallGraph graph;
    private MethodReference method;
    private Map callSiteMap;
    private List callSites;
    private DefaultCallSite singleCallSite;
    private Collection safeCallSites;
    private DefaultCallSite singleCaller;
    private List callerCallSites;
    private List safeCallersCallSites;
    private Set fieldAccessSites = new LinkedHashSet<>();
    private Set safeFieldAccessSites;
    private DefaultCallSite virtualCallSite;

    DefaultCallGraphNode(DefaultCallGraph graph, MethodReference method) {
        this.graph = graph;
        this.method = method;
    }

    @Override
    public DefaultCallGraph getGraph() {
        return graph;
    }

    @Override
    public MethodReference getMethod() {
        return method;
    }

    @Override
    public Collection getCallSites() {
        if (callSites == null) {
            if (singleCallSite != null) {
                return Collections.singletonList(singleCallSite);
            }
            return Collections.emptyList();
        }
        if (safeCallSites == null) {
            safeCallSites = Collections.unmodifiableCollection(callSites);
        }
        return safeCallSites;
    }

    @Override
    public Collection getCallerCallSites() {
        if (callerCallSites == null) {
            if (singleCaller != null) {
                return Collections.singletonList(singleCaller);
            }
            return Collections.emptyList();
        }
        if (safeCallersCallSites == null) {
            safeCallersCallSites = Collections.unmodifiableList(callerCallSites);
        }
        return safeCallersCallSites;
    }

    DefaultCallSite addCallSite(MethodReference method) {
        DefaultCallGraphNode callee = graph.getNode(method);

        if (callSites == null) {
            if (singleCallSite == null) {
                singleCallSite = new DefaultCallSite(callee, this);
                callee.addCaller(singleCallSite);
                return singleCallSite;
            }
            if (singleCallSite.singleCalledMethod.getMethod().equals(method)) {
                return singleCallSite;
            }
            callSiteMap = new LinkedHashMap<>();
            callSites = new ArrayList<>();
            callSiteMap.put(singleCallSite.singleCalledMethod.getMethod(), singleCallSite);
            callSites.add(singleCallSite);
            singleCallSite = null;
        }

        DefaultCallSite callSite = callSiteMap.get(method);
        if (callSite == null) {
            callSite = new DefaultCallSite(callee, this);
            callee.addCaller(callSite);
            callSiteMap.put(method, callSite);
            callSites.add(callSite);
        }

        return callSite;
    }

    DefaultCallSite getVirtualCallSite() {
        if (virtualCallSite == null) {
            virtualCallSite = new DefaultCallSite(method, new LinkedHashSet<>());
        }
        return virtualCallSite;
    }

    void addVirtualCallSite(DefaultCallSite callSite) {
        if (callSite.callers == null) {
            throw new IllegalArgumentException("Call site is not virtual");
        }
        if (callSite.callers.add(this)) {
            if (callSites == null) {
                callSites = new ArrayList<>();
                callSiteMap = new LinkedHashMap<>();
                if (singleCallSite != null) {
                    callSites.add(singleCallSite);
                    callSiteMap.put(singleCallSite.method, singleCallSite);
                    singleCallSite = null;
                }
            }
            callSites.add(callSite);
        }
    }

    void addCaller(DefaultCallSite caller) {
        if (callerCallSites == null) {
            if (singleCaller == null) {
                singleCaller = caller;
                return;
            }
            callerCallSites = new ArrayList<>();
            callerCallSites.add(singleCaller);
            singleCaller = null;
        }
        callerCallSites.add(caller);
    }

    @Override
    public Collection getFieldAccessSites() {
        if (safeFieldAccessSites == null) {
            safeFieldAccessSites = Collections.unmodifiableSet(fieldAccessSites);
        }
        return safeFieldAccessSites;
    }

    boolean addFieldAccess(FieldReference field, TextLocation location) {
        DefaultFieldAccessSite site = new DefaultFieldAccessSite(location, this, field);
        if (fieldAccessSites.add(site)) {
            graph.addFieldAccess(site);
            return true;
        } else {
            return false;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy