/*
* This file is part of JOP, the Java Optimized Processor
* see <http://www.jopdesign.com/>
*
* Copyright (C) 2011, Stefan Hepp (stefan@stefant.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.jopdesign.dfa.framework;
import com.jopdesign.common.AppInfo;
import com.jopdesign.common.MethodInfo;
import com.jopdesign.common.code.DefaultCallgraphBuilder;
import com.jopdesign.common.code.ExecutionContext;
import com.jopdesign.common.code.InvokeSite;
import com.jopdesign.common.type.MemberID;
import com.jopdesign.dfa.DFATool;
import org.apache.log4j.Logger;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
/**
* @author Stefan Hepp (stefan@stefant.org)
*/
public class DFACallgraphBuilder extends DefaultCallgraphBuilder {
private final AppInfo appInfo;
private final DFATool dfaTool;
private static final Logger logger = Logger.getLogger(DFATool.LOG_DFA_FRAMEWORK+".DFACallgraphBuilder");
public DFACallgraphBuilder(DFATool dfaTool, int callgraphLength) {
super(callgraphLength);
this.dfaTool = dfaTool;
this.appInfo = AppInfo.getSingleton();
}
@Override
protected Set<MethodInfo> getInvokedMethods(ExecutionContext context, InvokeSite invokeSite) {
// Receivers of instructions which are JVM calls are not the JVM class implementing the call, so
// to avoid problems we only use the DFA for virtual calls, all other can be uniquely resolved anyway.
if (!invokeSite.isVirtual()) {
return Collections.singleton(invokeSite.getInvokeeRef().getMethodInfo());
}
Set<String> receivers = dfaTool.getReceivers(invokeSite.getInstructionHandle(), context.getCallString());
if (receivers == null) {
// This can happen e.g. because we have all Runnable.run() methods as roots, regardless if they are used
logger.debug("No receivers for " + invokeSite.getInvokeeRef() + " at " + invokeSite + " in call context " +
context.getCallString().toStringVerbose(false));
return appInfo.findImplementations(invokeSite, context.getCallString());
}
if (receivers.size() == 0) {
// This can happen if a method is analyzed for some contexts but not for this context
logger.debug("No receivers for " + invokeSite.getInvokeeRef() + " at " + invokeSite + " in call context " +
context.getCallString().toStringVerbose(false));
return appInfo.findImplementations(invokeSite, context.getCallString());
}
Set<MethodInfo> methods = new LinkedHashSet<MethodInfo>(receivers.size());
for (String rcv: receivers) {
MemberID mId = MemberID.parse(rcv);
methods.add(appInfo.getMethodRef(mId).getMethodInfo());
}
return methods;
}
}