/*******************************************************************************
* Copyright (c) 2012 Andreas Engelbredt Dalsgaard <andreas.dalsgaard@gmail.com>.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*
* Contributors:
* Andreas Engelbredt Dalsgaard <andreas.dalsgaard@gmail.com>
******************************************************************************/
package analyser;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.util.intset.EmptyIntSet;
import com.ibm.wala.util.intset.IntSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.UUID;
public class ScjContextSelector implements ContextSelector {
private IClass missionIClass = null;
private IClass AEHIClass = null;
int counter = 0;
private ClassHierarchy cha;
private IClass ManagedMemoryIClass;
private IClass MemoryAreaIClass;
public HashMap<IClass, ScjScopeStack> classScopeMap = new HashMap<IClass, ScjScopeStack>();
public HashSet<ScjScopeStack> scopeStacks = new HashSet<ScjScopeStack>();
public HashMap<IMethod, ScjScopeStack> methodScopeMap = new HashMap<IMethod, ScjScopeStack>();
public int count;
private IClass immortalIClass;
private IClass safeletIClass;
private IClass PEHIClass;
private IClass APEHIClass;
private IClass CyclicExecutiveIClass;
private ScjContext immortal;
private boolean CyclicExecutiveUsed;
private IClass MissionSequencer;
public ScjContextSelector(ClassHierarchy cha)
{
this.cha = cha;
this.missionIClass = util.getIClass("Ljavax/safetycritical/Mission", cha);
if (this.missionIClass == null)
throw new IllegalArgumentException("No mission class in ClassHierarchy");
this.AEHIClass = util.getIClass("Ljavax/realtime/AbstractAsyncEventHandler", cha);
this.ManagedMemoryIClass = util.getIClass("Ljavax/safetycritical/ManagedMemory", cha);
this.MemoryAreaIClass = util.getIClass("Ljavax/realtime/MemoryArea", cha);
this.immortalIClass = util.getIClass("Ljavax/realtime/ImmortalMemory", cha);
this.safeletIClass = util.getIClass("Ljavax/safetycritical/Safelet", cha);
this.PEHIClass = util.getIClass("Ljavax/safetycritical/PeriodicEventHandler", cha);
this.APEHIClass = util.getIClass("Ljavax/safetycritical/AperiodicEventHandler", cha);
this.CyclicExecutiveIClass = util.getIClass("Ljavax/safetycritical/CyclicExecutive", cha);
this.MissionSequencer = util.getIClass("Ljavax/safetycritical/MissionSequencer", cha);
this.immortal = new ScjContext(null, "Ljavax/realtime/ImmortalMemory", ScjScopeType.IMMORTAL);
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site,
IMethod callee, InstanceKey[] actualParameters)
{
ScjContext calleeContext;
// Handles the first nodes that is called from the synthetic fakeRoot
if (!(caller.getContext() instanceof ScjContext))
{
return immortal;
}
calleeContext = (ScjContext) caller.getContext();
if (isSubclassOf(callee, this.AEHIClass) &&
isFuncName(callee, "handleAsyncEvent"))
{
calleeContext = new ScjContext(calleeContext, callee.getDeclaringClass().getName().toString(), ScjScopeType.PM);
} else if (this.isImplemented(callee, this.safeletIClass) && isFuncName(callee, "initializeApplication")) {
calleeContext = this.immortal;
}else if (isSubclassOf(callee,this.ManagedMemoryIClass))
{
if (isFuncName(callee, "enterPrivateMemory")) {
calleeContext = new ScjContext(calleeContext, getUniquePMName(), ScjScopeType.PM);
} else if (isFuncName(callee, "executeInOuterArea")) {
System.out.println("executeInOuterArea");
calleeContext = new ScjContext(calleeContext.getOuterStack());
} else if (isFuncName(callee, "executeInAreaOf")) {
util.error("Not supported by the analysis");
} else if (isFuncName(callee, "getCurrentManagedMemory")) {
util.error("Not supported by new SCJ revisions");
}
} else if (isFuncName(callee, "startMission") && callee.getDeclaringClass().getName().toString().equals("Ljavax/safetycritical/JopSystem"))
{
calleeContext = new ScjContext(calleeContext,
caller.getMethod().getDeclaringClass().getName().toString(), ScjScopeType.MISSION);
} else if(isFuncName(callee, "getSequencer") && this.isImplemented(callee, this.safeletIClass))
{
calleeContext = this.immortal;
}
if( ScjMemoryScopeAnalysis.analyseWithoutJRE == true && isFuncName(callee, "initialize") && isSubclassOf(callee, this.missionIClass))
{
calleeContext = new ScjContext(calleeContext,
caller.getMethod().getDeclaringClass().getName().toString(), ScjScopeType.MISSION);
}
this.scopeStacks.add(calleeContext.scopeStack);
this.updateClassScopeMapping(callee,calleeContext.scopeStack);
this.updateMethodScope(callee, calleeContext.scopeStack);
return calleeContext;
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return EmptyIntSet.instance;
}
public boolean isSubclassOf(IMethod callee, IClass parent)
{
if (parent != null)
return this.cha.isSubclassOf(callee.getDeclaringClass(), parent);
return false;
}
public boolean isImplemented(IMethod callee, IClass parent)
{
if (parent != null)
return this.cha.implementsInterface(callee.getDeclaringClass(), parent);
return false;
}
public boolean isFuncName(IMethod callee, String str)
{
return callee.getName().toString().equals(str);
}
public String getUniquePMName()
{
return UUID.randomUUID().toString();
}
private void updateClassScopeMapping(IMethod callee, ScjScopeStack scopeStack)
{
if (isSubclassOf(callee, this.CyclicExecutiveIClass))
{
updateClassScope(callee.getDeclaringClass(),immortal.scopeStack);
this.CyclicExecutiveUsed = true;
} else if(isImplemented(callee, this.safeletIClass)) {
updateClassScope(callee.getDeclaringClass(),immortal.scopeStack);
} else if(isSubclassOf(callee, this.missionIClass)) { //Mission
updateClassScope(callee.getDeclaringClass(), scopeStack);
} else if(isSubclassOf(callee, this.PEHIClass) || isSubclassOf(callee, this.APEHIClass)) { //EventHandlers
ScjScopeStack ss = new ScjScopeStack();
ss.add(scopeStack.get(0));
ss.add(scopeStack.get(1));
updateClassScope(callee.getDeclaringClass(), ss);
}
}
private void updateClassScope(IClass type, ScjScopeStack ss1)
{
ScjScope scjScope = ss1.getLast();
if (this.classScopeMap.containsKey(type))
{
ScjScopeStack ss2 = this.classScopeMap.get(type);
ss2.add(scjScope);
this.classScopeMap.put(type, ss2);
} else {
ScjScopeStack scopestack = new ScjScopeStack();
scopestack.add(ss1.getLast());
this.classScopeMap.put(type, scopestack);
}
}
private void updateMethodScope(IMethod method, ScjScopeStack ss1)
{
ScjScope scjScope = ss1.getLast();
//Filter out constructors, cleanUp methods
if (method.getName().toString().equals("cleanUp") && isSubclassOf(method, this.missionIClass) ||
method.getName().toString().equals("<init>"))
return;
if (this.methodScopeMap.containsKey(method))
{
ScjScopeStack ss2 = this.methodScopeMap.get(method);
if (ss2.size() != 1 || ss2.getLast() == scjScope)
{
this.methodScopeMap.remove(method);
ss2.add(scjScope);
this.methodScopeMap.put(method, ss2);
}
} else {
ScjScopeStack scopestack = new ScjScopeStack();
scopestack.add(ss1.getLast());
this.methodScopeMap.put(method, scopestack);
}
}
}