com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.ibm.wala.cast.js Show documentation
Show all versions of com.ibm.wala.cast.js Show documentation
T. J. Watson Libraries for Analysis
/*
* Copyright (c) 2013 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.js.ipa.callgraph;
import com.ibm.wala.cast.ipa.callgraph.CAstCallGraphUtil;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummarizedFunction;
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptSummary;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.ssa.JSInstructionFactory;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.js.types.JavaScriptTypes;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.cast.loader.DynamicCallSiteReference;
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.core.util.strings.Atom;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.intset.IntIterator;
import java.util.Map;
/**
* Generate IR to model Function.call()
*
* @see MDN
* Function.call() docs
* @author manu
*/
public class JavaScriptFunctionDotCallTargetSelector implements MethodTargetSelector {
/*
* Call graph imprecision often leads to spurious invocations of Function.prototype.call; two common
* patterns are invocations of "new" on Function.prototype.call (which in reality would lead to a
* type error), and self-applications of Function.prototype.call.
*
* While neither of these situations is a priori impossible, they are most likely due to analysis
* imprecision. If this flag is set to true, we emit a warning when seeing them.
*/
public static boolean WARN_ABOUT_IMPRECISE_CALLGRAPH = true;
public static final boolean DEBUG_SYNTHETIC_CALL_METHODS = false;
private static final TypeName CALL_TYPE_NAME =
TypeName.findOrCreate("Lprologue.js/Function_prototype_call");
private final MethodTargetSelector base;
public JavaScriptFunctionDotCallTargetSelector(MethodTargetSelector base) {
this.base = base;
}
/*
* (non-Javadoc)
*
* @see
* com.ibm.wala.ipa.callgraph.MethodTargetSelector#getCalleeTarget(com.ibm
* .wala.ipa.callgraph.CGNode, com.ibm.wala.classLoader.CallSiteReference,
* com.ibm.wala.classLoader.IClass)
*/
@Override
public IMethod getCalleeTarget(CGNode caller, CallSiteReference site, IClass receiver) {
IMethod method = receiver.getMethod(AstMethodReference.fnSelector);
if (method != null) {
TypeName tn = method.getReference().getDeclaringClass().getName();
if (tn.equals(CALL_TYPE_NAME)) {
/* invoking Function.prototype.call as a constructor results in a TypeError
* see ECMA-262 5.1, 15: "None of the built-in functions described in this clause that
* are not constructors shall implement the [[Construct]] internal method unless otherwise
* specified" */
if (!site.getDeclaredTarget().equals(JavaScriptMethods.ctorReference)) {
IMethod target = getFunctionCallTarget(caller, site, receiver);
if (target != null) return target;
}
// if we get here, we either saw an invocation of "call" as a constructor, or an invocation
// without receiver object; in either case, this is likely due to bad call graph info
if (WARN_ABOUT_IMPRECISE_CALLGRAPH) warnAboutImpreciseCallGraph(caller, site);
}
}
return base.getCalleeTarget(caller, site, receiver);
}
protected void warnAboutImpreciseCallGraph(CGNode caller, CallSiteReference site) {
IntIterator indices = caller.getIR().getCallInstructionIndices(site).intIterator();
IMethod callerMethod = caller.getMethod();
Position pos = null;
if (indices.hasNext() && callerMethod instanceof AstMethod) {
pos = ((AstMethod) callerMethod).getSourcePosition(indices.next());
}
System.err.println(
"Detected improbable call to Function.prototype.call "
+ (pos == null ? "in function " + caller : "at position " + pos)
+ "; this is likely caused by call graph imprecision.");
}
private static final boolean SEPARATE_SYNTHETIC_METHOD_PER_SITE = false;
/** cache synthetic method for each arity of Function.call() invocation */
private final Map