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;
|
|
|
|
|
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;
|
|
|
|
import com.ibm.wala.cast.ir.ssa.AstIsDefinedInstruction;
|
|
|
|
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;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.InstructionVisitor;
|
|
|
|
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;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptTypes;
|
|
|
|
import com.ibm.wala.classLoader.IClass;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.fixedpoint.impl.AbstractOperator;
|
|
|
|
import com.ibm.wala.fixedpoint.impl.UnaryOperator;
|
|
|
|
import com.ibm.wala.fixpoint.IVariable;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.fixpoint.IntSetVariable;
|
2007-07-20 15:20:23 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
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;
|
2007-02-02 17:25:09 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.impl.ExplicitCallGraph;
|
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;
|
|
|
|
import com.ibm.wala.shrikeBT.UnaryOpInstruction;
|
|
|
|
import com.ibm.wala.ssa.DefUse;
|
|
|
|
import com.ibm.wala.ssa.IR;
|
|
|
|
import com.ibm.wala.ssa.SSABinaryOpInstruction;
|
|
|
|
import com.ibm.wala.ssa.SSAUnaryOpInstruction;
|
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
2007-07-11 21:08:21 +00:00
|
|
|
import com.ibm.wala.util.collections.HashSetFactory;
|
2007-07-06 22:09:08 +00:00
|
|
|
import com.ibm.wala.util.debug.Trace;
|
|
|
|
import com.ibm.wala.util.intset.IntSetAction;
|
|
|
|
import com.ibm.wala.util.intset.IntSetUtil;
|
|
|
|
import com.ibm.wala.util.intset.MutableIntSet;
|
|
|
|
import com.ibm.wala.util.intset.MutableMapping;
|
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;
|
|
|
|
|
2007-12-04 21:40:38 +00:00
|
|
|
protected JSSSAPropagationCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache,
|
|
|
|
PointerKeyFactory pointerKeyFactory) {
|
2007-07-20 15:20:23 +00:00
|
|
|
super(cha, options, cache, pointerKeyFactory);
|
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
|
|
|
|
|
|
|
protected boolean useObjectCatalog() {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
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) {
|
|
|
|
Trace.println("IR of " + ir.getMethod());
|
2007-07-06 22:09:08 +00:00
|
|
|
Trace.println(ir);
|
2007-02-02 17:25:09 +00:00
|
|
|
Trace.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)) {
|
|
|
|
Trace.println(" value " + i + " is undefined");
|
|
|
|
} else {
|
|
|
|
Trace.println(" value " + i + " has type " + ti.getType(i));
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ti;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void addAssignmentsForCatchPointerKey(PointerKey exceptionVar, Set catchClasses, PointerKey e) {
|
|
|
|
system.newConstraint(exceptionVar, assignOperator, e);
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public static class JSInterestingVisitor extends AstInterestingVisitor implements com.ibm.wala.cast.js.ssa.InstructionVisitor {
|
2007-06-01 03:32:56 +00:00
|
|
|
public JSInterestingVisitor(int vn) {
|
2007-02-02 17:25:09 +00:00
|
|
|
super(vn);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitBinaryOp(final SSABinaryOpInstruction instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-02-02 17:25:09 +00:00
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction inst) {
|
|
|
|
bingo = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
public static class JSPointerAnalysisImpl extends 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
|
|
|
|
com.ibm.wala.cast.js.ssa.InstructionVisitor {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
|
|
|
|
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
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
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
protected PropagationSystem makeSystem(AnalysisOptions options) {
|
2007-07-06 22:09:08 +00:00
|
|
|
return new PropagationSystem(callGraph, pointerKeyFactory, instanceKeyFactory, options.getSupportRefinement()) {
|
|
|
|
public PointerAnalysis makePointerAnalysis(PropagationCallGraphBuilder builder) {
|
|
|
|
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
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
protected ConstraintVisitor makeVisitor(ExplicitCallGraph.ExplicitNode node) {
|
2007-06-01 03:32:56 +00:00
|
|
|
return new JSConstraintVisitor(this, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static class JSConstraintVisitor extends AstConstraintVisitor implements InstructionVisitor {
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public JSConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, ExplicitCallGraph.ExplicitNode node) {
|
2007-06-01 03:32:56 +00:00
|
|
|
super(builder, node);
|
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitUnaryOp(SSAUnaryOpInstruction inst) {
|
|
|
|
if (inst.getOpcode() == UnaryOpInstruction.Operator.NEG) {
|
2007-07-06 22:09:08 +00:00
|
|
|
int lval = inst.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
|
|
|
|
|
|
|
IClass bool = getClassHierarchy().lookupClass(JavaScriptTypes.Boolean);
|
|
|
|
InstanceKey key = new ConcreteTypeKey(bool);
|
2007-06-01 03:32:56 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
system.newConstraint(lk, key);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitIsDefined(AstIsDefinedInstruction inst) {
|
|
|
|
int lval = inst.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
IClass bool = getClassHierarchy().lookupClass(JavaScriptTypes.Boolean);
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitEachElementHasNext(EachElementHasNextInstruction inst) {
|
|
|
|
int lval = inst.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
IClass bool = getClassHierarchy().lookupClass(JavaScriptTypes.Boolean);
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void visitTypeOf(JavaScriptTypeOfInstruction instruction) {
|
|
|
|
int lval = instruction.getDef(0);
|
|
|
|
PointerKey lk = getPointerKeyForLocal(lval);
|
2007-07-06 22:09:08 +00:00
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
IClass string = getClassHierarchy().lookupClass(JavaScriptTypes.String);
|
2007-07-06 22:09:08 +00:00
|
|
|
InstanceKey key = new ConcreteTypeKey(string);
|
2007-06-01 03:32:56 +00:00
|
|
|
|
|
|
|
system.newConstraint(lk, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitJavaScriptPropertyRead(JavaScriptPropertyRead instruction) {
|
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
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
public void visitJavaScriptPropertyWrite(JavaScriptPropertyWrite instruction) {
|
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
|
|
|
}
|
|
|
|
|
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke instruction) {
|
|
|
|
PointerKey F = getPointerKeyForLocal(instruction.getFunction());
|
|
|
|
|
|
|
|
InstanceKey[][] consts = computeInvariantParameters(instruction);
|
|
|
|
|
|
|
|
PointerKey uniqueCatch = null;
|
|
|
|
if (hasUniqueCatchBlock(instruction, ir)) {
|
|
|
|
uniqueCatch = getBuilder().getUniqueCatchKey(instruction, ir, node);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (contentsAreInvariant(symbolTable, du, instruction.getFunction())) {
|
2007-07-06 22:09:08 +00:00
|
|
|
system.recordImplicitPointsToSet(F);
|
|
|
|
InstanceKey[] ik = getInvariantContents(instruction.getFunction());
|
|
|
|
for (int i = 0; i < ik.length; i++) {
|
2007-06-01 03:32:56 +00:00
|
|
|
system.findOrCreateIndexForInstanceKey(ik[i]);
|
2007-07-06 22:09:08 +00:00
|
|
|
CGNode n = getTargetForCall(node, instruction.getCallSite(), ik[i]);
|
|
|
|
if (n != null) {
|
|
|
|
processJSCall(node, instruction, n, ik[i], consts, uniqueCatch);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
}
|
2007-06-01 03:32:56 +00:00
|
|
|
} else {
|
2007-07-06 22:09:08 +00:00
|
|
|
system.newSideEffect(new JSDispatchOperator(instruction, node, consts, uniqueCatch), F);
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// function call handling
|
|
|
|
//
|
|
|
|
// ///////////////////////////////////////////////////////////////////////////
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-12-04 21:40:38 +00:00
|
|
|
class JSDispatchOperator extends UnaryOperator<PointsToSetVariable> {
|
2007-07-06 22:09:08 +00:00
|
|
|
private final JavaScriptInvoke call;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private final ExplicitCallGraph.ExplicitNode node;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private final InstanceKey[][] constParams;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private final PointerKey uniqueCatch;
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public boolean isLoadOperator() {
|
|
|
|
return false;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public String toString() {
|
|
|
|
return "JSDispatch of " + call.getCallSite();
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return call.getCallSite().hashCode() * node.hashCode();
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public boolean equals(Object o) {
|
|
|
|
return (o instanceof JSDispatchOperator) && ((JSDispatchOperator) o).node.equals(node)
|
|
|
|
&& ((JSDispatchOperator) o).call.equals(call);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param call
|
|
|
|
* @param node
|
|
|
|
*/
|
|
|
|
JSDispatchOperator(JavaScriptInvoke call, ExplicitCallGraph.ExplicitNode node, InstanceKey[][] constParams,
|
|
|
|
PointerKey uniqueCatch) {
|
|
|
|
this.call = call;
|
|
|
|
this.node = node;
|
|
|
|
this.constParams = constParams;
|
|
|
|
this.uniqueCatch = uniqueCatch;
|
|
|
|
}
|
|
|
|
|
|
|
|
private MutableIntSet previousReceivers = IntSetUtil.getDefaultIntSetFactory().make();
|
|
|
|
|
2007-12-04 21:40:38 +00:00
|
|
|
public byte evaluate(PointsToSetVariable lhs, PointsToSetVariable rhs) {
|
2007-07-06 22:09:08 +00:00
|
|
|
final IntSetVariable receivers = (IntSetVariable) rhs;
|
|
|
|
if (receivers.getValue() != null) {
|
|
|
|
receivers.getValue().foreachExcluding(previousReceivers, new IntSetAction() {
|
|
|
|
public void act(int ptr) {
|
|
|
|
InstanceKey iKey = system.getInstanceKey(ptr);
|
2008-01-04 21:18:25 +00:00
|
|
|
CGNode target = getTargetForCall(node, call.getCallSite(), iKey);
|
2007-07-06 22:09:08 +00:00
|
|
|
if (target != null) {
|
|
|
|
processJSCall(node, call, target, iKey, constParams, uniqueCatch);
|
|
|
|
if (!getBuilder().haveAlreadyVisited(target)) {
|
|
|
|
getBuilder().markDiscovered(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
previousReceivers.addAll(receivers.getValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
return NOT_CHANGED;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2007-07-11 18:43:55 +00:00
|
|
|
@SuppressWarnings("deprecation")
|
2007-07-06 22:09:08 +00:00
|
|
|
void processJSCall(CGNode caller, JavaScriptInvoke instruction, CGNode target, InstanceKey function,
|
|
|
|
InstanceKey constParams[][], PointerKey uniqueCatchKey) {
|
|
|
|
caller.addTarget(instruction.getCallSite(), target);
|
|
|
|
if (!getBuilder().haveAlreadyVisited(target)) {
|
|
|
|
getBuilder().markDiscovered(target);
|
|
|
|
}
|
|
|
|
|
|
|
|
IR sourceIR = getBuilder().getCFAContextInterpreter().getIR(caller);
|
|
|
|
SymbolTable sourceST = sourceIR.getSymbolTable();
|
|
|
|
|
|
|
|
IR targetIR = getBuilder().getCFAContextInterpreter().getIR(target);
|
|
|
|
SymbolTable targetST = targetIR.getSymbolTable();
|
|
|
|
|
|
|
|
int av = -1;
|
2007-08-22 15:33:55 +00:00
|
|
|
for (int v = 0; v <= targetST.getMaxValueNumber(); v++) {
|
2007-07-06 22:09:08 +00:00
|
|
|
String[] vns = targetIR.getLocalNames(1, v);
|
|
|
|
for (int n = 0; vns != null && n < vns.length; n++) {
|
|
|
|
if ("arguments".equals(vns[n])) {
|
|
|
|
av = v;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
int paramCount = targetST.getParameterValueNumbers().length;
|
|
|
|
int argCount = instruction.getNumberOfParameters();
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// pass actual arguments to formals in the normal way
|
|
|
|
for (int i = 0; i < Math.min(paramCount, argCount); i++) {
|
|
|
|
int fn = targetST.getConstant(i);
|
|
|
|
PointerKey F = (i == 0) ? getBuilder().getFilteredPointerKeyForLocal(target, targetST.getParameter(i), function)
|
|
|
|
: getBuilder().getPointerKeyForLocal(target, targetST.getParameter(i));
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
if (constParams != null && constParams[i] != null) {
|
|
|
|
for (int j = 0; j < constParams[i].length; j++) {
|
|
|
|
system.newConstraint(F, constParams[i][j]);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (av != -1)
|
|
|
|
newFieldWrite(target, av, fn, constParams[i]);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
PointerKey A = getBuilder().getPointerKeyForLocal(caller, instruction.getUse(i));
|
2007-12-04 21:40:38 +00:00
|
|
|
system.newConstraint(F, (F instanceof FilteredPointerKey) ? getBuilder().filterOperator : assignOperator, A);
|
2007-07-06 22:09:08 +00:00
|
|
|
|
|
|
|
if (av != -1)
|
|
|
|
newFieldWrite(target, av, fn, F);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra actual arguments get assigned into the ``arguments'' object
|
|
|
|
if (paramCount < argCount) {
|
|
|
|
if (av != -1) {
|
|
|
|
for (int i = paramCount; i < argCount; i++) {
|
|
|
|
int fn = targetST.getConstant(i);
|
|
|
|
if (constParams != null && constParams[i] != null) {
|
|
|
|
newFieldWrite(target, av, fn, constParams[i]);
|
|
|
|
} else {
|
|
|
|
PointerKey A = getBuilder().getPointerKeyForLocal(caller, instruction.getUse(i));
|
|
|
|
newFieldWrite(target, av, fn, A);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// extra formal parameters get null (extra args are ignored here)
|
|
|
|
else if (argCount < paramCount) {
|
|
|
|
int nullvn = sourceST.getNullConstant();
|
|
|
|
DefUse sourceDU = getBuilder().getCFAContextInterpreter().getDU(caller);
|
|
|
|
InstanceKey[] nullkeys = getInvariantContents(sourceST, sourceDU, caller, nullvn);
|
|
|
|
for (int i = argCount; i < paramCount; i++) {
|
|
|
|
PointerKey F = getBuilder().getPointerKeyForLocal(target, targetST.getParameter(i));
|
|
|
|
for (int k = 0; k < nullkeys.length; k++) {
|
|
|
|
system.newConstraint(F, nullkeys[k]);
|
|
|
|
}
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
2007-07-06 22:09:08 +00:00
|
|
|
|
|
|
|
// write `length' in argument objects
|
2007-02-02 17:25:09 +00:00
|
|
|
if (av != -1) {
|
2007-07-06 22:09:08 +00:00
|
|
|
int svn = targetST.getConstant(argCount);
|
|
|
|
int lnv = targetST.getConstant("length");
|
|
|
|
newFieldWrite(target, av, lnv, svn);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
// return values
|
|
|
|
if (instruction.getDef(0) != -1) {
|
|
|
|
PointerKey RF = getBuilder().getPointerKeyForReturnValue(target);
|
|
|
|
PointerKey RA = getBuilder().getPointerKeyForLocal(caller, instruction.getDef(0));
|
|
|
|
system.newConstraint(RA, assignOperator, RF);
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
PointerKey EF = getBuilder().getPointerKeyForExceptionalReturnValue(target);
|
|
|
|
if (SHORT_CIRCUIT_SINGLE_USES && uniqueCatchKey != null) {
|
|
|
|
// e has exactly one use. so, represent e implicitly
|
|
|
|
system.newConstraint(uniqueCatchKey, assignOperator, EF);
|
|
|
|
} else {
|
|
|
|
PointerKey EA = getBuilder().getPointerKeyForLocal(caller, instruction.getDef(1));
|
|
|
|
system.newConstraint(EA, assignOperator, EF);
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
private SSABinaryOpInstruction getInstruction() {
|
|
|
|
return instruction;
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public String toString() {
|
|
|
|
return "BinOp: " + getInstruction();
|
|
|
|
}
|
2007-02-02 17:25:09 +00:00
|
|
|
|
2007-07-06 22:09:08 +00:00
|
|
|
public int hashCode() {
|
|
|
|
return 17 * getInstruction().getUse(0) * getInstruction().getUse(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
2007-07-06 22:09:08 +00:00
|
|
|
v.getValue().foreach(new IntSetAction() {
|
|
|
|
public void act(int keyIndex) {
|
|
|
|
temp.add(system.getInstanceKey(keyIndex));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-12-04 21:40:38 +00:00
|
|
|
public byte evaluate(PointsToSetVariable lhs, final IVariable[] 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())) {
|
|
|
|
for (int i = 0; i < iks1.length; i++) {
|
|
|
|
if (isStringConstant(iks1[i])) {
|
|
|
|
for (int j = 0; j < iks2.length; j++) {
|
|
|
|
if (isStringConstant(iks2[j])) {
|
|
|
|
String v1 = (String) ((ConstantKey) iks1[i]).getValue();
|
|
|
|
String v2 = (String) ((ConstantKey) iks2[j]).getValue();
|
|
|
|
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) {
|
|
|
|
for (int i = 0; i < iks1.length; i++) {
|
|
|
|
if (addKey(new ConcreteTypeKey(iks1[i].getConcreteType()))) {
|
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < iks2.length; i++) {
|
|
|
|
if (addKey(new ConcreteTypeKey(iks2[i].getConcreteType()))) {
|
|
|
|
changed = CHANGED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-01 03:32:56 +00:00
|
|
|
}
|