2007-02-02 17:25:09 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* 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.js.ipa.callgraph;
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
import java.io.UnsupportedEncodingException;
|
2010-04-28 19:38:28 +00:00
|
|
|
import java.net.URL;
|
2007-07-06 22:09:08 +00:00
|
|
|
import java.util.Set;
|
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.analysis.typeInference.TypeInference;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.ipa.callgraph.AstSSAPropagationCallGraphBuilder;
|
2015-04-06 01:19:56 +00:00
|
|
|
import com.ibm.wala.cast.ipa.callgraph.GlobalObjectKey;
|
2012-01-06 21:22:58 +00:00
|
|
|
import com.ibm.wala.cast.ir.ssa.AstGlobalRead;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstGlobalWrite;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
2016-09-16 01:32:35 +00:00
|
|
|
import com.ibm.wala.cast.ir.ssa.CAstUnaryOp;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.cast.js.analysis.typeInference.JSTypeInference;
|
2012-01-06 21:24:25 +00:00
|
|
|
import com.ibm.wala.cast.js.ipa.callgraph.JSSSAPropagationCallGraphBuilder.JSPointerAnalysisImpl.JSImplicitPointsToSetVisitor;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JSInstructionVisitor;
|
2009-01-27 17:40:11 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptCheckReference;
|
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptInstanceOf;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
|
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyRead;
|
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptPropertyWrite;
|
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptTypeOfInstruction;
|
2009-01-27 17:40:11 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptWithRegion;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.PrototypeLookup;
|
|
|
|
import com.ibm.wala.cast.js.ssa.SetPrototype;
|
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptMethods;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptTypes;
|
2011-07-01 16:48:18 +00:00
|
|
|
import com.ibm.wala.cast.loader.AstMethod;
|
|
|
|
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.classLoader.IClass;
|
2012-01-06 21:22:58 +00:00
|
|
|
import com.ibm.wala.classLoader.IField;
|
2011-07-01 16:48:18 +00:00
|
|
|
import com.ibm.wala.classLoader.IMethod;
|
2012-03-08 17:35:04 +00:00
|
|
|
import com.ibm.wala.classLoader.Language;
|
2011-01-17 21:43:18 +00:00
|
|
|
import com.ibm.wala.fixpoint.AbstractOperator;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.fixpoint.UnaryOperator;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
|
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
|
|
|
import com.ibm.wala.ipa.callgraph.CallGraph;
|
2017-02-03 01:33:27 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.IAnalysisCacheView;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
|
2012-03-01 02:45:51 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.AbstractFieldPointerKey;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.ConcreteTypeKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.ConstantKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.FilteredPointerKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.InstanceKeyFactory;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.LocalPointerKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointerKeyFactory;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointsToMap;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointsToSetVariable;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
|
|
|
|
import com.ibm.wala.ipa.callgraph.propagation.PropagationSystem;
|
2007-06-01 03:32:56 +00:00
|
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.shrikeBT.BinaryOpInstruction;
|
2009-02-19 15:59:55 +00:00
|
|
|
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.ssa.DefUse;
|
|
|
|
import com.ibm.wala.ssa.IR;
|
2017-03-11 18:22:45 +00:00
|
|
|
import com.ibm.wala.ssa.IRView;
|
2015-07-25 02:44:10 +00:00
|
|
|
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
|
2011-04-27 13:58:56 +00:00
|
|
|
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.ssa.SSABinaryOpInstruction;
|
2011-05-04 21:06:35 +00:00
|
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.ssa.SSAUnaryOpInstruction;
|
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
2012-01-06 21:22:58 +00:00
|
|
|
import com.ibm.wala.types.FieldReference;
|
2011-05-04 21:06:35 +00:00
|
|
|
import com.ibm.wala.types.TypeReference;
|
2013-04-09 22:47:22 +00:00
|
|
|
import com.ibm.wala.util.CancelException;
|
|
|
|
import com.ibm.wala.util.CancelRuntimeException;
|
|
|
|
import com.ibm.wala.util.MonitorUtil;
|
2007-07-11 21:08:21 +00:00
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
2012-01-06 21:22:58 +00:00
|
|
|
import com.ibm.wala.util.intset.IntSet;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.util.intset.IntSetAction;
|
2016-09-16 01:32:35 +00:00
|
|
|
import com.ibm.wala.util.intset.IntSetUtil;
|
|
|
|
import com.ibm.wala.util.intset.MutableIntSet;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.util.intset.MutableMapping;
|
2012-01-06 21:22:58 +00:00
|
|
|
import com.ibm.wala.util.intset.MutableSparseIntSet;
|
|
|
|
import com.ibm.wala.util.intset.OrdinalSet;
|
2012-01-06 21:23:56 +00:00
|
|
|
import com.ibm.wala.util.strings.Atom;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2012-01-06 21:24:25 +00:00
|
|
|
/**
|
|
|
|
* Specialized pointer analysis constraint generation for JavaScript.
|
|
|
|
*
|
|
|
|
* <h2>Global object handling</h2>
|
|
|
|
*
|
|
|
|
* The global object is represented by a {@link GlobalObjectKey} stored in
|
|
|
|
* {@link #globalObject}. {@link AstGlobalRead} and {@link AstGlobalWrite}
|
|
|
|
* instructions are treated as accessing properties of the global object; see
|
|
|
|
* {@link JSConstraintVisitor#visitAstGlobalRead(AstGlobalRead)},
|
|
|
|
* {@link JSConstraintVisitor#visitAstGlobalWrite(AstGlobalWrite)}, and
|
|
|
|
* {@link JSImplicitPointsToSetVisitor#visitAstGlobalRead(AstGlobalRead)}.
|
|
|
|
* Finally, we need to represent direct flow of the global object to handle
|
|
|
|
* receiver argument semantics (see
|
|
|
|
* {@link org.mozilla.javascript.RhinoToAstTranslator}). To do so, we create a
|
|
|
|
* reference to a global named {@link #GLOBAL_OBJ_VAR_NAME}, which is handled
|
|
|
|
* specially in {@link JSConstraintVisitor#visitAstGlobalRead(AstGlobalRead)}.
|
|
|
|
*/
|
2017-03-22 23:26:05 +00:00
|
|
|
@SuppressWarnings("javadoc")
|
2007-02-02 17:25:09 +00:00
|
|
|
public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraphBuilder {
|
|
|
|
|
|
|
|
public static final boolean DEBUG_LEXICAL = false;
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
public static final boolean DEBUG_TYPE_INFERENCE = false;
|
|
|
|
|
2012-01-06 21:23:56 +00:00
|
|
|
/**
|
|
|
|
* name to be used internally to pass around the global object
|
|
|
|
*/
|
|
|
|
public static final String GLOBAL_OBJ_VAR_NAME = "__WALA__int3rnal__global";
|
|
|
|
|
2015-04-06 01:19:56 +00:00
|
|
|
private final GlobalObjectKey globalObject;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public GlobalObjectKey getGlobalObject(Atom language) {
|
|
|
|
assert language.equals(JavaScriptTypes.jsName);
|
|
|
|
return globalObject;
|
|
|
|
}
|
|
|
|
|
2012-01-06 21:23:56 +00:00
|
|
|
/**
|
|
|
|
* is field a direct (WALA-internal) reference to the global object?
|
|
|
|
*/
|
|
|
|
private static boolean directGlobalObjectRef(FieldReference field) {
|
|
|
|
return field.getName().toString().endsWith(GLOBAL_OBJ_VAR_NAME);
|
|
|
|
}
|
2012-01-06 21:24:25 +00:00
|
|
|
|
2012-01-06 21:23:56 +00:00
|
|
|
private static FieldReference makeNonGlobalFieldReference(FieldReference field) {
|
|
|
|
String nonGlobalFieldName = field.getName().toString().substring(7);
|
2012-01-06 21:24:25 +00:00
|
|
|
field = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreateUnicodeAtom(nonGlobalFieldName),
|
|
|
|
JavaScriptTypes.Root);
|
2012-01-06 21:23:56 +00:00
|
|
|
return field;
|
|
|
|
}
|
|
|
|
|
2011-04-04 15:23:58 +00:00
|
|
|
private URL scriptBaseURL;
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2011-04-04 15:23:58 +00:00
|
|
|
public URL getBaseURL() {
|
|
|
|
return scriptBaseURL;
|
|
|
|
}
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2010-04-28 19:38:28 +00:00
|
|
|
public void setBaseURL(URL url) {
|
|
|
|
this.scriptBaseURL = url;
|
|
|
|
}
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2017-02-03 01:33:27 +00:00
|
|
|
protected JSSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, IAnalysisCacheView cache,
|
2007-12-04 21:40:38 +00:00
|
|
|
PointerKeyFactory pointerKeyFactory) {
|
2007-07-20 15:20:23 +00:00
|
|
|
super(cha, options, cache, pointerKeyFactory);
|
2015-04-06 01:19:56 +00:00
|
|
|
globalObject = new GlobalObjectKey(cha.lookupClass(JavaScriptTypes.Root));
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected boolean isConstantRef(SymbolTable symbolTable, int valueNumber) {
|
|
|
|
if (valueNumber == -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return symbolTable.isConstant(valueNumber);
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
//
|
|
|
|
// language specialization interface
|
|
|
|
//
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
protected boolean useObjectCatalog() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2010-11-02 19:11:58 +00:00
|
|
|
protected boolean isUncataloguedField(IClass type, String fieldName) {
|
2011-05-04 21:06:35 +00:00
|
|
|
if (!type.getReference().equals(JavaScriptTypes.Object)) {
|
2010-11-02 19:11:58 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-05-04 21:06:35 +00:00
|
|
|
return "prototype".equals(fieldName) || "constructor".equals(fieldName) || "arguments".equals(fieldName)
|
2012-01-06 21:44:25 +00:00
|
|
|
|| "class".equals(fieldName) || "$value".equals(fieldName) || "__proto__".equals(fieldName);
|
2010-11-02 19:11:58 +00:00
|
|
|
}
|
|
|
|
|
2014-10-15 07:01:38 +00:00
|
|
|
@Override
|
|
|
|
protected AbstractFieldPointerKey fieldKeyForUnknownWrites(AbstractFieldPointerKey fieldKey) {
|
|
|
|
// TODO: fix this. null is wrong.
|
|
|
|
return null;
|
|
|
|
// return ReflectedFieldPointerKey.mapped(new ConcreteTypeKey(cha.lookupClass(JavaScriptTypes.String)), fieldKey.getInstanceKey());
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
//
|
|
|
|
// top-level node constraint generation
|
|
|
|
//
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2014-08-07 20:02:48 +00:00
|
|
|
private final static FieldReference prototypeRef;
|
|
|
|
static {
|
|
|
|
FieldReference x = null;
|
|
|
|
try {
|
|
|
|
byte[] utf8 = "__proto__".getBytes("UTF-8");
|
|
|
|
x = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreate(utf8, 0, utf8.length), JavaScriptTypes.Root);
|
|
|
|
} catch (UnsupportedEncodingException e) {
|
|
|
|
assert false;
|
|
|
|
}
|
|
|
|
prototypeRef = x;
|
|
|
|
}
|
|
|
|
|
2012-10-29 17:19:52 +00:00
|
|
|
public PointerKey getPointerKeyForGlobalVar(String varName) {
|
|
|
|
FieldReference fieldRef = FieldReference.findOrCreate(JavaScriptTypes.Root, Atom.findOrCreateUnicodeAtom(varName),
|
|
|
|
JavaScriptTypes.Root);
|
|
|
|
IField f = cha.resolveField(fieldRef);
|
|
|
|
assert f != null : "couldn't resolve " + varName;
|
2015-04-06 01:19:56 +00:00
|
|
|
return getPointerKeyForInstanceField(getGlobalObject(JavaScriptTypes.jsName), f);
|
2012-10-29 17:19:52 +00:00
|
|
|
}
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
protected ExplicitCallGraph createEmptyCallGraph(IClassHierarchy cha, AnalysisOptions options) {
|
2007-07-20 15:20:23 +00:00
|
|
|
return new JSCallGraph(cha, options, getAnalysisCache());
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
protected TypeInference makeTypeInference(IR ir, IClassHierarchy cha) {
|
2007-02-02 17:25:09 +00:00
|
|
|
TypeInference ti = new JSTypeInference(ir, cha);
|
|
|
|
|
|
|
|
if (DEBUG_TYPE_INFERENCE) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println(("IR of " + ir.getMethod()));
|
|
|
|
System.err.println(ir);
|
|
|
|
System.err.println(("TypeInference of " + ir.getMethod()));
|
2007-08-22 15:33:55 +00:00
|
|
|
for (int i = 0; i <= ir.getSymbolTable().getMaxValueNumber(); i++) {
|
2007-07-06 22:09:08 +00:00
|
|
|
if (ti.isUndefined(i)) {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((" value " + i + " is undefined"));
|
2007-07-06 22:09:08 +00:00
|
|
|
} else {
|
2009-04-09 20:31:14 +00:00
|
|
|
System.err.println((" value " + i + " has type " + ti.getType(i)));
|
2007-07-06 22:09:08 +00:00
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ti;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
protected void addAssignmentsForCatchPointerKey(PointerKey exceptionVar, Set<IClass> catchClasses, PointerKey e) {
|
2007-02-02 17:25:09 +00:00
|
|
|
system.newConstraint(exceptionVar, assignOperator, e);
|
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
public static class JSInterestingVisitor extends AstInterestingVisitor implements com.ibm.wala.cast.js.ssa.JSInstructionVisitor {
|
2007-06-01 03:32:56 +00:00
|
|
|
public JSInterestingVisitor(int vn) {
|
2007-02-02 17:25:09 +00:00
|
|
|
super(vn);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitBinaryOp(final SSABinaryOpInstruction instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction inst) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitJavaScriptInstanceOf(JavaScriptInstanceOf instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitCheckRef(JavaScriptCheckReference instruction) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitWithRegion(JavaScriptWithRegion instruction) {
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
2012-03-01 02:45:51 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitSetPrototype(SetPrototype instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitPrototypeLookup(PrototypeLookup instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
protected InterestingVisitor makeInterestingVisitor(CGNode node, int vn) {
|
2007-02-02 17:25:09 +00:00
|
|
|
return new JSInterestingVisitor(vn);
|
|
|
|
}
|
2016-09-16 01:32:35 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
//
|
|
|
|
// specialized pointer analysis
|
|
|
|
//
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2014-08-07 20:02:48 +00:00
|
|
|
public static class JSPointerAnalysisImpl extends AstSSAPropagationCallGraphBuilder.AstPointerAnalysisImpl {
|
2007-07-06 22:09:08 +00:00
|
|
|
|
|
|
|
JSPointerAnalysisImpl(PropagationCallGraphBuilder builder, CallGraph cg, PointsToMap pointsToMap,
|
|
|
|
MutableMapping<InstanceKey> instanceKeys, PointerKeyFactory pointerKeys, InstanceKeyFactory iKeyFactory) {
|
|
|
|
super(builder, cg, pointsToMap, instanceKeys, pointerKeys, iKeyFactory);
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public static class JSImplicitPointsToSetVisitor extends AstImplicitPointsToSetVisitor implements
|
2012-03-01 02:45:51 +00:00
|
|
|
com.ibm.wala.cast.js.ssa.JSInstructionVisitor {
|
2012-01-06 21:23:56 +00:00
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
public JSImplicitPointsToSetVisitor(AstPointerAnalysisImpl analysis, LocalPointerKey lpk) {
|
2007-07-06 22:09:08 +00:00
|
|
|
super(analysis, lpk);
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:53:31 +00:00
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:53:31 +00:00
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
|
|
|
|
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:53:31 +00:00
|
|
|
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:53:31 +00:00
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
|
|
|
|
|
|
|
}
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitJavaScriptInstanceOf(JavaScriptInstanceOf instruction) {
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitCheckRef(JavaScriptCheckReference instruction) {
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitWithRegion(JavaScriptWithRegion instruction) {
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
2012-01-06 21:22:58 +00:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitAstGlobalRead(AstGlobalRead instruction) {
|
|
|
|
JSPointerAnalysisImpl jsAnalysis = (JSPointerAnalysisImpl) analysis;
|
2012-01-06 21:23:56 +00:00
|
|
|
FieldReference field = makeNonGlobalFieldReference(instruction.getDeclaredField());
|
2012-01-06 21:24:25 +00:00
|
|
|
assert !directGlobalObjectRef(field);
|
2012-01-06 21:22:58 +00:00
|
|
|
IField f = jsAnalysis.builder.getCallGraph().getClassHierarchy().resolveField(field);
|
|
|
|
assert f != null;
|
|
|
|
MutableSparseIntSet S = MutableSparseIntSet.makeEmpty();
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey globalObj = ((AstSSAPropagationCallGraphBuilder) jsAnalysis.builder).getGlobalObject(JavaScriptTypes.jsName);
|
2012-01-06 21:23:56 +00:00
|
|
|
PointerKey fkey = analysis.getHeapModel().getPointerKeyForInstanceField(globalObj, f);
|
2012-01-06 21:22:58 +00:00
|
|
|
if (fkey != null) {
|
Fix nearly all Eclipse warnings about using raw types
Along the way, I also converted many "for (;;)" loops into modern
"for (:)" loops. I didn't systematically look for all opportunities
to do this, though. I merely made this change where I was already
converting raw Iterator uses into modern Iterator<...> uses.
Better use of generics also allowed many casts to become statically
redundant. I have removed all such redundant casts.
Only three raw-types warnings remain after this batch of fixes. All
three involve raw uses of CallGraphBuilder. I've tried to fix these
too, but it quickly snowballs into a cascade of changes that may or
may not eventually reach a statically-type-save fixed point. I may
give these last few problem areas another go in the future. For now,
though, the hundreds of other fixes seem worth keeping even if there
are a few stragglers.
This commit may change some public APIs, but only by making weaker
type signatures stronger by replacing raw types with generic types.
For example, we may change something like "Set" into "Set<String>",
but we're not adding new arguments, changing any
underlying (post-generics-erasure) types, etc.
2017-07-09 18:38:35 +00:00
|
|
|
OrdinalSet<InstanceKey> pointees = analysis.getPointsToSet(fkey);
|
2012-01-06 21:22:58 +00:00
|
|
|
IntSet set = pointees.getBackingSet();
|
|
|
|
if (set != null) {
|
|
|
|
S.addAll(set);
|
|
|
|
}
|
|
|
|
}
|
2017-03-12 03:20:51 +00:00
|
|
|
pointsToSet = new OrdinalSet<>(S, analysis.getInstanceKeyMapping());
|
2012-01-06 21:22:58 +00:00
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
@Override
|
|
|
|
public void visitSetPrototype(SetPrototype instruction) {
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitPrototypeLookup(PrototypeLookup instruction) {
|
|
|
|
}
|
|
|
|
|
2017-07-12 23:54:57 +00:00
|
|
|
}
|
2007-04-19 13:53:31 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-06 22:09:08 +00:00
|
|
|
protected ImplicitPointsToSetVisitor makeImplicitPointsToVisitor(LocalPointerKey lpk) {
|
2007-06-01 03:32:56 +00:00
|
|
|
return new JSImplicitPointsToSetVisitor(this, lpk);
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
2017-07-12 23:54:57 +00:00
|
|
|
}
|
2007-04-19 13:53:31 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-04-19 13:53:31 +00:00
|
|
|
protected PropagationSystem makeSystem(AnalysisOptions options) {
|
2010-05-12 18:30:55 +00:00
|
|
|
return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory) {
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2014-05-20 20:00:06 +00:00
|
|
|
public PointerAnalysis<InstanceKey> makePointerAnalysis(PropagationCallGraphBuilder builder) {
|
2007-07-06 22:09:08 +00:00
|
|
|
return new JSPointerAnalysisImpl(builder, cg, pointsToMap, instanceKeys, pointerKeyFactory, instanceKeyFactory);
|
2007-04-19 13:53:31 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-06-01 03:32:56 +00:00
|
|
|
//
|
|
|
|
// IR visitor specialization for JavaScript
|
|
|
|
//
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2015-04-06 01:19:56 +00:00
|
|
|
public JSConstraintVisitor makeVisitor(CGNode node) {
|
2011-07-01 16:48:18 +00:00
|
|
|
if (AstSSAPropagationCallGraphBuilder.DEBUG_PROPERTIES) {
|
|
|
|
final IMethod method = node.getMethod();
|
|
|
|
if (method instanceof AstMethod) {
|
|
|
|
System.err.println("\n\nNode: " + node);
|
|
|
|
final IR ir = node.getIR();
|
|
|
|
System.err.println("Position: " + getSomePositionForMethod(ir, (AstMethod) method));
|
|
|
|
// System.err.println(ir);
|
|
|
|
}
|
|
|
|
}
|
2007-06-01 03:32:56 +00:00
|
|
|
return new JSConstraintVisitor(this, node);
|
|
|
|
}
|
|
|
|
|
2012-01-06 21:31:44 +00:00
|
|
|
public static Position getSomePositionForMethod(IR ir, AstMethod method) {
|
2011-07-01 16:48:18 +00:00
|
|
|
SSAInstruction[] instructions = ir.getInstructions();
|
|
|
|
for (int i = 0; i < instructions.length; i++) {
|
|
|
|
Position p = method.getSourcePosition(i);
|
|
|
|
if (p != null) {
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
public static class JSConstraintVisitor extends AstConstraintVisitor implements JSInstructionVisitor {
|
2007-06-01 03:32:56 +00:00
|
|
|
|
2011-04-27 13:58:56 +00:00
|
|
|
public JSConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
|
2007-06-01 03:32:56 +00:00
|
|
|
super(builder, node);
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitUnaryOp(SSAUnaryOpInstruction inst) {
|
2009-02-19 15:59:55 +00:00
|
|
|
if (inst.getOpcode() == IUnaryOpInstruction.Operator.NEG) {
|
2011-05-04 21:06:35 +00:00
|
|
|
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Boolean);
|
2016-09-16 01:32:35 +00:00
|
|
|
} else if (inst.getOpcode() == CAstUnaryOp.MINUS) {
|
|
|
|
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Number);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-04 21:06:35 +00:00
|
|
|
/**
|
|
|
|
* add a constraint indicating that the value def'd by inst can point to a
|
|
|
|
* value of type t
|
|
|
|
*/
|
|
|
|
private void addLvalTypeKeyConstraint(SSAInstruction inst, TypeReference t) {
|
2007-06-01 03:32:56 +00:00
|
|
|
int lval = inst.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2011-05-04 21:06:35 +00:00
|
|
|
IClass bool = getClassHierarchy().lookupClass(t);
|
2007-07-06 22:09:08 +00:00
|
|
|
InstanceKey key = new ConcreteTypeKey(bool);
|
2007-06-01 03:32:56 +00:00
|
|
|
|
|
|
|
system.newConstraint(lk, key);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-05-04 21:06:35 +00:00
|
|
|
public void visitIsDefined(AstIsDefinedInstruction inst) {
|
|
|
|
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Boolean);
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2011-05-04 21:06:35 +00:00
|
|
|
}
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-05-04 21:06:35 +00:00
|
|
|
public void visitJavaScriptInstanceOf(JavaScriptInstanceOf inst) {
|
|
|
|
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Boolean);
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
|
2011-05-04 21:06:35 +00:00
|
|
|
addLvalTypeKeyConstraint(inst, JavaScriptTypes.Boolean);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
|
2011-05-04 21:06:35 +00:00
|
|
|
addLvalTypeKeyConstraint(instruction, JavaScriptTypes.String);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
|
2012-01-06 21:22:58 +00:00
|
|
|
@Override
|
|
|
|
public void visitAstGlobalRead(AstGlobalRead instruction) {
|
|
|
|
int lval = instruction.getDef();
|
2012-01-06 21:23:56 +00:00
|
|
|
FieldReference field = makeNonGlobalFieldReference(instruction.getDeclaredField());
|
2012-01-06 21:22:58 +00:00
|
|
|
PointerKey def = getPointerKeyForLocal(lval);
|
|
|
|
assert def != null;
|
|
|
|
IField f = getClassHierarchy().resolveField(field);
|
|
|
|
assert f != null : "could not resolve referenced global " + field;
|
|
|
|
if (hasNoInterestingUses(lval)) {
|
|
|
|
system.recordImplicitPointsToSet(def);
|
|
|
|
} else {
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey globalObj = getBuilder().getGlobalObject(JavaScriptTypes.jsName);
|
2012-01-06 21:23:56 +00:00
|
|
|
if (directGlobalObjectRef(field)) {
|
|
|
|
// points-to set is just the global object
|
|
|
|
system.newConstraint(def, globalObj);
|
|
|
|
} else {
|
|
|
|
system.findOrCreateIndexForInstanceKey(globalObj);
|
|
|
|
PointerKey p = getPointerKeyForInstanceField(globalObj, f);
|
|
|
|
system.newConstraint(def, assignOperator, p);
|
|
|
|
}
|
2012-01-06 21:22:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitAstGlobalWrite(AstGlobalWrite instruction) {
|
|
|
|
int rval = instruction.getVal();
|
2012-01-06 21:23:56 +00:00
|
|
|
FieldReference field = makeNonGlobalFieldReference(instruction.getDeclaredField());
|
2012-01-06 21:22:58 +00:00
|
|
|
IField f = getClassHierarchy().resolveField(field);
|
|
|
|
assert f != null : "could not resolve referenced global " + field;
|
|
|
|
assert !f.getFieldTypeReference().isPrimitiveType();
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey globalObj = getBuilder().getGlobalObject(JavaScriptTypes.jsName);
|
2012-01-06 21:22:58 +00:00
|
|
|
system.findOrCreateIndexForInstanceKey(globalObj);
|
|
|
|
PointerKey p = getPointerKeyForInstanceField(globalObj, f);
|
|
|
|
|
|
|
|
PointerKey rvalKey = getPointerKeyForLocal(rval);
|
|
|
|
if (contentsAreInvariant(symbolTable, du, rval)) {
|
|
|
|
system.recordImplicitPointsToSet(rvalKey);
|
|
|
|
InstanceKey[] ik = getInvariantContents(rval);
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey element : ik) {
|
|
|
|
system.newConstraint(p, element);
|
2012-01-06 21:22:58 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
system.newConstraint(p, assignOperator, rvalKey);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitBinaryOp(final SSABinaryOpInstruction instruction) {
|
2007-07-06 22:09:08 +00:00
|
|
|
handleBinaryOp(instruction, node, symbolTable, du);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
|
2011-07-02 15:34:21 +00:00
|
|
|
if (AstSSAPropagationCallGraphBuilder.DEBUG_PROPERTIES) {
|
|
|
|
Position instructionPosition = getInstructionPosition(instruction);
|
|
|
|
if (instructionPosition != null) {
|
|
|
|
System.err.println("processing read instruction " + instruction + ", position " + instructionPosition);
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
newFieldRead(node, instruction.getUse(0), instruction.getUse(1), instruction.getDef(0));
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2011-07-02 15:34:21 +00:00
|
|
|
private Position getInstructionPosition(SSAInstruction instruction) {
|
|
|
|
IMethod method = node.getMethod();
|
|
|
|
if (method instanceof AstMethod) {
|
2017-02-03 01:33:27 +00:00
|
|
|
return ((AstMethod) method).getSourcePosition(instruction.iindex);
|
2011-07-02 15:34:21 +00:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
2011-07-02 15:34:21 +00:00
|
|
|
if (AstSSAPropagationCallGraphBuilder.DEBUG_PROPERTIES) {
|
|
|
|
Position instructionPosition = getInstructionPosition(instruction);
|
|
|
|
if (instructionPosition != null) {
|
|
|
|
System.err.println("processing write instruction " + instruction + ", position " + instructionPosition);
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
newFieldWrite(node, instruction.getUse(0), instruction.getUse(1), instruction.getUse(2));
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
2012-03-01 02:45:51 +00:00
|
|
|
if (instruction.getDeclaredTarget().equals(JavaScriptMethods.dispatchReference)) {
|
|
|
|
handleJavascriptDispatch(instruction);
|
|
|
|
} else {
|
2015-04-06 01:19:56 +00:00
|
|
|
if (! instruction.getDeclaredTarget().equals(JavaScriptMethods.ctorReference)) {
|
|
|
|
System.err.println(instruction);
|
|
|
|
}
|
2012-03-01 02:45:51 +00:00
|
|
|
visitInvokeInternal(instruction, new DefaultInvariantComputer());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void handleJavascriptDispatch(final JavaScriptInvoke instruction, final InstanceKey receiverType) {
|
|
|
|
int functionVn = instruction.getFunction();
|
|
|
|
|
|
|
|
ReflectedFieldAction fieldDispatchAction = new ReflectedFieldAction() {
|
|
|
|
@Override
|
|
|
|
public void action(final AbstractFieldPointerKey fieldKey) {
|
|
|
|
class FieldValueDispatch extends UnaryOperator<PointsToSetVariable> {
|
|
|
|
private JavaScriptInvoke getInstruction() { return instruction; }
|
|
|
|
private InstanceKey getReceiver() { return receiverType; }
|
|
|
|
private AbstractFieldPointerKey getProperty() { return fieldKey; }
|
2012-10-31 00:31:28 +00:00
|
|
|
private CGNode getNode() { return node; }
|
2012-03-01 02:45:51 +00:00
|
|
|
|
2016-09-16 01:32:35 +00:00
|
|
|
private MutableIntSet previous = IntSetUtil.make();
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
@Override
|
|
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable ptrs) {
|
|
|
|
if (ptrs.getValue() != null) {
|
2017-11-23 01:28:36 +00:00
|
|
|
ptrs.getValue().foreachExcluding(previous, x -> {
|
|
|
|
final InstanceKey functionObj = system.getInstanceKey(x);
|
|
|
|
visitInvokeInternal(instruction, new DefaultInvariantComputer() {
|
|
|
|
@Override
|
|
|
|
public InstanceKey[][] computeInvariantParameters(SSAAbstractInvokeInstruction call) {
|
|
|
|
InstanceKey[][] x = super.computeInvariantParameters(call);
|
|
|
|
if (x == null) {
|
|
|
|
x = new InstanceKey[call.getNumberOfUses()][];
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
2017-11-23 01:28:36 +00:00
|
|
|
x[0] = new InstanceKey[]{ functionObj };
|
|
|
|
x[1] = new InstanceKey[]{ receiverType };
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
});
|
2012-03-01 02:45:51 +00:00
|
|
|
});
|
2016-09-16 01:32:35 +00:00
|
|
|
previous.addAll(ptrs.getValue());
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
|
|
|
return NOT_CHANGED;
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return instruction.hashCode() * fieldKey.hashCode() * receiverType.hashCode();
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
return o instanceof FieldValueDispatch &&
|
2012-10-31 00:31:28 +00:00
|
|
|
((FieldValueDispatch)o).getNode().equals(node) &&
|
2012-03-01 02:45:51 +00:00
|
|
|
((FieldValueDispatch)o).getInstruction() == instruction &&
|
|
|
|
((FieldValueDispatch)o).getProperty().equals(fieldKey) &&
|
|
|
|
((FieldValueDispatch)o).getReceiver().equals(receiverType);
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "sub-dispatch for " + instruction + ": " + receiverType + ", " + fieldKey;
|
|
|
|
}
|
2017-07-12 23:54:57 +00:00
|
|
|
}
|
2012-03-01 02:45:51 +00:00
|
|
|
|
|
|
|
system.newSideEffect(new FieldValueDispatch(), fieldKey);
|
|
|
|
}
|
|
|
|
@Override
|
|
|
|
public void dump(AbstractFieldPointerKey fieldKey, boolean constObj, boolean constProp) {
|
|
|
|
System.err.println("dispatch to " + receiverType + "." + fieldKey + " for " + instruction);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TransitivePrototypeKey prototypeObjs = new TransitivePrototypeKey(receiverType);
|
|
|
|
InstanceKey[] objKeys = new InstanceKey[]{ receiverType };
|
|
|
|
if (contentsAreInvariant(symbolTable, du, functionVn)) {
|
|
|
|
InstanceKey[] fieldsKeys = getInvariantContents(functionVn);
|
|
|
|
newFieldOperationObjectAndFieldConstant(true, fieldDispatchAction, objKeys, fieldsKeys);
|
|
|
|
newFieldOperationOnlyFieldConstant(true, fieldDispatchAction, prototypeObjs, fieldsKeys);
|
|
|
|
} else {
|
|
|
|
PointerKey fieldKey = getPointerKeyForLocal(functionVn);
|
|
|
|
newFieldOperationOnlyObjectConstant(true, fieldDispatchAction, fieldKey, objKeys);
|
|
|
|
newFieldFullOperation(true, fieldDispatchAction, prototypeObjs, fieldKey);
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2012-03-01 02:45:51 +00:00
|
|
|
|
|
|
|
private void handleJavascriptDispatch(final JavaScriptInvoke instruction) {
|
|
|
|
int receiverVn = instruction.getUse(1);
|
|
|
|
PointerKey receiverKey = getPointerKeyForLocal(receiverVn);
|
|
|
|
if (contentsAreInvariant(symbolTable, du, receiverVn)) {
|
|
|
|
system.recordImplicitPointsToSet(receiverKey);
|
|
|
|
InstanceKey[] ik = getInvariantContents(receiverVn);
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey element : ik) {
|
|
|
|
handleJavascriptDispatch(instruction, element);
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
class ReceiverForDispatchOp extends UnaryOperator<PointsToSetVariable> {
|
2016-09-16 01:32:35 +00:00
|
|
|
MutableIntSet previous = IntSetUtil.make();
|
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
private JavaScriptInvoke getInstruction() {
|
|
|
|
return instruction;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
|
|
|
if (rhs.getValue() != null) {
|
2017-11-23 01:28:36 +00:00
|
|
|
rhs.getValue().foreachExcluding(previous, x -> {
|
|
|
|
try {
|
|
|
|
MonitorUtil.throwExceptionIfCanceled(getBuilder().monitor);
|
|
|
|
} catch (CancelException e) {
|
|
|
|
throw new CancelRuntimeException(e);
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
2017-11-23 01:28:36 +00:00
|
|
|
InstanceKey ik = system.getInstanceKey(x);
|
|
|
|
handleJavascriptDispatch(instruction, ik);
|
2012-03-01 02:45:51 +00:00
|
|
|
});
|
2016-09-16 01:32:35 +00:00
|
|
|
previous.addAll(rhs.getValue());
|
2012-03-01 02:45:51 +00:00
|
|
|
}
|
|
|
|
return NOT_CHANGED;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return instruction.hashCode();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
return o instanceof ReceiverForDispatchOp && ((ReceiverForDispatchOp)o).getInstruction()==getInstruction();
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "receiver for dispatch: " + instruction;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
system.newSideEffect(new ReceiverForDispatchOp(), receiverKey);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// string manipulation handling for binary operators
|
|
|
|
//
|
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private void handleBinaryOp(final SSABinaryOpInstruction instruction, final CGNode node, final SymbolTable symbolTable,
|
|
|
|
final DefUse du) {
|
|
|
|
int lval = instruction.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
|
|
|
final PointsToSetVariable lv = system.findOrCreatePointsToSet(lk);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
final int arg1 = instruction.getUse(0);
|
|
|
|
final int arg2 = instruction.getUse(1);
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-12-04 21:40:38 +00:00
|
|
|
class BinaryOperator extends AbstractOperator<PointsToSetVariable> {
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private CGNode getNode() {
|
|
|
|
return node;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2015-07-25 02:44:10 +00:00
|
|
|
private SSAAbstractBinaryInstruction getInstruction() {
|
2007-07-06 22:09:08 +00:00
|
|
|
return instruction;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-06 22:09:08 +00:00
|
|
|
public String toString() {
|
|
|
|
return "BinOp: " + getInstruction();
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-06 22:09:08 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return 17 * getInstruction().getUse(0) * getInstruction().getUse(1);
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2007-07-06 22:09:08 +00:00
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (o instanceof BinaryOperator) {
|
|
|
|
BinaryOperator op = (BinaryOperator) o;
|
|
|
|
return op.getNode().equals(getNode()) && op.getInstruction().getUse(0) == getInstruction().getUse(0)
|
|
|
|
&& op.getInstruction().getUse(1) == getInstruction().getUse(1)
|
|
|
|
&& op.getInstruction().getDef(0) == getInstruction().getDef(0);
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private InstanceKey[] getInstancesArray(int vn) {
|
|
|
|
if (contentsAreInvariant(symbolTable, du, vn)) {
|
|
|
|
return getInvariantContents(vn);
|
|
|
|
} else {
|
|
|
|
PointsToSetVariable v = system.findOrCreatePointsToSet(getPointerKeyForLocal(vn));
|
|
|
|
if (v.getValue() == null || v.size() == 0) {
|
|
|
|
return new InstanceKey[0];
|
|
|
|
} else {
|
2007-07-11 21:08:21 +00:00
|
|
|
final Set<InstanceKey> temp = HashSetFactory.make();
|
2017-11-23 01:28:36 +00:00
|
|
|
v.getValue().foreach(keyIndex -> temp.add(system.getInstanceKey(keyIndex)));
|
2007-07-06 22:09:08 +00:00
|
|
|
|
|
|
|
return temp.toArray(new InstanceKey[temp.size()]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean isStringConstant(InstanceKey k) {
|
|
|
|
return (k instanceof ConstantKey) && k.getConcreteType().getReference().equals(JavaScriptTypes.String);
|
|
|
|
}
|
|
|
|
|
|
|
|
private boolean addKey(InstanceKey k) {
|
|
|
|
int n = system.findOrCreateIndexForInstanceKey(k);
|
|
|
|
if (!lv.contains(n)) {
|
|
|
|
lv.add(n);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2011-04-27 13:58:56 +00:00
|
|
|
public byte evaluate(PointsToSetVariable lhs, final PointsToSetVariable[] rhs) {
|
2007-07-06 22:09:08 +00:00
|
|
|
boolean doDefault = false;
|
|
|
|
byte changed = NOT_CHANGED;
|
|
|
|
|
|
|
|
InstanceKey[] iks1 = getInstancesArray(arg1);
|
|
|
|
InstanceKey[] iks2 = getInstancesArray(arg2);
|
|
|
|
|
|
|
|
if ((instruction.getOperator() == BinaryOpInstruction.Operator.ADD) && (getOptions().getTraceStringConstants())) {
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey element : iks1) {
|
|
|
|
if (isStringConstant(element)) {
|
|
|
|
for (InstanceKey element2 : iks2) {
|
|
|
|
if (isStringConstant(element2)) {
|
2013-04-09 22:47:22 +00:00
|
|
|
try {
|
|
|
|
MonitorUtil.throwExceptionIfCanceled(builder.monitor);
|
|
|
|
} catch (CancelException e) {
|
|
|
|
throw new CancelRuntimeException(e);
|
|
|
|
}
|
2017-11-28 20:26:09 +00:00
|
|
|
String v1 = (String) ((ConstantKey<?>) element).getValue();
|
|
|
|
String v2 = (String) ((ConstantKey<?>) element2).getValue();
|
2007-07-06 22:09:08 +00:00
|
|
|
if (v1.indexOf(v2) == -1 && v2.indexOf(v1) == -1) {
|
|
|
|
InstanceKey lvalKey = getInstanceKeyForConstant(v1 + v2);
|
|
|
|
if (addKey(lvalKey)) {
|
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
doDefault = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
doDefault = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
doDefault = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
doDefault = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (doDefault) {
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey element : iks1) {
|
|
|
|
for (InstanceKey element2 : iks2) {
|
2013-04-09 22:47:22 +00:00
|
|
|
try {
|
|
|
|
MonitorUtil.throwExceptionIfCanceled(builder.monitor);
|
|
|
|
} catch (CancelException e) {
|
|
|
|
throw new CancelRuntimeException(e);
|
|
|
|
}
|
2017-11-28 20:26:09 +00:00
|
|
|
if (handleBinaryOperatorArgs(element, element2)) {
|
2012-03-08 17:35:04 +00:00
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
}
|
|
|
|
}
|
2012-03-08 17:35:04 +00:00
|
|
|
|
2016-09-16 01:32:35 +00:00
|
|
|
if (iks1 == null || iks1.length == 0 || iks2 == null || iks2.length == 0) {
|
|
|
|
if (iks1 != null) {
|
|
|
|
for(InstanceKey ik : iks1) {
|
|
|
|
if (addKey(ik)) {
|
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (iks2 != null) {
|
|
|
|
for(InstanceKey ik : iks2) {
|
|
|
|
if (addKey(ik)) {
|
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
System.err.println(instruction);
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
return changed;
|
|
|
|
}
|
2012-03-08 17:35:04 +00:00
|
|
|
|
|
|
|
private boolean isNumberType(Language l, TypeReference t) {
|
|
|
|
return l.isDoubleType(t)||l.isFloatType(t)||l.isIntType(t)||l.isLongType(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected boolean handleBinaryOperatorArgs(InstanceKey left, InstanceKey right) {
|
|
|
|
Language l = node.getMethod().getDeclaringClass().getClassLoader().getLanguage();
|
|
|
|
if (l.isStringType(left.getConcreteType().getReference()) || l.isStringType(right.getConcreteType().getReference())) {
|
|
|
|
return addKey(new ConcreteTypeKey(node.getClassHierarchy().lookupClass(l.getStringType())));
|
|
|
|
} else if (isNumberType(l, left.getConcreteType().getReference()) && isNumberType(l, right.getConcreteType().getReference())) {
|
2013-01-08 01:18:27 +00:00
|
|
|
if (left instanceof ConstantKey && right instanceof ConstantKey) {
|
|
|
|
return addKey(new ConcreteTypeKey(node.getClassHierarchy().lookupClass(JavaScriptTypes.Number)));
|
|
|
|
} else {
|
|
|
|
return addKey(left) || addKey(right);
|
|
|
|
}
|
2012-03-08 17:35:04 +00:00
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
|
|
|
BinaryOperator B = new BinaryOperator();
|
|
|
|
if (contentsAreInvariant(symbolTable, du, arg1)) {
|
|
|
|
if (contentsAreInvariant(symbolTable, du, arg2)) {
|
|
|
|
B.evaluate(null, null);
|
|
|
|
} else {
|
|
|
|
system.newConstraint(lk, B, getPointerKeyForLocal(arg2));
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
} else {
|
2007-07-06 22:09:08 +00:00
|
|
|
PointerKey k1 = getPointerKeyForLocal(arg1);
|
|
|
|
if (contentsAreInvariant(symbolTable, du, arg2)) {
|
|
|
|
system.newConstraint(lk, B, k1);
|
|
|
|
} else {
|
|
|
|
system.newConstraint(lk, B, k1, getPointerKeyForLocal(arg2));
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-27 17:40:11 +00:00
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitCheckRef(JavaScriptCheckReference instruction) {
|
|
|
|
// TODO Auto-generated method stub
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
|
|
|
|
2013-06-25 15:57:37 +00:00
|
|
|
@Override
|
2009-01-27 17:40:11 +00:00
|
|
|
public void visitWithRegion(JavaScriptWithRegion instruction) {
|
|
|
|
// TODO Auto-generated method stub
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2009-01-27 17:40:11 +00:00
|
|
|
}
|
2012-03-01 02:45:51 +00:00
|
|
|
|
|
|
|
private final UnaryOperator<PointsToSetVariable> transitivePrototypeOp = new UnaryOperator<PointsToSetVariable>() {
|
|
|
|
@Override
|
|
|
|
public byte evaluate(final PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
|
|
|
class Op implements IntSetAction {
|
|
|
|
private boolean changed = false;
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void act(int x) {
|
|
|
|
InstanceKey protoObj = system.getInstanceKey(x);
|
|
|
|
PointerKey protoObjKey = new TransitivePrototypeKey(protoObj);
|
|
|
|
changed |= system.newStatement(lhs, assignOperator, system.findOrCreatePointsToSet(protoObjKey), true, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rhs.getValue() != null) {
|
|
|
|
Op op = new Op();
|
|
|
|
rhs.getValue().foreach(op);
|
|
|
|
return (op.changed? CHANGED: NOT_CHANGED);
|
|
|
|
}
|
|
|
|
return NOT_CHANGED;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
|
|
|
return -896435647;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
return o == this;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "transitivePrototypeOp";
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
2014-08-07 20:02:48 +00:00
|
|
|
|
2012-03-01 02:45:51 +00:00
|
|
|
@Override
|
|
|
|
public void visitSetPrototype(SetPrototype instruction) {
|
|
|
|
visitPutInternal(instruction.getUse(1), instruction.getUse(0), false, prototypeRef);
|
|
|
|
|
|
|
|
assert contentsAreInvariant(symbolTable, du, instruction.getUse(0));
|
|
|
|
if (contentsAreInvariant(symbolTable, du, instruction.getUse(1))) {
|
|
|
|
for(InstanceKey newObj : getInvariantContents(instruction.getUse(0))) {
|
|
|
|
PointerKey newObjKey = new TransitivePrototypeKey(newObj);
|
|
|
|
for(InstanceKey protoObj : getInvariantContents(instruction.getUse(1))) {
|
|
|
|
system.newConstraint(newObjKey, protoObj);
|
|
|
|
system.newConstraint(newObjKey, assignOperator, new TransitivePrototypeKey(protoObj));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(InstanceKey newObj : getInvariantContents(instruction.getUse(0))) {
|
|
|
|
PointerKey newObjKey = new TransitivePrototypeKey(newObj);
|
|
|
|
system.newConstraint(newObjKey, assignOperator, getPointerKeyForLocal(instruction.getUse(1)));
|
|
|
|
system.newConstraint(newObjKey, transitivePrototypeOp, getPointerKeyForLocal(instruction.getUse(1)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitPrototypeLookup(PrototypeLookup instruction) {
|
|
|
|
if (contentsAreInvariant(symbolTable, du, instruction.getUse(0))) {
|
|
|
|
for(InstanceKey rhsObj : getInvariantContents(instruction.getUse(0))) {
|
|
|
|
// property can come from object itself...
|
|
|
|
system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), rhsObj);
|
|
|
|
|
|
|
|
// ...or prototype objects
|
|
|
|
system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), assignOperator, new TransitivePrototypeKey(rhsObj));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// property can come from object itself...
|
|
|
|
system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), assignOperator, getPointerKeyForLocal(instruction.getUse(0)));
|
|
|
|
|
|
|
|
// ...or prototype objects
|
|
|
|
system.newConstraint(getPointerKeyForLocal(instruction.getDef(0)), transitivePrototypeOp, getPointerKeyForLocal(instruction.getUse(0)));
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2011-07-01 16:48:18 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2011-04-27 13:58:56 +00:00
|
|
|
//
|
|
|
|
// function call handling
|
|
|
|
//
|
2011-07-01 16:48:18 +00:00
|
|
|
// //////////////////////////////////////////////////////////////////////////
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2011-04-27 13:58:56 +00:00
|
|
|
@Override
|
|
|
|
protected void processCallingConstraints(CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
|
|
|
|
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
|
2015-04-06 01:19:56 +00:00
|
|
|
processCallingConstraintsInternal(this, caller, instruction, target, constParams, uniqueCatchKey);
|
|
|
|
}
|
2011-05-04 21:06:35 +00:00
|
|
|
|
2017-03-18 02:47:10 +00:00
|
|
|
@SuppressWarnings("unused")
|
2015-04-06 01:19:56 +00:00
|
|
|
public static void processCallingConstraintsInternal(AstSSAPropagationCallGraphBuilder builder, CGNode caller, SSAAbstractInvokeInstruction instruction, CGNode target,
|
|
|
|
InstanceKey[][] constParams, PointerKey uniqueCatchKey) {
|
2017-02-03 01:33:27 +00:00
|
|
|
|
2017-03-11 18:22:45 +00:00
|
|
|
IRView sourceIR = builder.getCFAContextInterpreter().getIRView(caller);
|
2011-04-27 13:58:56 +00:00
|
|
|
SymbolTable sourceST = sourceIR.getSymbolTable();
|
2011-07-01 16:48:18 +00:00
|
|
|
|
2017-03-11 18:22:45 +00:00
|
|
|
IRView targetIR = builder.getCFAContextInterpreter().getIRView(target);
|
2011-04-27 13:58:56 +00:00
|
|
|
SymbolTable targetST = targetIR.getSymbolTable();
|
|
|
|
|
|
|
|
JSConstraintVisitor targetVisitor = null;
|
|
|
|
int av = -1;
|
|
|
|
for (int v = 0; v <= targetST.getMaxValueNumber(); v++) {
|
|
|
|
String[] vns = targetIR.getLocalNames(1, v);
|
|
|
|
for (int n = 0; vns != null && n < vns.length; n++) {
|
|
|
|
if ("arguments".equals(vns[n])) {
|
|
|
|
av = v;
|
2015-04-06 01:19:56 +00:00
|
|
|
targetVisitor = (JSConstraintVisitor) builder.makeVisitor(target);
|
2011-04-27 13:58:56 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int paramCount = targetST.getParameterValueNumbers().length;
|
|
|
|
int argCount = instruction.getNumberOfParameters();
|
2012-01-06 21:24:53 +00:00
|
|
|
|
2012-02-17 20:18:32 +00:00
|
|
|
// the first two arguments are the function object and the receiver, neither of which
|
|
|
|
// should become part of the arguments array
|
|
|
|
int num_pseudoargs = 2;
|
2011-04-27 13:58:56 +00:00
|
|
|
|
|
|
|
// pass actual arguments to formals in the normal way
|
|
|
|
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey[] fn = new InstanceKey[] { builder.getInstanceKeyForConstant(JavaScriptTypes.String, ""+(i-num_pseudoargs)) };
|
|
|
|
PointerKey F = builder.getTargetPointerKey(target, i);
|
2011-04-27 13:58:56 +00:00
|
|
|
|
|
|
|
if (constParams != null && constParams[i] != null) {
|
|
|
|
for (int j = 0; j < constParams[i].length; j++) {
|
2015-04-06 01:19:56 +00:00
|
|
|
builder.getSystem().newConstraint(F, constParams[i][j]);
|
2011-04-27 13:58:56 +00:00
|
|
|
}
|
|
|
|
|
2012-02-17 20:18:32 +00:00
|
|
|
if (av != -1 && i >= num_pseudoargs) {
|
2011-04-27 13:58:56 +00:00
|
|
|
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
|
2012-01-27 20:15:33 +00:00
|
|
|
}
|
|
|
|
|
2011-04-27 13:58:56 +00:00
|
|
|
} else {
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey A = builder.getPointerKeyForLocal(caller, instruction.getUse(i));
|
|
|
|
builder.getSystem().newConstraint(F, (F instanceof FilteredPointerKey) ? builder.filterOperator : assignOperator, A);
|
2011-04-27 13:58:56 +00:00
|
|
|
|
2012-02-17 20:18:32 +00:00
|
|
|
if (av != -1 && i >= num_pseudoargs) {
|
2011-04-27 13:58:56 +00:00
|
|
|
targetVisitor.newFieldWrite(target, av, fn, F);
|
2012-01-27 20:15:33 +00:00
|
|
|
}
|
2011-04-27 13:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra actual arguments get assigned into the ``arguments'' object
|
|
|
|
if (paramCount < argCount) {
|
|
|
|
if (av != -1) {
|
|
|
|
for (int i = paramCount; i < argCount; i++) {
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey[] fn = new InstanceKey[] { builder.getInstanceKeyForConstant(JavaScriptTypes.String, ""+(i-num_pseudoargs)) };
|
2012-02-17 20:18:32 +00:00
|
|
|
if (constParams != null && constParams[i] != null && i >= num_pseudoargs) {
|
2012-01-06 21:24:53 +00:00
|
|
|
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
|
2012-02-17 20:18:32 +00:00
|
|
|
} else if(i >= num_pseudoargs) {
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey A = builder.getPointerKeyForLocal(caller, instruction.getUse(i));
|
2011-04-27 13:58:56 +00:00
|
|
|
targetVisitor.newFieldWrite(target, av, fn, A);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra formal parameters get null (extra args are ignored here)
|
|
|
|
else if (argCount < paramCount) {
|
|
|
|
int nullvn = sourceST.getNullConstant();
|
2015-04-06 01:19:56 +00:00
|
|
|
DefUse sourceDU = builder.getCFAContextInterpreter().getDU(caller);
|
|
|
|
InstanceKey[] nullkeys = builder.getInvariantContents(sourceST, sourceDU, caller, nullvn, builder);
|
2011-04-27 13:58:56 +00:00
|
|
|
for (int i = argCount; i < paramCount; i++) {
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey F = builder.getPointerKeyForLocal(target, targetST.getParameter(i));
|
2017-11-28 20:26:09 +00:00
|
|
|
for (InstanceKey nullkey : nullkeys) {
|
|
|
|
builder.getSystem().newConstraint(F, nullkey);
|
2011-04-27 13:58:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// write `length' in argument objects
|
|
|
|
if (av != -1) {
|
2015-04-06 01:19:56 +00:00
|
|
|
InstanceKey[] svn = new InstanceKey[] { builder.getInstanceKeyForConstant(JavaScriptTypes.Number, argCount-1) };
|
|
|
|
InstanceKey[] lnv = new InstanceKey[] { builder.getInstanceKeyForConstant(JavaScriptTypes.String, "length") };
|
2011-04-27 13:58:56 +00:00
|
|
|
targetVisitor.newFieldWrite(target, av, lnv, svn);
|
|
|
|
}
|
|
|
|
|
|
|
|
// return values
|
|
|
|
if (instruction.getDef(0) != -1) {
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey RF = builder.getPointerKeyForReturnValue(target);
|
|
|
|
PointerKey RA = builder.getPointerKeyForLocal(caller, instruction.getDef(0));
|
|
|
|
builder.getSystem().newConstraint(RA, assignOperator, RF);
|
2011-04-27 13:58:56 +00:00
|
|
|
}
|
|
|
|
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey EF = builder.getPointerKeyForExceptionalReturnValue(target);
|
2011-04-27 13:58:56 +00:00
|
|
|
if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) {
|
|
|
|
// e has exactly one use. so, represent e implicitly
|
2015-04-06 01:19:56 +00:00
|
|
|
builder.getSystem().newConstraint(uniqueCatchKey, assignOperator, EF);
|
2011-04-27 13:58:56 +00:00
|
|
|
} else {
|
2015-04-06 01:19:56 +00:00
|
|
|
PointerKey EA = builder.getPointerKeyForLocal(caller, instruction.getDef(1));
|
|
|
|
builder.getSystem().newConstraint(EA, assignOperator, EF);
|
2013-04-30 03:34:40 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected boolean sameMethod(CGNode opNode, String definingMethod) {
|
|
|
|
return definingMethod.equals(opNode.getMethod().getReference().getDeclaringClass().getName().toString());
|
2011-04-27 13:58:56 +00:00
|
|
|
}
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|