WALA/com.ibm.wala.cast/source/java/com/ibm/wala/cast/ipa/callgraph/ScopeMappingInstanceKeys.java

162 lines
5.9 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2006 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*****************************************************************************/
package com.ibm.wala.cast.ipa.callgraph;
import java.util.Iterator;
import com.ibm.wala.cast.ipa.callgraph.LexicalScopingResolverContexts.Resolver;
import com.ibm.wala.cast.loader.AstMethod.LexicalParent;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.NewSiteReference;
import com.ibm.wala.classLoader.ProgramCounter;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.CompoundIterator;
import com.ibm.wala.util.collections.EmptyIterator;
import com.ibm.wala.util.collections.NonNullSingletonIterator;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.OrdinalSet;
/**
* An {@link InstanceKeyFactory} that returns {@link ScopeMappingInstanceKey}s
* as necessary to handle interprocedural lexical scoping
*/
abstract public class ScopeMappingInstanceKeys implements InstanceKeyFactory {
/**
* does base require a scope mapping key? Typically, true if base is allocated
* in a nested lexical scope
*/
protected abstract boolean needsScopeMappingKey(InstanceKey base);
private final PropagationCallGraphBuilder builder;
private final InstanceKeyFactory basic;
/**
* An {@link InstanceKey} carrying information about which {@link CGNode}s
* represent lexical parents of the allocating {@link CGNode}.
*
* The fact that we discover at most one {@link CGNode} per lexical parent
* relies on the following property: in a call graph, the contexts used for a
* nested function can be finer than those used for the containing function,
* but _not_ coarser. This ensures that there is at most one CGNode
* corresponding to a lexical parent (e.g., we don't get two clones of
* function f1() invoking a single CGNode representing nested function f2())
*
* Note that it is possible to not find a {@link CGNode} corresponding to some
* lexical parent; this occurs when a deeply nested function is returned
* before being invoked, so some lexical parent is no longer on the call stack
* when the function is allocated. See test case nested.js.
*/
public class ScopeMappingInstanceKey implements InstanceKey {
/**
* the underlying instance key
*/
private final InstanceKey base;
/**
* the node in which base is allocated
*/
private final CGNode creator;
/**
* compute the {@link CGNode} correspond to each specified
* {@link LexicalParent} of {@link #base}, populating {@link #scopeMap}
*
*/
private ScopeMappingInstanceKey(CGNode creator, InstanceKey base) {
this.creator = creator;
this.base = base;
}
public IClass getConcreteType() {
return base.getConcreteType();
}
/**
* get the CGNode representing the lexical parent of {@link #creator} with name definer
* @param definer
* @return
*/
Iterator<CGNode> getFunargNodes(Pair<String,String> name) {
Iterator<CGNode> result = EmptyIterator.instance();
Resolver r = (Resolver)creator.getContext().get(LexicalScopingResolverContexts.RESOLVER);
if (r != null) {
CGNode def = r.getFunarg(name);
if (def != null) {
result = new NonNullSingletonIterator<CGNode>(def);
}
}
PointerKey funcKey = builder.getPointerKeyForLocal(creator, 1);
OrdinalSet<InstanceKey> funcPtrs = builder.getPointerAnalysis().getPointsToSet(funcKey);
for(InstanceKey x : funcPtrs) {
if (x instanceof ScopeMappingInstanceKey) {
result = new CompoundIterator<CGNode>(result, ((ScopeMappingInstanceKey)x).getFunargNodes(name));
}
}
return result;
}
public int hashCode() {
return base.hashCode() * creator.hashCode();
}
public boolean equals(Object o) {
return (o instanceof ScopeMappingInstanceKey) && ((ScopeMappingInstanceKey) o).base.equals(base)
&& ((ScopeMappingInstanceKey) o).creator.equals(creator);
}
public String toString() {
return "SMIK:" + base + "@" + creator;
}
}
public InstanceKey getInstanceKeyForAllocation(CGNode creatorNode, NewSiteReference allocationSite) {
InstanceKey base = basic.getInstanceKeyForAllocation(creatorNode, allocationSite);
if (base != null && needsScopeMappingKey(base)) {
return new ScopeMappingInstanceKey(creatorNode, base);
} else {
return base;
}
}
public InstanceKey getInstanceKeyForMultiNewArray(CGNode node, NewSiteReference allocation, int dim) {
return basic.getInstanceKeyForMultiNewArray(node, allocation, dim);
}
public InstanceKey getInstanceKeyForConstant(TypeReference type, Object S) {
return basic.getInstanceKeyForConstant(type, S);
}
public InstanceKey getInstanceKeyForPEI(CGNode node, ProgramCounter instr, TypeReference type) {
return basic.getInstanceKeyForPEI(node, instr, type);
}
public InstanceKey getInstanceKeyForClassObject(TypeReference type) {
return basic.getInstanceKeyForClassObject(type);
}
public ScopeMappingInstanceKeys(PropagationCallGraphBuilder builder, InstanceKeyFactory basic) {
this.basic = basic;
this.builder = builder;
}
}