blunt force trauma to CAst frond end:

1) Structural changes in the AstTranslator to allow retranslation and generation of custom IR.  This is mostly moving state from the translator itself into the context.
2) Some refactoring to share some AST generation code across the Java and JavaScript front ends.
3) Switching to the latest Rhino, release 1.7R3; this is a pervasive change to the JavaScript Rhino translator, since it involves switching to the new AST interface in Rhino.
4) Common code to, as an option, translate Do-style loops by replicating the loop body.  This allows the use of CAstNode.LOOP forms for such loops.
5) Some bug fixes to the mechanisms of the CAstRewriter to handle weird control flow cases.
6) An example of retranslation to specialize JavaScript methods based on how many arguments they receive at call sites.


git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4425 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
dolby-oss 2012-01-27 20:15:33 +00:00
parent 5a3470a674
commit 4c6d062dbb
60 changed files with 4863 additions and 1282 deletions

View File

@ -128,10 +128,11 @@ import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.WhileStatement;
import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.DoLoopTranslator;
import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl;
import com.ibm.wala.cast.java.loader.Util;
import com.ibm.wala.cast.java.translator.JavaProcedureEntity;
import com.ibm.wala.cast.java.translator.TranslatorToCAst;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
@ -175,7 +176,7 @@ import com.ibm.wala.util.debug.Assertions;
// * enums (probably in simplename or something. but using resolveConstantExpressionValue() possible)
@SuppressWarnings("unchecked")
public class JDTJava2CAstTranslator implements TranslatorToCAst {
public class JDTJava2CAstTranslator {
protected final CAst fFactory = new CAstImpl();
// ///////////////////////////////////////////
@ -203,6 +204,8 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
protected ITypeBinding OutOfMemoryError;
protected DoLoopTranslator doLoopTranslator;
private String fullPath;
private CompilationUnit cu;
@ -211,20 +214,7 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
// COMPILATION UNITS & TYPES
//
public JDTJava2CAstTranslator(JavaSourceLoaderImpl sourceLoader) {
this.fSourceLoader = sourceLoader;
}
public CAstEntity translate(Object astRoot, String fullPath) {
this.cu = (CompilationUnit) astRoot;
this.fullPath = fullPath;
ast = cu.getAST();
// FIXME: we might need one AST (-> "Object" class) for all files.
fIdentityMapper = new JDTIdentityMapper(fSourceLoader.getReference(), ast);
fTypeDict = new JDTTypeDictionary(ast, fIdentityMapper);
public JDTJava2CAstTranslator(JavaSourceLoaderImpl sourceLoader, CompilationUnit astRoot, String fullPath, boolean replicateForDoLoops) {
fDivByZeroExcType = FakeExceptionTypeBinding.arithmetic;
fNullPointerExcType = FakeExceptionTypeBinding.nullPointer;
fClassCastExcType = FakeExceptionTypeBinding.classCast;
@ -232,12 +222,27 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
ExceptionInInitializerError = FakeExceptionTypeBinding.initException;
OutOfMemoryError = FakeExceptionTypeBinding.outOfMemory;
this.fSourceLoader = sourceLoader;
this.cu = astRoot;
this.fullPath = fullPath;
ast = cu.getAST();
this.doLoopTranslator = new DoLoopTranslator(replicateForDoLoops, fFactory);
// FIXME: we might need one AST (-> "Object" class) for all files.
fIdentityMapper = new JDTIdentityMapper(fSourceLoader.getReference(), ast);
fTypeDict = new JDTTypeDictionary(ast, fIdentityMapper);
fRuntimeExcType = ast.resolveWellKnownType("java.lang.RuntimeException");
assert fRuntimeExcType != null;
}
public CAstEntity translateToCAst() {
List<CAstEntity> declEntities = new ArrayList<CAstEntity>();
for (Iterator iter = cu.types().iterator(); iter.hasNext();) {
for (Iterator<CAstEntity> iter = cu.types().iterator(); iter.hasNext();) {
AbstractTypeDeclaration decl = (AbstractTypeDeclaration) iter.next();
// can be of type AnnotationTypeDeclaration, EnumDeclaration, TypeDeclaration
declEntities.add(visit(decl, new RootContext()));
@ -2095,7 +2100,6 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
// ////////////////
private CAstNode visit(LabeledStatement n, WalkContext context) {
ASTNode breakTarget = makeBreakOrContinueTarget(n, n.getLabel().getIdentifier());
// find the first non-block statement ant set-up the label map (useful for breaking many fors)
ASTNode stmt = n.getBody();
@ -2108,10 +2112,12 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
CAstNode result;
if (!(n.getBody() instanceof EmptyStatement)) {
ASTNode breakTarget = makeBreakOrContinueTarget(n, n.getLabel().getIdentifier());
CAstNode breakNode = visitNode(breakTarget, context);
WalkContext child = new BreakContext(context, n.getLabel().getIdentifier(), breakTarget);
result = makeNode(context, fFactory, n, CAstNode.BLOCK_STMT, makeNode(context, fFactory, n, CAstNode.LABEL_STMT, fFactory
.makeConstant(n.getLabel().getIdentifier()), visitNode(n.getBody(), child)), visitNode(breakTarget, context));
.makeConstant(n.getLabel().getIdentifier()), visitNode(n.getBody(), child)), breakNode);
} else {
result = makeNode(context, fFactory, n, CAstNode.LABEL_STMT, fFactory.makeConstant(n.getLabel().getIdentifier()), visitNode(n
.getBody(), context));
@ -2163,7 +2169,10 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
Statement body = n.getBody();
ASTNode breakTarget = makeBreakOrContinueTarget(n, "breakLabel" + n.getStartPosition());
CAstNode breakNode = visitNode(breakTarget, context);
ASTNode continueTarget = makeBreakOrContinueTarget(n, "continueLabel" + n.getStartPosition());
CAstNode continueNode = visitNode(continueTarget, context);
String loopLabel = (String) context.getLabelMap().get(n);
LoopContext lc = new LoopContext(context, loopLabel, breakTarget, continueTarget);
@ -2172,8 +2181,8 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
* The following loop is created sligtly differently than in jscore. It doesn't have a specific target for continue.
*/
return makeNode(context, fFactory, n, CAstNode.BLOCK_STMT, makeNode(context, fFactory, n, CAstNode.LOOP, visitNode(cond,
context), makeNode(context, fFactory, n, CAstNode.BLOCK_STMT, visitNode(body, lc), visitNode(continueTarget, context))),
visitNode(breakTarget, context));
context), makeNode(context, fFactory, n, CAstNode.BLOCK_STMT, visitNode(body, lc), continueNode)),
breakNode);
}
private CAstNode getSwitchCaseConstant(SwitchCase n, WalkContext context) {
@ -2282,22 +2291,21 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
}
private CAstNode visit(DoStatement n, WalkContext context) {
ASTNode header = ast.newEmptyStatement();
ASTNode breakTarget = makeBreakOrContinueTarget(n, "breakLabel" + n.getStartPosition());
ASTNode continueTarget = makeBreakOrContinueTarget(n, "continue" + "Label" + n.getStartPosition());
CAstNode loopGoto = makeNode(context, fFactory, n, CAstNode.IFGOTO, visitNode(n.getExpression(), context));
context.cfg().map(loopGoto, loopGoto);
context.cfg().add(loopGoto, header, Boolean.TRUE);
String loopLabel = (String) context.getLabelMap().get(n); // set by visit(LabeledStatement)
WalkContext loopContext = new LoopContext(context, loopLabel, breakTarget, continueTarget);
String token = loopLabel==null? "at_" + n.getStartPosition(): loopLabel;
ASTNode breakTarget = makeBreakOrContinueTarget(n, "breakLabel_" + token);
CAstNode breakNode = visitNode(breakTarget, context);
ASTNode continueTarget = makeBreakOrContinueTarget(n, "continueLabel_" + token);
CAstNode continueNode = visitNode(continueTarget, context);
CAstNode loopTest = visitNode(n.getExpression(), context);
return makeNode(context, fFactory, n, CAstNode.BLOCK_STMT, visitNode(header, context), makeNode(context, fFactory, n,
CAstNode.BLOCK_STMT, visitNode(n.getBody(), loopContext), continueNode), loopGoto, visitNode(breakTarget, context));
WalkContext loopContext = new LoopContext(context, loopLabel, breakTarget, continueTarget);
CAstNode loopBody = visitNode(n.getBody(), loopContext);
return doLoopTranslator.translateDoLoop(loopTest, loopBody, continueNode, breakNode, context);
}
/**
@ -2889,24 +2897,12 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
* Contains things needed by in the visit() of some nodes to process the nodes. For example, pos() contains the source position
* mapping which each node registers
*/
public static interface WalkContext {
// LEFTOUT: plenty of stuff
public CAstControlFlowRecorder cfg();
public void addScopedEntity(CAstNode newNode, CAstEntity visit);
public static interface WalkContext extends TranslatorToCAst.WalkContext<WalkContext, ASTNode> {
public Collection<Pair<ITypeBinding, Object>> getCatchTargets(ITypeBinding type);
public CAstSourcePositionRecorder pos();
public CAstNodeTypeMapRecorder getNodeTypeMap();
public Map<ASTNode, String> getLabelMap();
public ASTNode getContinueFor(String label);
public ASTNode getBreakFor(String label);
public boolean needLValue();
}
@ -2914,46 +2910,21 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
* Default context functions. When one context doesn't handle something, it the next one up does. For example, there is only one
* source pos. mapping per MethodContext, so loop contexts delegate it up.
*/
public static class DelegatingContext implements WalkContext {
protected WalkContext parent;
public static class DelegatingContext extends TranslatorToCAst.DelegatingContext<WalkContext, ASTNode> implements WalkContext {
public DelegatingContext(WalkContext parent) {
this.parent = parent;
}
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
super(parent);
}
public Collection<Pair<ITypeBinding, Object>> getCatchTargets(ITypeBinding type) {
return parent.getCatchTargets(type);
}
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
parent.addScopedEntity(newNode, visit);
}
public Map<ASTNode, String> getLabelMap() {
return parent.getLabelMap();
}
public ASTNode getContinueFor(String label) {
return parent.getContinueFor(label);
}
public ASTNode getBreakFor(String label) {
return parent.getBreakFor(label);
}
public boolean needLValue() {
public boolean needLValue() {
return parent.needLValue();
}
}
@ -2961,27 +2932,8 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
/*
* Root context. Doesn't do anything.
*/
public static class RootContext implements WalkContext {
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
Assertions.UNREACHABLE("Rootcontext.addScopedEntity()");
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("RootContext.cfg()");
return null;
}
public CAstSourcePositionRecorder pos() {
Assertions.UNREACHABLE("RootContext.pos()");
return null;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
Assertions.UNREACHABLE("RootContext.getNodeTypeMap()");
return null;
}
public Collection<Pair<ITypeBinding, Object>> getCatchTargets(ITypeBinding type) {
public static class RootContext extends TranslatorToCAst.RootContext<WalkContext, ASTNode> implements WalkContext {
public Collection<Pair<ITypeBinding, Object>> getCatchTargets(ITypeBinding type) {
Assertions.UNREACHABLE("RootContext.getCatchTargets()");
return null;
}
@ -2991,16 +2943,6 @@ public class JDTJava2CAstTranslator implements TranslatorToCAst {
return null;
}
public ASTNode getBreakFor(String label) {
Assertions.UNREACHABLE("RootContext.getBreakFor()");
return null;
}
public ASTNode getContinueFor(String label) {
Assertions.UNREACHABLE("RootContext.getContinueFor()");
return null;
}
public boolean needLValue() {
Assertions.UNREACHABLE("Rootcontext.needLValue()");
return false;

View File

@ -115,8 +115,6 @@ public class JDTSourceModuleTranslator implements SourceModuleTranslator {
public void loadAllSources(Set<ModuleEntry> modules) {
// TODO: we might need one AST (-> "Object" class) for all files.
// TODO: group by project and send 'em in
JDTJava2CAstTranslator jdt2cast = makeCAstTranslator();
final Java2IRTranslator java2ir = makeIRTranslator(jdt2cast);
System.out.println(modules);
@ -143,7 +141,9 @@ public class JDTSourceModuleTranslator implements SourceModuleTranslator {
public void acceptAST(ICompilationUnit source, CompilationUnit ast) {
try {
java2ir.translate(proj.getValue().get(source), ast, source.getUnderlyingResource().getLocation().toOSString());
JDTJava2CAstTranslator jdt2cast = makeCAstTranslator(ast, source.getUnderlyingResource().getLocation().toOSString());
final Java2IRTranslator java2ir = makeIRTranslator();
java2ir.translate(proj.getValue().get(source), jdt2cast.translateToCAst());
} catch (JavaModelException e) {
e.printStackTrace();
}
@ -165,12 +165,12 @@ public class JDTSourceModuleTranslator implements SourceModuleTranslator {
}
}
protected Java2IRTranslator makeIRTranslator(JDTJava2CAstTranslator jdt2cast) {
return new Java2IRTranslator(jdt2cast, sourceLoader);
protected Java2IRTranslator makeIRTranslator() {
return new Java2IRTranslator(sourceLoader);
}
protected JDTJava2CAstTranslator makeCAstTranslator() {
return new JDTJava2CAstTranslator(sourceLoader);
protected JDTJava2CAstTranslator makeCAstTranslator(CompilationUnit cu, String fullPath) {
return new JDTJava2CAstTranslator(sourceLoader, cu, fullPath, false);
}
}

View File

@ -51,16 +51,18 @@ public class IRGoal extends SourceGoal_c /* PORT1.7 removed 'implements EndGoal'
ExtensionInfo extInfo= job.extensionInfo();
fTranslator= new Java2IRTranslator(
fSourceLoader,
((IRTranslatorExtension)extInfo).getCAstRewriterFactory());
ModuleSource src = (ModuleSource) job.source();
fTranslator.translate(
src.getModule(),
new PolyglotJava2CAstTranslator(
job.ast(),
fSourceLoader.getReference(),
extInfo.nodeFactory(),
extInfo.typeSystem(),
new PolyglotIdentityMapper(fSourceLoader.getReference()),
((IRTranslatorExtension)extInfo).getReplicateForDoLoops()),
fSourceLoader,
((IRTranslatorExtension)extInfo).getCAstRewriterFactory());
ModuleSource src = (ModuleSource) job.source();
fTranslator.translate(src.getModule(),job.ast(), src.name());
((IRTranslatorExtension)extInfo).getReplicateForDoLoops()).translateToCAst());
return true;
}

View File

@ -20,6 +20,7 @@ import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@ -34,6 +35,7 @@ import polyglot.ast.ArrayTypeNode;
import polyglot.ast.Assert;
import polyglot.ast.Assign;
import polyglot.ast.Binary;
import polyglot.ast.Binary.Operator;
import polyglot.ast.Block;
import polyglot.ast.BooleanLit;
import polyglot.ast.Branch;
@ -49,6 +51,7 @@ import polyglot.ast.ClassLit;
import polyglot.ast.ClassMember;
import polyglot.ast.Conditional;
import polyglot.ast.ConstructorCall;
import polyglot.ast.ConstructorCall.Kind;
import polyglot.ast.ConstructorDecl;
import polyglot.ast.Do;
import polyglot.ast.Empty;
@ -94,8 +97,6 @@ import polyglot.ast.TopLevelDecl;
import polyglot.ast.Try;
import polyglot.ast.Unary;
import polyglot.ast.While;
import polyglot.ast.Binary.Operator;
import polyglot.ast.ConstructorCall.Kind;
import polyglot.types.ArrayType;
import polyglot.types.ClassType;
import polyglot.types.CodeInstance;
@ -117,9 +118,11 @@ import polyglot.types.Types;
import polyglot.util.Position;
import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.DoLoopTranslator;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst.WalkContext;
import com.ibm.wala.cast.java.loader.Util;
import com.ibm.wala.cast.java.translator.JavaProcedureEntity;
import com.ibm.wala.cast.java.translator.TranslatorToCAst;
import com.ibm.wala.cast.java.types.JavaType;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
@ -132,12 +135,10 @@ import com.ibm.wala.cast.tree.CAstSymbol;
import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.CAstTypeDictionary;
import com.ibm.wala.cast.tree.impl.AbstractSourcePosition;
import com.ibm.wala.cast.tree.impl.CAstCloner;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstRewriter;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
import com.ibm.wala.classLoader.CallSiteReference;
@ -155,8 +156,7 @@ import com.ibm.wala.util.collections.IteratorPlusOne;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
@SuppressWarnings("unchecked")
public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
public class PolyglotJava2CAstTranslator {
protected final CAst fFactory = new CAstImpl();
protected final NodeFactory fNodeFactory;
@ -179,10 +179,12 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
protected PolyglotIdentityMapper fIdentityMapper;
protected boolean replicateForDoLoops = false;
protected final DoLoopTranslator doLoopTranslator;
protected final boolean DEBUG = true;
private final Node ast;
final protected TranslatingVisitor getTranslator() {
if (fTranslator == null)
fTranslator = createTranslator();
@ -1133,42 +1135,17 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
String loopLabel = (String) wc.getLabelMap().get(d);
CAstNode continueNode = walkNodes(continueTarget, wc);
CAstNode breakBody = walkNodes(breakTarget, wc);
CAstNode breakNode = walkNodes(breakTarget, wc);
WalkContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode loopBody = walkNodes(d.body(), lc);
if (replicateForDoLoops) {
CAstRewriter.Rewrite x = (new CAstCloner(fFactory, false)).copy(loopBody, wc.cfg(), wc.pos(), wc.getNodeTypeMap(), null);
CAstNode otherBody = x.newRoot();
wc.cfg().addAll(x.newCfg());
wc.pos().addAll(x.newPos());
wc.getNodeTypeMap().addAll(x.newTypes());
WalkContext lc = new LoopContext(wc, loopLabel, breakTarget, continueTarget);
CAstNode loopExpr = walkNodes(d.cond(), wc);
CAstNode loopBody = walkNodes(d.body(), lc);
return makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
loopBody,
makeNode(wc, fFactory, d, CAstNode.LOOP,
walkNodes(d.cond(), wc),
makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT, otherBody, continueNode)),
breakBody);
} else {
Node header = fNodeFactory.Empty(Position.COMPILER_GENERATED);
CAstNode loopGoto = makeNode(wc, fFactory, d, CAstNode.IFGOTO, walkNodes(d.cond(), wc));
wc.cfg().map(loopGoto, loopGoto);
wc.cfg().add(loopGoto, header, Boolean.TRUE);
return makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT,
walkNodes(header, wc),
makeNode(wc, fFactory, d, CAstNode.BLOCK_STMT, loopBody, continueNode),
loopGoto,
breakBody);
}
return doLoopTranslator.translateDoLoop(loopExpr, loopBody, continueNode, breakNode, wc);
}
public CAstNode visit(For f, WalkContext wc) {
Node breakTarget = makeBreakTarget(f);
Node continueTarget = makeContinueTarget(f);
@ -1529,12 +1506,8 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
protected abstract static class CodeBodyEntity implements CAstEntity {
private final Map<CAstNode, Collection<CAstEntity>> fEntities;
public CodeBodyEntity(Map<CAstNode, CAstEntity> entities) {
fEntities = new LinkedHashMap<CAstNode, Collection<CAstEntity>>();
for (Iterator<CAstNode> keys = entities.keySet().iterator(); keys.hasNext();) {
CAstNode key = keys.next();
fEntities.put(key, Collections.singleton(entities.get(key)));
}
public CodeBodyEntity(Map<CAstNode, Collection<CAstEntity>> entities) {
fEntities = new LinkedHashMap<CAstNode, Collection<CAstEntity>>(entities);
}
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
@ -1674,7 +1647,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
private final String[] argumentNames;
public ProcedureEntity(CAstNode pdast, TypeSystem system, CodeInstance pd, Type declaringType, String[] argumentNames,
Map<CAstNode, CAstEntity> entities, MethodContext mc) {
Map<CAstNode, Collection<CAstEntity>> entities, MethodContext mc) {
super(entities);
fPdast = pdast;
fSystem = system;
@ -1685,7 +1658,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
}
public ProcedureEntity(CAstNode pdast, TypeSystem system, CodeInstance pd, String[] argumentNames,
Map<CAstNode, CAstEntity> entities, MethodContext mc) {
Map<CAstNode, Collection<CAstEntity>> entities, MethodContext mc) {
//PORT1.7 used to be this(pdast, system, pd, ((MemberInstance) pd).container(), argumentNames, entities, mc);
this(pdast, system, pd, ((MemberDef) pd.def()).container().get(), argumentNames, entities, mc);
}
@ -1916,21 +1889,9 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
}
}
public interface WalkContext {
void addScopedEntity(CAstNode node, CAstEntity e);
CAstControlFlowRecorder cfg();
CAstSourcePositionRecorder pos();
CAstNodeTypeMapRecorder getNodeTypeMap();
public interface WalkContext extends TranslatorToCAst.WalkContext<WalkContext, Node> {
Collection<Pair<Type, Object>> getCatchTargets(Type label);
Node getContinueFor(String label);
Node getBreakFor(String label);
Node getFinally();
CodeInstance getEnclosingMethod();
@ -1948,49 +1909,15 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
boolean needLVal();
}
protected static class DelegatingContext implements WalkContext {
private final WalkContext parent;
public WalkContext getParent() {
return parent;
}
protected static class DelegatingContext extends TranslatorToCAst.DelegatingContext<WalkContext, Node> implements WalkContext {
protected DelegatingContext(WalkContext parent) {
this.parent = parent;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
parent.addScopedEntity(node, e);
}
// public Map/*<CAstNode,CAstEntity>*/ getScopedEntities() {
// return parent.getScopedEntities();
// }
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
super(parent);
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
return parent.getCatchTargets(label);
}
public Node getContinueFor(String label) {
return parent.getContinueFor(label);
}
public Node getBreakFor(String label) {
return parent.getBreakFor(label);
}
public Node getFinally() {
return parent.getFinally();
}
@ -2121,9 +2048,9 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
private final Map<Node, String> labelMap = HashMapFactory.make(2);
private final Map<CAstNode, CAstEntity> fEntities;
private final Map<CAstNode, Collection<CAstEntity>> fEntities;
public CodeBodyContext(WalkContext parent, Map<CAstNode, CAstEntity> entities) {
public CodeBodyContext(WalkContext parent, Map<CAstNode, Collection<CAstEntity>> entities) {
super(parent);
fEntities = entities;
}
@ -2141,10 +2068,11 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
}
public void addScopedEntity(CAstNode node, CAstEntity entity) {
fEntities.put(node, entity);
if (! fEntities.containsKey(node)) { fEntities.put(node, new HashSet<CAstEntity>(1)); }
fEntities.get(node).add(entity);
}
public Map/* <CAstNode,CAstEntity> */<CAstNode, CAstEntity> getScopedEntities() {
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return fEntities;
}
@ -2160,7 +2088,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
public class MethodContext extends CodeBodyContext {
final CodeInstance fPI;
public MethodContext(CodeInstance pi, Map<CAstNode, CAstEntity> entities, WalkContext parent) {
public MethodContext(CodeInstance pi, Map<CAstNode, Collection<CAstEntity>> entities, WalkContext parent) {
super(parent, entities);
fPI = pi;
}
@ -2188,8 +2116,8 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
this.tryNode = tryNode;
this.context = context;
for (Iterator catchIter = tryNode.catchBlocks().iterator(); catchIter.hasNext();) {
Catch c = (Catch) catchIter.next();
for (Iterator<Catch> catchIter = tryNode.catchBlocks().iterator(); catchIter.hasNext();) {
Catch c = catchIter.next();
Pair<Type,Object> p = Pair.make(c.catchType(), (Object)c);
fCatchNodes.add(p);
@ -2217,7 +2145,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
continue;
}
}
catchNodes.addAll(getParent().getCatchTargets(label));
catchNodes.addAll(parent.getCatchTargets(label));
return catchNodes;
}
@ -2230,53 +2158,23 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
}
}
protected static class RootContext implements WalkContext {
protected static class RootContext extends TranslatorToCAst.RootContext<WalkContext, Node> implements WalkContext {
final CAstTypeDictionary fTypeDict;
public RootContext(CAstTypeDictionary typeDict) {
fTypeDict = typeDict;
}
public void addScopedEntity(CAstNode node, CAstEntity e) {
Assertions.UNREACHABLE("Attempt to call addScopedEntity() on a RootContext.");
}
public CAstControlFlowRecorder cfg() {
Assertions.UNREACHABLE("RootContext.cfg()");
return null;
}
public Collection<Pair<Type, Object>> getCatchTargets(Type label) {
Assertions.UNREACHABLE("RootContext.getCatchTargets()");
return null;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
Assertions.UNREACHABLE("RootContext.getNodeTypeMap()");
return null;
}
public Node getFinally() {
Assertions.UNREACHABLE("RootContext.getFinally()");
return null;
}
public CAstSourcePositionRecorder pos() {
// No AST, so no AST map
Assertions.UNREACHABLE("RootContext.pos()");
return null;
}
public Node getContinueFor(String label) {
Assertions.UNREACHABLE("RootContext.getContinueFor()");
return null;
}
public Node getBreakFor(String label) {
Assertions.UNREACHABLE("RootContext.getBreakFor()");
return null;
}
public CodeInstance getEnclosingMethod() {
Assertions.UNREACHABLE("RootContext.getEnclosingMethod()");
return null;
@ -2360,12 +2258,13 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
}
}
public PolyglotJava2CAstTranslator(ClassLoaderReference clr, NodeFactory nf, TypeSystem ts, PolyglotIdentityMapper identityMapper, boolean replicateForDoLoops) {
public PolyglotJava2CAstTranslator(Node ast, ClassLoaderReference clr, NodeFactory nf, TypeSystem ts, PolyglotIdentityMapper identityMapper, boolean replicateForDoLoops) {
this.ast = ast;
fClassLoaderRef = clr;
fTypeSystem = ts;
fNodeFactory = nf;
fIdentityMapper = identityMapper;
this.replicateForDoLoops = replicateForDoLoops;
doLoopTranslator = new DoLoopTranslator(replicateForDoLoops, fFactory);
fNPEType = fTypeSystem.NullPointerException();
fCCEType = fTypeSystem.ClassCastException();
fREType = fTypeSystem.RuntimeException();
@ -2530,8 +2429,8 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
return cn;
}
public CAstEntity translate(Object ast, String fileName) {
return walkEntity((Node) ast, new RootContext(getTypeDict()));
public CAstEntity translateToCAst() {
return walkEntity(ast, new RootContext(getTypeDict()));
}
/**
@ -2623,7 +2522,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
InitializerDef initDef = fTypeSystem.initializerDef(n.position(), Types.ref(classType), Flags.STATIC);
InitializerInstance initInstance = fTypeSystem.createInitializerInstance(n.position(), Types.ref(initDef));
Map<CAstNode, CAstEntity> childEntities = HashMapFactory.make();
Map<CAstNode, Collection<CAstEntity>> childEntities = HashMapFactory.make();
final MethodContext mc = new MethodContext(initInstance, childEntities, classContext);
List inits = classContext.getStaticInitializers();
@ -2644,7 +2543,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
for (Iterator iter = superConstructors.iterator(); iter.hasNext();) {
ConstructorInstance superCtor = (ConstructorInstance) iter.next();
Map<CAstNode, CAstEntity> childEntities = HashMapFactory.make();
Map<CAstNode, Collection<CAstEntity>> childEntities = HashMapFactory.make();
final MethodContext mc = new MethodContext(superCtor, childEntities, classContext);
String[] fakeArguments = new String[superCtor.formalTypes().size() + 1];
@ -2713,7 +2612,7 @@ public class PolyglotJava2CAstTranslator implements TranslatorToCAst {
return new ClassEntity(classContext, memberEntities, anonType, anonTypeName, n.position());
} else if (rootNode instanceof ProcedureDecl) {
final ProcedureDecl pd = (ProcedureDecl) rootNode;
final Map<CAstNode, CAstEntity> memberEntities = new LinkedHashMap<CAstNode, CAstEntity>();
final Map<CAstNode, Collection<CAstEntity>> memberEntities = HashMapFactory.make();
final MethodContext mc = new MethodContext(pd.procedureInstance().asInstance(), memberEntities, context);
CAstNode pdAST = null;

View File

@ -186,7 +186,7 @@ public class SynchronizedBlockDuplicator extends
return null;
}
protected CAstNode copyNodes(CAstNode n, RewriteContext<UnwindKey> c, Map<Pair<CAstNode, UnwindKey>, CAstNode> nodeMap) {
protected CAstNode copyNodes(CAstNode n, final CAstControlFlowMap cfg, RewriteContext<UnwindKey> c, Map<Pair<CAstNode, UnwindKey>, CAstNode> nodeMap) {
String varName;
// don't copy operators or constants (presumably since they are immutable?)
if (n instanceof CAstOperator) {
@ -204,15 +204,15 @@ public class SynchronizedBlockDuplicator extends
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(varName)));
// the new if conditional
return Ast.makeNode(CAstNode.IF_STMT, test, copyNodes(n, new SyncContext(true, n, c), nodeMap),
copyNodes(n, new SyncContext(false, n, c), nodeMap));
return Ast.makeNode(CAstNode.IF_STMT, test, copyNodes(n, cfg, new SyncContext(true, n, c), nodeMap),
copyNodes(n, cfg, new SyncContext(false, n, c), nodeMap));
} else {
// invoke copyNodes() on the children with context c, ensuring, e.g., that
// the body of a synchronized block gets cloned
CAstNode[] newChildren = new CAstNode[n.getChildCount()];
for (int i = 0; i < newChildren.length; i++)
newChildren[i] = copyNodes(n.getChild(i), c, nodeMap);
newChildren[i] = copyNodes(n.getChild(i), cfg, c, nodeMap);
CAstNode newN = Ast.makeNode(n.getKind(), newChildren);

View File

@ -15,6 +15,7 @@ package com.ibm.wala.cast.java.translator;
import java.io.PrintWriter;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.java.loader.JavaSourceLoaderImpl;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstEntity;
@ -29,34 +30,29 @@ public class Java2IRTranslator {
protected final JavaSourceLoaderImpl fLoader;
protected final TranslatorToCAst fSourceTranslator;
CAstRewriterFactory castRewriterFactory = null;
public Java2IRTranslator(TranslatorToCAst sourceTranslator, JavaSourceLoaderImpl srcLoader) {
this(sourceTranslator, srcLoader, false);
public Java2IRTranslator(JavaSourceLoaderImpl srcLoader) {
this(srcLoader, false);
}
public Java2IRTranslator(TranslatorToCAst sourceTranslator, JavaSourceLoaderImpl srcLoader, boolean debug) {
this(sourceTranslator, srcLoader, null, debug);
public Java2IRTranslator(JavaSourceLoaderImpl srcLoader, boolean debug) {
this(srcLoader, null, debug);
}
public Java2IRTranslator(TranslatorToCAst sourceTranslator, JavaSourceLoaderImpl srcLoader,
public Java2IRTranslator(JavaSourceLoaderImpl srcLoader,
CAstRewriterFactory castRewriterFactory) {
this(sourceTranslator, srcLoader, castRewriterFactory, false);
this(srcLoader, castRewriterFactory, false);
}
public Java2IRTranslator(TranslatorToCAst sourceTranslator, JavaSourceLoaderImpl srcLoader,
public Java2IRTranslator(JavaSourceLoaderImpl srcLoader,
CAstRewriterFactory castRewriterFactory, boolean debug) {
DEBUG = debug;
fLoader = srcLoader;
fSourceTranslator = sourceTranslator;
this.castRewriterFactory = castRewriterFactory;
}
public void translate(ModuleEntry module, Object ast, String N) {
CAstEntity ce = fSourceTranslator.translate(ast, N);
public void translate(ModuleEntry module, CAstEntity ce) {
if (DEBUG) {
PrintWriter printWriter = new PrintWriter(System.out);
CAstPrinter.printTo(ce, printWriter);

View File

@ -304,26 +304,24 @@ public class JavaCAst2IRTranslator extends AstTranslator {
return ((JavaSourceLoaderImpl) loader).defineType(type, type.getType().getName(), parentType) != null;
}
protected void leaveThis(CAstNode n, Context c, CAstVisitor visitor) {
protected void leaveThis(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
if (n.getChildCount() == 0) {
super.leaveThis(n, c, visitor);
} else {
WalkContext wc = (WalkContext) c;
int result = wc.currentScope().allocateTempValue();
setValue(n, result);
wc.cfg().addInstruction(new EnclosingObjectReference(result, (TypeReference) n.getChild(0).getValue()));
int result = c.currentScope().allocateTempValue();
c.setValue(n, result);
c.cfg().addInstruction(new EnclosingObjectReference(result, (TypeReference) n.getChild(0).getValue()));
}
}
protected boolean visitCast(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
protected boolean visitCast(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
int result = context.currentScope().allocateTempValue();
setValue(n, result);
context.setValue(n, result);
return false;
}
protected void leaveCast(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int result = getValue(n);
protected void leaveCast(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
int result = context.getValue(n);
CAstType toType = (CAstType) n.getChild(0).getValue();
TypeReference toRef = makeType(toType);
@ -334,7 +332,7 @@ public class JavaCAst2IRTranslator extends AstTranslator {
context.cfg().addInstruction(
insts.ConversionInstruction(
result,
getValue(n.getChild(1)),
context.getValue(n.getChild(1)),
fromRef,
toRef,
false));
@ -343,43 +341,42 @@ public class JavaCAst2IRTranslator extends AstTranslator {
context.cfg().addInstruction(
insts.CheckCastInstruction(
result,
getValue(n.getChild(1)),
context.getValue(n.getChild(1)),
toRef,
true));
processExceptions(n, context);
}
}
protected boolean visitInstanceOf(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
protected boolean visitInstanceOf(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
int result = context.currentScope().allocateTempValue();
setValue(n, result);
context.setValue(n, result);
return false;
}
protected void leaveInstanceOf(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext)c;
int result = getValue(n);
protected void leaveInstanceOf(CAstNode n, WalkContext context, CAstVisitor<WalkContext> visitor) {
int result = context.getValue(n);
CAstType type = (CAstType) n.getChild(0).getValue();
TypeReference ref = makeType( type );
context.cfg().addInstruction(
insts.InstanceofInstruction(
result,
getValue(n.getChild(1)),
context.getValue(n.getChild(1)),
ref));
}
protected boolean doVisit(CAstNode n, Context context, CAstVisitor visitor) {
WalkContext wc = (WalkContext) context;
protected boolean doVisit(CAstNode n, WalkContext wc, CAstVisitor<WalkContext> visitor) {
if (n.getKind() == CAstNode.MONITOR_ENTER) {
visitor.visit(n.getChild(0), wc, visitor);
wc.cfg().addInstruction(insts.MonitorInstruction(getValue(n.getChild(0)), true));
wc.cfg().addInstruction(insts.MonitorInstruction(wc.getValue(n.getChild(0)), true));
processExceptions(n, wc);
return true;
} else if (n.getKind() == CAstNode.MONITOR_EXIT) {
visitor.visit(n.getChild(0), wc, visitor);
wc.cfg().addInstruction(insts.MonitorInstruction(getValue(n.getChild(0)), false));
wc.cfg().addInstruction(insts.MonitorInstruction(wc.getValue(n.getChild(0)), false));
processExceptions(n, wc);
return true;
} else {

View File

@ -1,19 +0,0 @@
/******************************************************************************
* 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.java.translator;
import com.ibm.wala.cast.tree.CAstEntity;
public interface TranslatorToCAst {
public CAstEntity translate(Object astRoot, String unitName);
}

View File

@ -0,0 +1,15 @@
package com.ibm.wala.cast.js.test;
import org.junit.Before;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
public class TestArgumentSensitivityRhino extends TestArgumentSensitivity {
@Before
public void setUp() {
com.ibm.wala.cast.js.ipa.callgraph.Util.setTranslatorFactory(new CAstRhinoTranslatorFactory());
}
}

View File

@ -15,10 +15,10 @@ import java.io.IOException;
import com.ibm.wala.cast.js.ipa.callgraph.correlations.CorrelationFinder;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
import com.ibm.wala.cast.js.translator.RhinoToAstTranslator;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.classLoader.SourceModule;
import org.mozilla.javascript.RhinoToAstTranslator;
public class TestCorrelatedPairExtractionRhino extends TestCorrelatedPairExtraction {
protected CorrelationFinder makeCorrelationFinder() {
@ -26,9 +26,8 @@ public class TestCorrelatedPairExtractionRhino extends TestCorrelatedPairExtract
}
protected CAstEntity parseJS(CAstImpl ast, SourceModule module) throws IOException {
RhinoToAstTranslator.resetGensymCounters();
RhinoToAstTranslator translator = new RhinoToAstTranslator(ast, module, module.getName());
CAstEntity entity = translator.translate();
RhinoToAstTranslator translator = new RhinoToAstTranslator(ast, module, module.getName(), false);
CAstEntity entity = translator.translateToCAst();
return entity;
}
}

View File

@ -13,17 +13,16 @@ package com.ibm.wala.cast.js.test;
import java.io.IOException;
import org.mozilla.javascript.RhinoToAstTranslator;
import com.ibm.wala.cast.js.translator.RhinoToAstTranslator;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.classLoader.SourceModule;
public class TestForInBodyExtractionRhino extends TestForInBodyExtraction {
protected CAstEntity parseJS(CAstImpl ast, SourceModule module) throws IOException {
RhinoToAstTranslator.resetGensymCounters();
RhinoToAstTranslator translator = new RhinoToAstTranslator(ast, module, module.getName());
CAstEntity entity = translator.translate();
RhinoToAstTranslator translator = new RhinoToAstTranslator(ast, module, module.getName(), false);
CAstEntity entity = translator.translateToCAst();
return entity;
}
}

View File

@ -0,0 +1,18 @@
package com.ibm.wala.cast.js.test;
import org.junit.Before;
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
public class TestJQueryExamplesRhino extends TestJQueryExamples {
public static void main(String[] args) {
justThisTest(TestJQueryExamplesRhino.class);
}
@Before
public void setUp() {
com.ibm.wala.cast.js.ipa.callgraph.Util.setTranslatorFactory(new CAstRhinoTranslatorFactory());
}
}

View File

@ -4,6 +4,7 @@ import java.io.IOException;
import java.net.URL;
import java.util.Set;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.js.html.DefaultSourceExtractor;
import com.ibm.wala.cast.js.html.DomLessSourceExtractor;
import com.ibm.wala.cast.js.html.IdentityUrlResolver;
@ -40,8 +41,8 @@ public class JsViewerDriver extends Util {
SourceModule[] sources = getSources(domless, url);
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, false, true);
builder.setBaseURL(url);
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), sources, false, false, AstIRFactory.makeDefaultFactory());
builder.setBaseURL(url);
CallGraph cg = builder.makeCallGraph(builder.getOptions());
PointerAnalysis pa = builder.getPointerAnalysis();

View File

@ -14,7 +14,6 @@ import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.mozilla.javascript.RhinoToAstTranslator;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.js.translator.PropertyReadExpander.ExpanderKey;
@ -31,9 +30,11 @@ import com.ibm.wala.classLoader.SourceModule;
public class CAstRhinoTranslator implements TranslatorToCAst {
private final List<CAstRewriterFactory> rewriters = new LinkedList<CAstRewriterFactory>();
private final SourceModule M;
public CAstRhinoTranslator(SourceModule M) {
private final boolean replicateForDoLoops;
public CAstRhinoTranslator(SourceModule M, boolean replicateForDoLoops) {
this.M = M;
this.replicateForDoLoops = replicateForDoLoops;
this.addRewriter(new CAstRewriterFactory<PropertyReadExpander.RewriteContext, ExpanderKey>() {
public CAstRewriter<PropertyReadExpander.RewriteContext, ExpanderKey> createCAstRewriter(CAst ast) {
return new PropertyReadExpander(ast);
@ -57,9 +58,10 @@ public class CAstRhinoTranslator implements TranslatorToCAst {
}
CAstImpl Ast = new CAstImpl();
CAstEntity entity = new RhinoToAstTranslator(Ast, M, N).translate();
CAstEntity entity = new RhinoToAstTranslator(Ast, M, N, replicateForDoLoops).translateToCAst();
for(CAstRewriterFactory rwf : rewriters)
entity = rwf.createCAstRewriter(Ast).rewrite(entity);
return entity;
}
}

View File

@ -7,7 +7,7 @@ import com.ibm.wala.classLoader.SourceModule;
public class CAstRhinoTranslatorFactory implements JavaScriptTranslatorFactory {
public TranslatorToCAst make(CAst ast, SourceModule M) {
return new CAstRhinoTranslator(M);
return new CAstRhinoTranslator(M, false);
}
}

View File

@ -0,0 +1,303 @@
package com.ibm.wala.cast.js.translator;
import org.mozilla.javascript.ast.ArrayComprehension;
import org.mozilla.javascript.ast.ArrayComprehensionLoop;
import org.mozilla.javascript.ast.ArrayLiteral;
import org.mozilla.javascript.ast.Assignment;
import org.mozilla.javascript.ast.AstNode;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.Block;
import org.mozilla.javascript.ast.BreakStatement;
import org.mozilla.javascript.ast.CatchClause;
import org.mozilla.javascript.ast.Comment;
import org.mozilla.javascript.ast.ConditionalExpression;
import org.mozilla.javascript.ast.ContinueStatement;
import org.mozilla.javascript.ast.DoLoop;
import org.mozilla.javascript.ast.ElementGet;
import org.mozilla.javascript.ast.EmptyExpression;
import org.mozilla.javascript.ast.ErrorNode;
import org.mozilla.javascript.ast.ExpressionStatement;
import org.mozilla.javascript.ast.ForInLoop;
import org.mozilla.javascript.ast.ForLoop;
import org.mozilla.javascript.ast.FunctionCall;
import org.mozilla.javascript.ast.FunctionNode;
import org.mozilla.javascript.ast.IfStatement;
import org.mozilla.javascript.ast.InfixExpression;
import org.mozilla.javascript.ast.Jump;
import org.mozilla.javascript.ast.KeywordLiteral;
import org.mozilla.javascript.ast.Label;
import org.mozilla.javascript.ast.LabeledStatement;
import org.mozilla.javascript.ast.LetNode;
import org.mozilla.javascript.ast.Name;
import org.mozilla.javascript.ast.NewExpression;
import org.mozilla.javascript.ast.NumberLiteral;
import org.mozilla.javascript.ast.ObjectLiteral;
import org.mozilla.javascript.ast.ObjectProperty;
import org.mozilla.javascript.ast.ParenthesizedExpression;
import org.mozilla.javascript.ast.PropertyGet;
import org.mozilla.javascript.ast.RegExpLiteral;
import org.mozilla.javascript.ast.ReturnStatement;
import org.mozilla.javascript.ast.Scope;
import org.mozilla.javascript.ast.ScriptNode;
import org.mozilla.javascript.ast.StringLiteral;
import org.mozilla.javascript.ast.SwitchCase;
import org.mozilla.javascript.ast.SwitchStatement;
import org.mozilla.javascript.ast.Symbol;
import org.mozilla.javascript.ast.ThrowStatement;
import org.mozilla.javascript.ast.TryStatement;
import org.mozilla.javascript.ast.UnaryExpression;
import org.mozilla.javascript.ast.VariableDeclaration;
import org.mozilla.javascript.ast.VariableInitializer;
import org.mozilla.javascript.ast.WhileLoop;
import org.mozilla.javascript.ast.WithStatement;
import org.mozilla.javascript.ast.XmlDotQuery;
import org.mozilla.javascript.ast.XmlElemRef;
import org.mozilla.javascript.ast.XmlExpression;
import org.mozilla.javascript.ast.XmlFragment;
import org.mozilla.javascript.ast.XmlLiteral;
import org.mozilla.javascript.ast.XmlMemberGet;
import org.mozilla.javascript.ast.XmlPropRef;
import org.mozilla.javascript.ast.XmlRef;
import org.mozilla.javascript.ast.XmlString;
import org.mozilla.javascript.ast.Yield;
public abstract class TypedNodeVisitor<R,A> {
public R visit(AstNode node, A arg) {
if (node instanceof ArrayComprehension) {
return visitArrayComprehension((ArrayComprehension) node, arg);
} else if (node instanceof WhileLoop) {
return visitWhileLoop((WhileLoop) node, arg);
} else if (node instanceof ArrayComprehensionLoop) {
return visitArrayComprehensionLoop((ArrayComprehensionLoop) node, arg);
} else if (node instanceof ArrayLiteral) {
return visitArrayLiteral((ArrayLiteral) node, arg);
} else if (node instanceof Assignment) {
return visitAssignment((Assignment) node, arg);
} else if (node instanceof AstRoot) {
return visitAstRoot((AstRoot) node, arg);
} else if (node instanceof Block) {
return visitBlock((Block) node, arg);
} else if (node instanceof BreakStatement) {
return visitBreakStatement((BreakStatement) node, arg);
} else if (node instanceof CatchClause) {
return visitCatchClause((CatchClause) node, arg);
} else if (node instanceof Comment) {
return visitComment((Comment) node, arg);
} else if (node instanceof ConditionalExpression) {
return visitConditionalExpression((ConditionalExpression) node, arg);
} else if (node instanceof ContinueStatement) {
return visitContinueStatement((ContinueStatement) node, arg);
} else if (node instanceof DoLoop) {
return visitDoLoop((DoLoop) node, arg);
} else if (node instanceof ElementGet) {
return visitElementGet((ElementGet) node, arg);
} else if (node instanceof EmptyExpression) {
return visitEmptyExpression((EmptyExpression) node, arg);
} else if (node instanceof ErrorNode) {
return visitErrorNode((ErrorNode) node, arg);
} else if (node instanceof ExpressionStatement) {
return visitExpressionStatement((ExpressionStatement) node, arg);
} else if (node instanceof ForInLoop) {
return visitForInLoop((ForInLoop) node, arg);
} else if (node instanceof ForLoop) {
return visitForLoop((ForLoop) node, arg);
} else if (node instanceof NewExpression) {
return visitNewExpression((NewExpression) node, arg);
} else if (node instanceof FunctionCall) {
return visitFunctionCall((FunctionCall) node, arg);
} else if (node instanceof FunctionNode) {
return visitFunctionNode((FunctionNode) node, arg);
} else if (node instanceof IfStatement) {
return visitIfStatement((IfStatement) node, arg);
} else if (node instanceof KeywordLiteral) {
return visitKeywordLiteral((KeywordLiteral) node, arg);
} else if (node instanceof Label) {
return visitLabel((Label) node, arg);
} else if (node instanceof LabeledStatement) {
return visitLabeledStatement((LabeledStatement) node, arg);
} else if (node instanceof LetNode) {
return visitLetNode((LetNode) node, arg);
} else if (node instanceof Name) {
return visitName((Name) node, arg);
} else if (node instanceof NumberLiteral) {
return visitNumberLiteral((NumberLiteral) node, arg);
} else if (node instanceof ObjectLiteral) {
return visitObjectLiteral((ObjectLiteral) node, arg);
} else if (node instanceof ObjectProperty) {
return visitObjectProperty((ObjectProperty) node, arg);
} else if (node instanceof ParenthesizedExpression) {
return visitParenthesizedExpression((ParenthesizedExpression) node, arg);
} else if (node instanceof PropertyGet) {
return visitPropertyGet((PropertyGet) node, arg);
} else if (node instanceof RegExpLiteral) {
return visitRegExpLiteral((RegExpLiteral) node, arg);
} else if (node instanceof ReturnStatement) {
return visitReturnStatement((ReturnStatement) node, arg);
} else if (node instanceof Scope) {
return visitScope((Scope) node, arg);
} else if (node instanceof ScriptNode) {
return visitScriptNode((ScriptNode) node, arg);
} else if (node instanceof StringLiteral) {
return visitStringLiteral((StringLiteral) node, arg);
} else if (node instanceof SwitchCase) {
return visitSwitchCase((SwitchCase) node, arg);
} else if (node instanceof SwitchStatement) {
return visitSwitchStatement((SwitchStatement) node, arg);
} else if (node instanceof ThrowStatement) {
return visitThrowStatement((ThrowStatement) node, arg);
} else if (node instanceof TryStatement) {
return visitTryStatement((TryStatement) node, arg);
} else if (node instanceof UnaryExpression) {
return visitUnaryExpression((UnaryExpression) node, arg);
} else if (node instanceof VariableDeclaration) {
return visitVariableDeclaration((VariableDeclaration) node, arg);
} else if (node instanceof VariableInitializer) {
return visitVariableInitializer((VariableInitializer) node, arg);
} else if (node instanceof WithStatement) {
return visitWithStatement((WithStatement) node, arg);
} else if (node instanceof XmlDotQuery) {
return visitXmlDotQuery((XmlDotQuery) node, arg);
} else if (node instanceof XmlElemRef) {
return visitXmlElemRef((XmlElemRef) node, arg);
} else if (node instanceof XmlExpression) {
return visitXmlExpression((XmlExpression) node, arg);
} else if (node instanceof XmlLiteral) {
return visitXmlLiteral((XmlLiteral) node, arg);
} else if (node instanceof XmlMemberGet) {
return visitXmlMemberGet((XmlMemberGet) node, arg);
} else if (node instanceof XmlPropRef) {
return visitXmlPropRef((XmlPropRef) node, arg);
} else if (node instanceof XmlString) {
return visitXmlString((XmlString) node, arg);
} else if (node instanceof Yield) {
return visitYield((Yield) node, arg);
} else if (node instanceof InfixExpression) {
return visitInfixExpression((InfixExpression) node, arg);
} else if (node instanceof Jump) {
return visitJump((Jump) node, arg);
} else {
throw new Error("unexpected node type " + node.getClass().getName());
}
}
public abstract R visitArrayComprehension(ArrayComprehension node, A arg) ;
public abstract R visitArrayComprehensionLoop(ArrayComprehensionLoop node, A arg) ;
public abstract R visitArrayLiteral(ArrayLiteral node, A arg) ;
public abstract R visitAssignment(Assignment node, A arg) ;
public abstract R visitAstRoot(AstRoot node, A arg) ;
public abstract R visitBlock(Block node, A arg) ;
public abstract R visitBreakStatement(BreakStatement node, A arg) ;
public abstract R visitCatchClause(CatchClause node, A arg) ;
public abstract R visitComment(Comment node, A arg) ;
public abstract R visitConditionalExpression(ConditionalExpression node, A arg) ;
public abstract R visitContinueStatement(ContinueStatement node, A arg) ;
public abstract R visitDoLoop(DoLoop node, A arg) ;
public abstract R visitElementGet(ElementGet node, A arg) ;
public abstract R visitEmptyExpression(EmptyExpression node, A arg) ;
public abstract R visitErrorNode(ErrorNode node, A arg) ;
public abstract R visitExpressionStatement(ExpressionStatement node, A arg) ;
public abstract R visitForInLoop(ForInLoop node, A arg) ;
public abstract R visitForLoop(ForLoop node, A arg) ;
public abstract R visitFunctionCall(FunctionCall node, A arg) ;
public abstract R visitFunctionNode(FunctionNode node, A arg) ;
public abstract R visitIfStatement(IfStatement node, A arg) ;
public abstract R visitInfixExpression(InfixExpression node, A arg) ;
public abstract R visitJump(Jump node, A arg) ;
public abstract R visitKeywordLiteral(KeywordLiteral node, A arg) ;
public abstract R visitLabel(Label node, A arg) ;
public abstract R visitLabeledStatement(LabeledStatement node, A arg) ;
public abstract R visitLetNode(LetNode node, A arg) ;
public abstract R visitName(Name node, A arg) ;
public abstract R visitNewExpression(NewExpression node, A arg) ;
public abstract R visitNumberLiteral(NumberLiteral node, A arg) ;
public abstract R visitObjectLiteral(ObjectLiteral node, A arg) ;
public abstract R visitObjectProperty(ObjectProperty node, A arg) ;
public abstract R visitParenthesizedExpression(ParenthesizedExpression node, A arg) ;
public abstract R visitPropertyGet(PropertyGet node, A arg) ;
public abstract R visitRegExpLiteral(RegExpLiteral node, A arg) ;
public abstract R visitReturnStatement(ReturnStatement node, A arg) ;
public abstract R visitScope(Scope node, A arg) ;
public abstract R visitScriptNode(ScriptNode node, A arg) ;
public abstract R visitStringLiteral(StringLiteral node, A arg) ;
public abstract R visitSwitchCase(SwitchCase node, A arg) ;
public abstract R visitSwitchStatement(SwitchStatement node, A arg) ;
public abstract R visitSymbol(Symbol node, A arg) ;
public abstract R visitThrowStatement(ThrowStatement node, A arg) ;
public abstract R visitTryStatement(TryStatement node, A arg) ;
public abstract R visitUnaryExpression(UnaryExpression node, A arg) ;
public abstract R visitVariableDeclaration(VariableDeclaration node, A arg) ;
public abstract R visitVariableInitializer(VariableInitializer node, A arg) ;
public abstract R visitWhileLoop(WhileLoop node, A arg) ;
public abstract R visitWithStatement(WithStatement node, A arg) ;
public abstract R visitXmlDotQuery(XmlDotQuery node, A arg) ;
public abstract R visitXmlElemRef(XmlElemRef node, A arg) ;
public abstract R visitXmlExpression(XmlExpression node, A arg) ;
public abstract R visitXmlFragment(XmlFragment node, A arg) ;
public abstract R visitXmlLiteral(XmlLiteral node, A arg) ;
public abstract R visitXmlMemberGet(XmlMemberGet node, A arg) ;
public abstract R visitXmlPropRef(XmlPropRef node, A arg) ;
public abstract R visitXmlRef(XmlRef node, A arg) ;
public abstract R visitXmlString(XmlString node, A arg) ;
public abstract R visitYield(Yield node, A arg) ;
}

View File

@ -0,0 +1,24 @@
function a() {
if (arguments.length >= 1) {
arguments[0]();
if (arguments.length >= 2) {
arguments[1]();
}
}
}
function x() {
print("x");
}
function y() {
print("y");
}
function z() {
print("z");
}
a(x);
a(y, z);

View File

@ -1,8 +1,11 @@
function() {
switch(0) {
(function(x) {
switch(x) {
case Ext.Date:
return 1;
break;
}
}
return -1;
})(0);

View File

@ -0,0 +1,53 @@
package com.ibm.wala.cast.js.test;
import java.io.IOException;
import org.junit.Test;
import com.ibm.wala.cast.js.ipa.callgraph.ArgumentSpecialization;
import com.ibm.wala.cast.js.ipa.callgraph.JSAnalysisOptions;
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
import com.ibm.wala.cast.js.ipa.callgraph.JSZeroOrOneXCFABuilder;
import com.ibm.wala.cast.js.loader.JavaScriptLoaderFactory;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisScope;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.Entrypoint;
import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.util.CancelException;
public abstract class TestArgumentSensitivity extends TestJSCallGraphShape {
protected static final Object[][] assertionsForArgs = new Object[][] {
new Object[] { ROOT, new String[] { "tests/args.js" } },
new Object[] {
"tests/args.js",
new String[] { "tests/args.js/a" } },
new Object[] { "tests/args.js/a", new String[] { "tests/args.js/x"} },
new Object[] { "tests/args.js/a", new String[] { "tests/args.js/y", "tests/args.js/z" } } };
@Test public void testArgs() throws IOException, IllegalArgumentException, CancelException, ClassHierarchyException {
JavaScriptLoaderFactory loaders = Util.makeLoaders();
AnalysisScope scope = Util.makeScriptScope("tests", "args.js", loaders);
IClassHierarchy cha = Util.makeHierarchy(scope, loaders);
com.ibm.wala.cast.js.util.Util.checkForFrontEndErrors(cha);
Iterable<Entrypoint> roots = Util.makeScriptRoots(cha);
JSAnalysisOptions options = Util.makeOptions(scope, cha, roots);
AnalysisCache cache = Util.makeCache(new ArgumentSpecialization.ArgumentCountIRFactory(options.getSSAOptions()));
JSCFABuilder builder = new JSZeroOrOneXCFABuilder(cha, options, cache, null, null, ZeroXInstanceKeys.ALLOCATIONS, false);
builder.setContextSelector(new ArgumentSpecialization.ArgumentCountContextSelector(builder.getContextSelector()));
builder.setContextInterpreter(new ArgumentSpecialization.ArgumentSpecializationContextIntepreter(options, cache));
CallGraph CG = builder.makeCallGraph(options);
Util.AVOID_DUMP = false;
Util.dumpCG(builder.getPointerAnalysis(), CG);
verifyGraphAssertions(CG, assertionsForArgs);
}
}

View File

@ -0,0 +1,32 @@
package com.ibm.wala.cast.js.test;
import java.io.IOException;
import java.net.URL;
import org.junit.Before;
import org.junit.Test;
import com.ibm.wala.cast.js.html.JSSourceExtractor;
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.CancelException;
public class TestJQueryExamples extends TestJSCallGraphShape {
public static void main(String[] args) {
justThisTest(TestJQueryExamples.class);
}
@Before
public void config() {
JSSourceExtractor.USE_TEMP_NAME = false;
JSSourceExtractor.DELETE_UPON_EXIT = false;
}
@Test public void testEx1() throws IOException, IllegalArgumentException, CancelException {
URL url = getClass().getClassLoader().getResource("pages/jquery/ex1.html");
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
CallGraph CG = builder.makeCallGraph(builder.getOptions());
Util.dumpCG(builder.getPointerAnalysis(), CG);
}
}

View File

@ -42,6 +42,18 @@ public abstract class TestSimpleCallGraphShape extends TestJSCallGraphShape {
justThisTest(TestSimpleCallGraphShape.class);
}
protected static final Object[][] assertionsForArgs = new Object[][] {
new Object[] { ROOT, new String[] { "tests/args.js" } },
new Object[] {
"tests/args.js",
new String[] { "tests/args.js/a" } },
new Object[] { "tests/args.js/a", new String[] { "tests/args.js/x", "tests/args.js/y" } } };
@Test public void testArgs() throws IOException, IllegalArgumentException, CancelException {
CallGraph CG = Util.makeScriptCG("tests", "args.js");
verifyGraphAssertions(CG, assertionsForArgs);
}
protected static final Object[][] assertionsForSimple = new Object[][] {
new Object[] { ROOT, new String[] { "tests/simple.js" } },
new Object[] {

View File

@ -139,6 +139,7 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape
@Test public void testCrawlPage12() throws IOException, IllegalArgumentException, CancelException {
URL url = getClass().getClassLoader().getResource("pages/crawl/page12.html");
CallGraph CG = Util.makeHTMLCG(url);
System.err.println(CG);
verifyGraphAssertions(CG, assertionsForPage12);
}
@ -230,7 +231,9 @@ public abstract class TestSimplePageCallGraphShape extends TestJSCallGraphShape
@Test public void testCrawlPage17() throws IOException, IllegalArgumentException, CancelException {
URL url = getClass().getClassLoader().getResource("pages/crawl/page17.html");
CallGraph CG = Util.makeHTMLCG(url);
JSCFABuilder builder = Util.makeHTMLCGBuilder(url);
CallGraph CG = builder.makeCallGraph(builder.getOptions());
Util.dumpCG(builder.getPointerAnalysis(), CG);
verifyGraphAssertions(CG, assertionsForPage17);
}

View File

@ -18,6 +18,7 @@ import java.util.Set;
import junit.framework.Assert;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.js.html.MappedSourceModule;
import com.ibm.wala.cast.js.html.WebPageLoaderFactory;
import com.ibm.wala.cast.js.html.WebUtil;
@ -36,6 +37,7 @@ import com.ibm.wala.ipa.callgraph.propagation.PropagationCallGraphBuilder;
import com.ibm.wala.ipa.callgraph.propagation.cfa.ZeroXInstanceKeys;
import com.ibm.wala.ipa.cha.ClassHierarchyException;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.ssa.IRFactory;
import com.ibm.wala.util.CancelException;
/**
@ -43,9 +45,15 @@ import com.ibm.wala.util.CancelException;
*/
public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
public static JSCFABuilder makeScriptCGBuilder(String dir, String name, boolean useOneCFA) throws IOException {
public static JSCFABuilder makeScriptCGBuilder(String dir, String name, boolean useOneCFA, IRFactory irFactory) throws IOException {
JavaScriptLoaderFactory loaders = Util.makeLoaders();
AnalysisScope scope = makeScriptScope(dir, name, loaders);
return makeCG(loaders, scope, useOneCFA, true, irFactory);
}
static AnalysisScope makeScriptScope(String dir, String name, JavaScriptLoaderFactory loaders) throws IOException {
URL script = Util.class.getClassLoader().getResource(dir + File.separator + name);
if (script == null) {
script = Util.class.getClassLoader().getResource(dir + "/" + name);
@ -58,29 +66,36 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
} else {
scope = makeScope(new SourceFileModule[] { makeSourceModule(script, dir, name) }, loaders, JavaScriptLoader.JS);
}
return makeCG(loaders, scope, useOneCFA, true);
return scope;
}
public static JSCFABuilder makeScriptCGBuilder(String dir, String name) throws IOException {
return makeScriptCGBuilder(dir, name, false);
return makeScriptCGBuilder(dir, name, false, AstIRFactory.makeDefaultFactory());
}
public static CallGraph makeScriptCG(String dir, String name) throws IOException, IllegalArgumentException, CancelException {
return makeScriptCG(dir, name, false);
return makeScriptCG(dir, name, AstIRFactory.makeDefaultFactory());
}
public static CallGraph makeScriptCG(String dir, String name, boolean useOneCFA) throws IOException, IllegalArgumentException,
public static CallGraph makeScriptCG(String dir, String name, boolean useOneCFA) throws IOException, IllegalArgumentException, CancelException {
return makeScriptCG(dir, name, useOneCFA, AstIRFactory.makeDefaultFactory());
}
public static CallGraph makeScriptCG(String dir, String name, IRFactory irFactory) throws IOException, IllegalArgumentException, CancelException {
return makeScriptCG(dir, name, false, irFactory);
}
public static CallGraph makeScriptCG(String dir, String name, boolean useOneCFA, IRFactory irFactory) throws IOException, IllegalArgumentException,
CancelException {
PropagationCallGraphBuilder b = makeScriptCGBuilder(dir, name, useOneCFA);
PropagationCallGraphBuilder b = makeScriptCGBuilder(dir, name, useOneCFA, irFactory);
CallGraph CG = b.makeCallGraph(b.getOptions());
dumpCG(b.getPointerAnalysis(), CG);
return CG;
}
public static CallGraph makeScriptCG(SourceModule[] scripts, boolean useOneCFA) throws IOException, IllegalArgumentException,
public static CallGraph makeScriptCG(SourceModule[] scripts, boolean useOneCFA, IRFactory irFactory) throws IOException, IllegalArgumentException,
CancelException {
PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, useOneCFA, true);
PropagationCallGraphBuilder b = makeCGBuilder(makeLoaders(), scripts, useOneCFA, true, irFactory);
CallGraph CG = b.makeCallGraph(b.getOptions());
dumpCG(b.getPointerAnalysis(), CG);
return CG;
@ -92,7 +107,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
public static JSCFABuilder makeHTMLCGBuilder(URL url, boolean handleCallApply) throws IOException {
JavaScriptLoader.addBootstrapFile(WebUtil.preamble);
Set<MappedSourceModule> script = WebUtil.extractScriptFromHTML(url);
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory, preprocessor), script.toArray(new SourceModule[script.size()]), false, handleCallApply);
JSCFABuilder builder = makeCGBuilder(new WebPageLoaderFactory(translatorFactory), script.toArray(new SourceModule[script.size()]), false, handleCallApply, AstIRFactory.makeDefaultFactory());
builder.setBaseURL(url);
return builder;
}
@ -100,7 +115,7 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
public static CallGraph makeHTMLCG(URL url) throws IOException, IllegalArgumentException, CancelException {
PropagationCallGraphBuilder b = makeHTMLCGBuilder(url);
CallGraph CG = b.makeCallGraph(b.getOptions());
//dumpCG(b.getPointerAnalysis(), CG);
dumpCG(b.getPointerAnalysis(), CG);
return CG;
}
@ -111,19 +126,19 @@ public class Util extends com.ibm.wala.cast.js.ipa.callgraph.Util {
return CG;
}
public static JSCFABuilder makeCGBuilder(JavaScriptLoaderFactory loaders, SourceModule[] scripts, boolean useOneCFA, boolean handleCallApply) throws IOException {
public static JSCFABuilder makeCGBuilder(JavaScriptLoaderFactory loaders, SourceModule[] scripts, boolean useOneCFA, boolean handleCallApply, IRFactory irFactory) throws IOException {
AnalysisScope scope = makeScope(scripts, loaders, JavaScriptLoader.JS);
return makeCG(loaders, scope, useOneCFA, handleCallApply);
return makeCG(loaders, scope, useOneCFA, handleCallApply, irFactory);
}
protected static JSCFABuilder makeCG(JavaScriptLoaderFactory loaders, AnalysisScope scope, boolean useOneCFA, boolean handleCallApply) throws IOException {
protected static JSCFABuilder makeCG(JavaScriptLoaderFactory loaders, AnalysisScope scope, boolean useOneCFA, boolean handleCallApply, IRFactory irFactory) throws IOException {
try {
IClassHierarchy cha = makeHierarchy(scope, loaders);
com.ibm.wala.cast.js.util.Util.checkForFrontEndErrors(cha);
Iterable<Entrypoint> roots = makeScriptRoots(cha);
JSAnalysisOptions options = makeOptions(scope, cha, roots);
options.setHandleCallApply(handleCallApply);
AnalysisCache cache = makeCache();
AnalysisCache cache = makeCache(irFactory);
JSCFABuilder builder = new JSZeroOrOneXCFABuilder(cha, options, cache, null, null, ZeroXInstanceKeys.ALLOCATIONS, useOneCFA);

View File

@ -0,0 +1,353 @@
package com.ibm.wala.cast.js.ipa.callgraph;
import java.util.Map;
import com.ibm.wala.cast.ipa.callgraph.AstContextInsensitiveSSAContextInterpreter;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.js.loader.JavaScriptLoader;
import com.ibm.wala.cast.js.translator.JSAstTranslator;
import com.ibm.wala.cast.js.translator.JSConstantFoldingRewriter;
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
import com.ibm.wala.cast.loader.AstMethod.Retranslatable;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstBasicRewriter;
import com.ibm.wala.cast.tree.impl.CAstImpl;
import com.ibm.wala.cfg.AbstractCFG;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.AnalysisCache;
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.Context;
import com.ibm.wala.ipa.callgraph.ContextItem;
import com.ibm.wala.ipa.callgraph.ContextItem.Value;
import com.ibm.wala.ipa.callgraph.ContextKey;
import com.ibm.wala.ipa.callgraph.ContextSelector;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSAOptions;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.intset.IntSet;
public class ArgumentSpecialization {
public static class ArgumentSpecializationContextIntepreter extends AstContextInsensitiveSSAContextInterpreter {
public ArgumentSpecializationContextIntepreter(AnalysisOptions options, AnalysisCache cache) {
super(options, cache);
}
@Override
public IR getIR(CGNode node) {
if (node.getMethod() instanceof Retranslatable) {
return getAnalysisCache().getSSACache().findOrCreateIR(node.getMethod(), node.getContext(), options.getSSAOptions());
} else {
return super.getIR(node);
}
}
public DefUse getDU(CGNode node) {
if (node.getMethod() instanceof Retranslatable) {
return getAnalysisCache().getSSACache().findOrCreateDU(node.getMethod(), node.getContext(), options.getSSAOptions());
} else {
return super.getDU(node);
}
}
}
public static class ArgumentCountContext implements Context {
private final Context base;
private final int argumentCount;
public static ContextKey ARGUMENT_COUNT = new ContextKey() {
public String toString() {
return "argument count key";
}
};
public int hashCode() {
return base.hashCode() + (argumentCount * 4073);
}
public boolean equals(Object o) {
return
o.getClass() == this.getClass() &&
base.equals(((ArgumentCountContext)o).base) &&
argumentCount == ((ArgumentCountContext)o).argumentCount;
}
public ArgumentCountContext(int argumentCount, Context base) {
this.argumentCount = argumentCount;
this.base = base;
}
public ContextItem get(ContextKey name) {
return (name == ARGUMENT_COUNT)? ContextItem.Value.make(argumentCount): base.get(name);
}
public String toString() {
return base.toString() + "(nargs:" + argumentCount + ")";
}
}
public static class ArgumentCountContextSelector implements ContextSelector, ContextKey {
private final ContextSelector base;
public ArgumentCountContextSelector(ContextSelector base) {
this.base = base;
}
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] actualParameters) {
Context baseContext = base.getCalleeTarget(caller, site, callee, actualParameters);
if (caller.getMethod() instanceof Retranslatable) {
int v = -1;
for (SSAAbstractInvokeInstruction x : caller.getIR().getCalls(site)) {
if (v == -1) {
v = x.getNumberOfParameters();
} else {
if (v != x.getNumberOfParameters()) {
return baseContext;
}
}
}
return new ArgumentCountContext(v, baseContext);
} else {
return baseContext;
}
}
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
return base.getRelevantParameters(caller, site);
}
}
public static class ArgumentCountIRFactory extends AstIRFactory.AstDefaultIRFactory {
private final SSAOptions defaultOptions;
public ArgumentCountIRFactory(SSAOptions defaultOptions) {
this.defaultOptions = defaultOptions;
}
@Override
public boolean contextIsIrrelevant(IMethod method) {
return method instanceof Retranslatable? false: super.contextIsIrrelevant(method);
}
@Override
public IR makeIR(final IMethod method, Context context, SSAOptions options) {
if (method instanceof Retranslatable) {
@SuppressWarnings("unchecked")
final Value<Integer> v = (Value<Integer>) context.get(ArgumentCountContext.ARGUMENT_COUNT);
final Retranslatable m = (Retranslatable)method;
if (v != null) {
final JavaScriptLoader myloader = (JavaScriptLoader) method.getDeclaringClass().getClassLoader();
class FixedArgumentsRewriter extends CAstBasicRewriter {
private final CAstEntity e = m.getEntity();
public FixedArgumentsRewriter(CAst Ast) {
super(Ast, false);
}
private boolean isNamedVar(CAstNode n, String name) {
if (n.getKind() == CAstNode.VAR) {
String nm = (String) n.getChild(0).getValue();
return nm.equals(name);
}
return false;
}
private Object getIndexFromArgumentRef(CAstNode n) {
if (n.getKind() == CAstNode.OBJECT_REF || n.getKind() == CAstNode.ARRAY_REF) {
if (isNamedVar(n.getChild(0), "arguments")) {
return n.getChild(1).getValue();
}
}
return null;
}
private Object getIndexFromBaseVar(CAstNode n) {
if (n.getKind() == CAstNode.BLOCK_EXPR) {
if (n.getChildCount() == 2) {
CAstNode c1 = n.getChild(0);
if (c1.getKind() == CAstNode.ASSIGN) {
if (isNamedVar(c1.getChild(0), "base")) {
if (isNamedVar(c1.getChild(1), "arguments")) {
CAstNode c2 = n.getChild(1);
if (c2.getKind() == CAstNode.OBJECT_REF || c2.getKind() == CAstNode.ARRAY_REF) {
if (isNamedVar(c2.getChild(0), "base")) {
return c2.getChild(1).getValue();
}
}
}
}
}
}
}
return null;
}
private Object getStaticArgumentIndex(CAstNode n) {
Object x = getIndexFromArgumentRef(n);
if (x != null) {
return x;
} else {
return getIndexFromBaseVar(n);
}
}
private CAstNode handleArgumentRef(CAstNode n) {
Object x = getStaticArgumentIndex(n);
if (x != null) {
if (x instanceof Number && ((Number)x).intValue() < v.getValue()-2) {
int arg = ((Number)x).intValue() + 3;
if (arg < e.getArgumentCount()) {
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant(e.getArgumentNames()[arg]));
} else {
return Ast.makeNode(CAstNode.VAR, Ast.makeConstant("$arg" + arg));
}
} else if (x instanceof String && "length".equals(x)) {
return Ast.makeConstant(v.getValue());
}
}
return null;
}
@Override
protected CAstNode copyNodes(CAstNode root,
CAstControlFlowMap cfg,
NonCopyingContext context,
Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap)
{
CAstNode result = null;
if (root.getKind() == CAstNode.ARRAY_REF
|| root.getKind() == CAstNode.OBJECT_REF
|| root.getKind() == CAstNode.BLOCK_EXPR)
{
result = handleArgumentRef(root);
} else if (root.getKind() == CAstNode.CONSTANT) {
result = Ast.makeConstant(root.getValue());
} else if (root.getKind() == CAstNode.OPERATOR) {
result = root;
}
if (result == null) {
CAstNode children[] = new CAstNode[root.getChildCount()];
for (int i = 0; i < children.length; i++) {
children[i] = copyNodes(root.getChild(i), cfg, context, nodeMap);
}
for(Object label: cfg.getTargetLabels(root)) {
if (label instanceof CAstNode) {
copyNodes((CAstNode)label, cfg, context, nodeMap);
}
}
CAstNode copy = Ast.makeNode(root.getKind(), children);
result = copy;
}
nodeMap.put(Pair.make(root, context.key()), result);
return result;
}
}
final FixedArgumentsRewriter args = new FixedArgumentsRewriter(new CAstImpl());
final JSConstantFoldingRewriter fold = new JSConstantFoldingRewriter(new CAstImpl());
class ArgumentativeTranslator extends JSAstTranslator {
public ArgumentativeTranslator(JavaScriptLoader loader) {
super(loader);
}
private CAstEntity codeBodyEntity;
private IMethod specializedCode;
@Override
protected int getArgumentCount(CAstEntity f) {
return Math.max(super.getArgumentCount(f), v.getValue());
}
@Override
protected String[] getArgumentNames(CAstEntity f) {
if (super.getArgumentCount(f) >= v.getValue()) {
return super.getArgumentNames(f);
} else {
String[] argNames = new String[ v.getValue() ];
System.arraycopy(super.getArgumentNames(f), 0, argNames, 0, super.getArgumentCount(f));
for(int i = super.getArgumentCount(f); i < argNames.length; i++) {
argNames[i] = "$arg" + (i+1);
}
return argNames;
}
}
@Override
protected String composeEntityName(WalkContext parent, CAstEntity f) {
if (f == codeBodyEntity) {
return super.composeEntityName(parent, f) + "_" + v.getValue().intValue();
} else {
return super.composeEntityName(parent, f);
}
}
@Override
protected void defineFunction(CAstEntity N, WalkContext definingContext, AbstractCFG cfg, SymbolTable symtab,
boolean hasCatchBlock, TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation LI,
DebuggingInformation debugInfo) {
if (N == codeBodyEntity) {
specializedCode = myloader.makeCodeBodyCode(cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI, debugInfo, method.getDeclaringClass());
} else {
super.defineFunction(N, definingContext, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI, debugInfo);
}
}
@Override
public void translate(CAstEntity N, WalkContext context) {
if (N == m.getEntity()) {
codeBodyEntity = fold.rewrite(args.rewrite(N));
super.translate(codeBodyEntity, context);
} else {
super.translate(N, context);
}
}
}
ArgumentativeTranslator a = new ArgumentativeTranslator(myloader);
m.retranslate(a);
return super.makeIR(a.specializedCode, context, options);
}
}
return super.makeIR(method, context, options);
}
@Override
public ControlFlowGraph makeCFG(IMethod method, Context context) {
return makeIR(method, context, defaultOptions).getControlFlowGraph();
}
}
}

View File

@ -16,7 +16,6 @@ public class GlobalObjectKey implements InstanceKey {
this.concreteType = concreteType;
}
@Override
public IClass getConcreteType() {
return concreteType;
}

View File

@ -686,15 +686,17 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
system.newConstraint(F, constParams[i][j]);
}
if (av != -1 && i > num_pseudoargs)
if (av != -1 && i > num_pseudoargs) {
targetVisitor.newFieldWrite(target, av, fn, constParams[i]);
}
} else {
PointerKey A = getPointerKeyForLocal(caller, instruction.getUse(i));
system.newConstraint(F, (F instanceof FilteredPointerKey) ? filterOperator : assignOperator, A);
if (av != -1 && i > num_pseudoargs)
if (av != -1 && i > num_pseudoargs) {
targetVisitor.newFieldWrite(target, av, fn, F);
}
}
}

View File

@ -91,7 +91,6 @@ public class JavaScriptFunctionApplyContextSelector implements ContextSelector {
this.isNonNullArray = new BooleanContextItem(isNonNullArray);
}
@Override
public ContextItem get(ContextKey name) {
if (APPLY_NON_NULL_ARGS.equals(name)) {
return isNonNullArray;

View File

@ -62,7 +62,6 @@ public class JavaScriptFunctionDotCallTargetSelector implements MethodTargetSele
* .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) {

View File

@ -50,7 +50,6 @@ public class ObjectSensitivityContextSelector implements ContextSelector {
return false;
}
@Override
public Context getCalleeTarget(CGNode caller, CallSiteReference site, IMethod callee, InstanceKey[] arguments) {
Context baseContext = base.getCalleeTarget(caller, site, callee, arguments);
if(returnsThis(callee)) {
@ -61,7 +60,6 @@ public class ObjectSensitivityContextSelector implements ContextSelector {
return baseContext;
}
@Override
public IntSet getRelevantParameters(CGNode caller, CallSiteReference site) {
if (caller.getIR().getCalls(site)[0].getNumberOfUses() > 1) {
return IntSetUtil.make(new int[]{1}).union(base.getRelevantParameters(caller, site));
@ -83,7 +81,6 @@ class ArgumentInstanceContext implements Context {
this.instanceKey = instanceKey;
}
@Override
public ContextItem get(ContextKey name) {
/*if(name == ContextKey.RECEIVER && index == 1)
return instanceKey;*/

View File

@ -163,16 +163,15 @@ public class Util extends com.ibm.wala.cast.ipa.callgraph.Util {
}
@Override
protected void leaveFunctionStmt(CAstNode n, Context c, CAstVisitor visitor) {
WalkContext context = (WalkContext) c;
protected void leaveFunctionStmt(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
CAstEntity fn = (CAstEntity) n.getChild(0).getValue();
Scope cs = context.currentScope();
Scope cs = c.currentScope();
if (!cs.contains(fn.getName())
|| cs.lookup(fn.getName()).getDefiningScope().getEntity().getKind() == CAstEntity.SCRIPT_ENTITY) {
int result = processFunctionExpr(n, c);
assignValue(n, context, cs.lookup(fn.getName()), fn.getName(), result);
assignValue(n, c, cs.lookup(fn.getName()), fn.getName(), result);
} else {
super.leaveFunctionStmt(n, context, visitor);
super.leaveFunctionStmt(n, c, visitor);
}
}
};

View File

@ -216,7 +216,6 @@ public class CorrelationFinder {
Collections.sort(correlations, new Comparator<Pair<Position, String>>() {
@SuppressWarnings("unchecked")
@Override
public int compare(Pair<Position, String> o1, Pair<Position, String> o2) {
return o1.fst.compareTo(o2.fst);
}

View File

@ -196,50 +196,50 @@ public class ClosureExtractor extends CAstRewriterExt {
}
@Override
protected CAstNode copyNodes(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
protected CAstNode copyNodes(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
switch(root.getKind()) {
case OPERATOR:
return root;
case CONSTANT:
return copyConstant(root, context, nodeMap);
return copyConstant(root, cfg, context, nodeMap);
case BLOCK_STMT:
return copyBlock(root, context, nodeMap);
return copyBlock(root, cfg, context, nodeMap);
case RETURN:
return copyReturn(root, context, nodeMap);
return copyReturn(root, cfg, context, nodeMap);
case VAR:
return copyVar(root, context, nodeMap);
return copyVar(root, cfg, context, nodeMap);
case GOTO:
return copyGoto(root, context, nodeMap);
return copyGoto(root, cfg, context, nodeMap);
default:
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
}
}
/* Constants are not affected by the rewriting, they are just copied. */
private CAstNode copyConstant(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyConstant(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
CAstNode newNode = Ast.makeConstant(root.getValue());
nodeMap.put(Pair.make(root, context.key()), newNode);
return newNode;
}
/* Ask the policy whether it wants anything extracted from this block; otherwise the node is simply copied. */
private CAstNode copyBlock(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyBlock(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
List<ExtractionRegion> regions = policies.getFirst().extract(root);
if(regions == null) {
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
} else {
ArrayList<CAstNode> copied_children = new ArrayList<CAstNode>();
int next_child = 0;
// code in between regions is handled by invoking copyNodes, the regions themselves by extractRegion
for(ExtractionRegion region : regions) {
for(;next_child<region.getStart();++next_child)
copied_children.add(copyNodes(root.getChild(next_child), new ChildPos(root, next_child, context), nodeMap));
for(CAstNode stmt : extractRegion(root, new ExtractionPos(root, region, context), nodeMap))
copied_children.add(copyNodes(root.getChild(next_child), cfg, new ChildPos(root, next_child, context), nodeMap));
for(CAstNode stmt : extractRegion(root, cfg, new ExtractionPos(root, region, context), nodeMap))
copied_children.add(stmt);
next_child = region.getEnd();
}
for(;next_child<root.getChildCount();++next_child)
copied_children.add(copyNodes(root.getChild(next_child), new ChildPos(root, next_child, context), nodeMap));
copied_children.add(copyNodes(root.getChild(next_child), cfg, new ChildPos(root, next_child, context), nodeMap));
CAstNode newNode = Ast.makeNode(BLOCK_STMT, copied_children.toArray(new CAstNode[0]));
nodeMap.put(Pair.make(root, context.key()), newNode);
return newNode;
@ -250,7 +250,7 @@ public class ClosureExtractor extends CAstRewriterExt {
* Normal variables are just copied, but 'this' references need to be rewritten if we are inside an extracted
* function body.
*/
private CAstNode copyVar(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyVar(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
/*
* If this node is a "this" reference, the outermost enclosing extracted function needs to pass in
* the value of "this" as a parameter.
@ -268,10 +268,10 @@ public class ClosureExtractor extends CAstRewriterExt {
nodeMap.put(Pair.make(root, context.key()), newNode);
return newNode;
} else {
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
}
} else {
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
}
}
@ -279,7 +279,7 @@ public class ClosureExtractor extends CAstRewriterExt {
* 'break' and 'continue' statements are both encoded as GOTO. If they refer to a target outside the innermost
* enclosing extracted function body, they are rewritten into a 'return' statement.
*/
private CAstNode copyGoto(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyGoto(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
CAstNode target = getCurrentEntity().getControlFlow().getTarget(root, null);
ExtractionPos epos = ExtractionPos.getEnclosingExtractionPos(context);
if(epos != null && !NodePos.inSubtree(target, epos.getParent())) {
@ -301,18 +301,18 @@ public class ClosureExtractor extends CAstRewriterExt {
nodeMap.put(Pair.make(root, context.key()), newNode);
return newNode;
} else {
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
}
}
/* 'return' statements inside an extracted function body need to be encoded in a similar fashion. */
private CAstNode copyReturn(CAstNode root, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyReturn(CAstNode root, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
ExtractionPos epos = ExtractionPos.getEnclosingExtractionPos(context);
// if an extracted function body may terminate normally, we need to append a default RETURN node
// which should not be rewritten; this node is marked as 'synthetic'
if(epos == null || isSynthetic(root))
return copyNode(root, context, nodeMap);
return copyNode(root, cfg, context, nodeMap);
// add a return to every enclosing extracted function body
do {
@ -323,7 +323,7 @@ public class ClosureExtractor extends CAstRewriterExt {
// emit appropriate 'return' statement
if(root.getChildCount() > 0) {
// return { type: 'return', value: <retval> }
CAstNode retval = copyNodes(root.getChild(0), new ChildPos(root, 0, context), nodeMap);
CAstNode retval = copyNodes(root.getChild(0), cfg, new ChildPos(root, 0, context), nodeMap);
CAstNode newNode =
Ast.makeNode(RETURN,
Ast.makeNode(OBJECT_LITERAL,
@ -352,10 +352,10 @@ public class ClosureExtractor extends CAstRewriterExt {
}
/* Recursively copy child nodes. */
private CAstNode copyNode(CAstNode node, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private CAstNode copyNode(CAstNode node, CAstControlFlowMap cfg, NodePos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
CAstNode children[] = new CAstNode[node.getChildCount()];
for (int i = 0; i < children.length; i++) {
children[i] = copyNodes(node.getChild(i), new ChildPos(node, i, context), nodeMap);
children[i] = copyNodes(node.getChild(i), cfg, new ChildPos(node, i, context), nodeMap);
}
CAstNode newNode = Ast.makeNode(node.getKind(), children);
nodeMap.put(Pair.make(node, context.key()), newNode);
@ -363,7 +363,7 @@ public class ClosureExtractor extends CAstRewriterExt {
// if this node has a control flow successor beyond the innermost enclosing extracted function loop, we need to reroute
ExtractionPos epos = ExtractionPos.getEnclosingExtractionPos(context);
if(!isFlowDeleted(newNode, getCurrentEntity()) && epos != null) {
CAstControlFlowMap cfg = getCurrentEntity().getControlFlow();
// CAstControlFlowMap cfg = getCurrentEntity().getControlFlow();
Collection<Object> labels = cfg.getTargetLabels(node);
boolean invalidateCFlow = false;
for(Object label : labels) {
@ -388,7 +388,7 @@ public class ClosureExtractor extends CAstRewriterExt {
}
private int anonymous_counter = 0;
private List<CAstNode> extractRegion(CAstNode root, ExtractionPos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
private List<CAstNode> extractRegion(CAstNode root, CAstControlFlowMap cfg, ExtractionPos context, Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
CAstEntity entity = getCurrentEntity();
// whether we are extracting a single statement that is itself a block
@ -434,7 +434,7 @@ public class ClosureExtractor extends CAstRewriterExt {
throw new UnimplementedError("Two-level extraction not fully implemented.");
int i;
for(i=0;i<tler.getStartInner();++i)
prologue.add(copyNodes(start.getChild(i),context, nodeMap));
prologue.add(copyNodes(start.getChild(i), cfg, context, nodeMap));
for(;i<start.getChildCount();++i)
fun_body_stmts.add(start.getChild(i));
for(i=context.getStart()+1;i<context.getEnd();++i)
@ -459,7 +459,7 @@ public class ClosureExtractor extends CAstRewriterExt {
* Now we rewrite the body and construct a Rewrite object.
*/
final Map<Pair<CAstNode, NoKey>, CAstNode> nodes = HashMapFactory.make();
final CAstNode newRoot = copyNodes(fun_body, context, nodes);
final CAstNode newRoot = copyNodes(fun_body, cfg, context, nodes);
final CAstSourcePositionMap theSource = copySource(nodes, entity.getSourceMap());
final CAstControlFlowMap theCfg = copyFlow(nodes, entity.getControlFlow(), theSource);
final CAstNodeTypeMap theTypes = copyTypes(nodes, entity.getNodeTypeMap());
@ -468,11 +468,11 @@ public class ClosureExtractor extends CAstRewriterExt {
theChildren.putAll(copyChildren(root.getChild(i), nodes, entity.getAllScopedEntities()));
Rewrite rw = new Rewrite() {
@Override public CAstNode newRoot() { return newRoot; }
@Override public CAstControlFlowMap newCfg() { return theCfg; }
@Override public CAstSourcePositionMap newPos() { return theSource; }
@Override public CAstNodeTypeMap newTypes() { return theTypes; }
@Override public Map<CAstNode, Collection<CAstEntity>> newChildren() { return theChildren; }
public CAstNode newRoot() { return newRoot; }
public CAstControlFlowMap newCfg() { return theCfg; }
public CAstSourcePositionMap newPos() { return theSource; }
public CAstNodeTypeMap newTypes() { return theTypes; }
public Map<CAstNode, Collection<CAstEntity>> newChildren() { return theChildren; }
};
new_entity.setRewrite(rw);
@ -724,4 +724,5 @@ public class ClosureExtractor extends CAstRewriterExt {
synthetic.add(node);
return node;
}
}

View File

@ -37,7 +37,6 @@ public class CorrelatedPairExtractorFactory implements CAstRewriterFactory<NodeP
this.summaries = summaries;
}
@Override
public CAstRewriter<NodePos, NoKey> createCAstRewriter(CAst ast) {
ExtractionPolicyFactory policyFactory = new ExtractionPolicyFactory() {
@Override

View File

@ -61,33 +61,27 @@ class ExtractedFunction implements CAstEntity {
this.types = r.newTypes();
}
@Override
public int getKind() {
return CAstEntity.FUNCTION_ENTITY;
}
@Override
public String getName() {
return name;
}
@Override
public String getSignature() {
return null;
}
@Override
public String[] getArgumentNames() {
computeParms();
return parms;
}
@Override
public CAstNode[] getArgumentDefaults() {
return new CAstNode[0];
}
@Override
public int getArgumentCount() {
computeParms();
return parms.length;
@ -105,7 +99,6 @@ class ExtractedFunction implements CAstEntity {
}
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
if(scopedEntities == null) {
scopedEntities = HashMapFactory.make();
@ -132,7 +125,6 @@ class ExtractedFunction implements CAstEntity {
return scopedEntities;
}
@Override
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
if(getAllScopedEntities().containsKey(construct)) {
return getAllScopedEntities().get(construct).iterator();
@ -141,37 +133,30 @@ class ExtractedFunction implements CAstEntity {
}
}
@Override
public CAstNode getAST() {
return root;
}
@Override
public CAstControlFlowMap getControlFlow() {
return cfg;
}
@Override
public CAstSourcePositionMap getSourceMap() {
return posmap;
}
@Override
public Position getPosition() {
return getSourceMap().getPosition(root);
}
@Override
public CAstNodeTypeMap getNodeTypeMap() {
return types;
}
@Override
public Collection<CAstQualifier> getQualifiers() {
return null;
}
@Override
public CAstType getType() {
return null;
}

View File

@ -26,7 +26,6 @@ import com.ibm.wala.cast.tree.impl.CAstBasicRewriter.NoKey;
public abstract class NodePos implements CAstRewriter.RewriteContext<CAstBasicRewriter.NoKey> {
public abstract <A> A accept(PosSwitch<A> ps);
@Override
public NoKey key() {
return null;
}

View File

@ -33,6 +33,7 @@ import com.ibm.wala.cast.ir.ssa.EachElementGetInstruction;
import com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction;
import com.ibm.wala.cast.ir.translator.AstTranslator;
import com.ibm.wala.cast.ir.translator.AstTranslator.AstLexicalInformation;
import com.ibm.wala.cast.ir.translator.AstTranslator.WalkContext;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.ir.translator.TranslatorToIR;
import com.ibm.wala.cast.js.analysis.typeInference.JSPrimitiveType;
@ -52,6 +53,7 @@ import com.ibm.wala.cast.loader.AstDynamicPropertyClass;
import com.ibm.wala.cast.loader.AstFunctionClass;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.cast.loader.AstMethod.DebuggingInformation;
import com.ibm.wala.cast.loader.AstMethod.Retranslatable;
import com.ibm.wala.cast.loader.CAstAbstractModuleLoader;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstEntity;
@ -641,19 +643,25 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
class JavaScriptCodeBody extends AstFunctionClass {
private final WalkContext translationContext;
private final CAstEntity entity;
public JavaScriptCodeBody(TypeReference codeName, TypeReference parent, IClassLoader loader,
CAstSourcePositionMap.Position sourcePosition) {
CAstSourcePositionMap.Position sourcePosition, CAstEntity entity, WalkContext context) {
super(codeName, parent, loader, sourcePosition);
types.put(codeName.getName(), this);
this.translationContext = context;
this.entity = entity;
}
public IClassHierarchy getClassHierarchy() {
return cha;
}
private IMethod setCodeBody(IMethod codeBody) {
private IMethod setCodeBody(JavaScriptMethodObject codeBody) {
this.functionBody = codeBody;
codeBody.entity = entity;
codeBody.translationContext = translationContext;
return codeBody;
}
}
@ -666,12 +674,27 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
functionQualifiers.add(CAstQualifier.FINAL);
}
public class JavaScriptMethodObject extends AstMethod {
public class JavaScriptMethodObject extends AstMethod implements Retranslatable {
private WalkContext translationContext;
private CAstEntity entity;
JavaScriptMethodObject(JavaScriptCodeBody cls, AbstractCFG cfg, SymbolTable symtab, boolean hasCatchBlock,
JavaScriptMethodObject(IClass cls, AbstractCFG cfg, SymbolTable symtab, boolean hasCatchBlock,
TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo, DebuggingInformation debugInfo) {
super(cls, functionQualifiers, cfg, symtab, AstMethodReference.fnReference(cls.getReference()), hasCatchBlock, caughtTypes,
hasMonitorOp, lexicalInfo, debugInfo);
// force creation of these constants by calling the getter methods
symtab.getNullConstant();
}
public CAstEntity getEntity() {
return entity;
}
public void retranslate(AstTranslator xlator) {
xlator.translate(entity, translationContext);
}
public IClassHierarchy getClassHierarchy() {
@ -745,25 +768,31 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
}
public IClass defineCodeBodyType(String name, TypeReference P, CAstSourcePositionMap.Position sourcePosition) {
public IClass makeCodeBodyType(String name, TypeReference P, CAstSourcePositionMap.Position sourcePosition, CAstEntity entity, WalkContext context) {
return new JavaScriptCodeBody(TypeReference.findOrCreate(JavaScriptTypes.jsLoader, TypeName.string2TypeName(name)), P, this,
sourcePosition);
sourcePosition, entity, context);
}
public IClass defineFunctionType(String name, CAstSourcePositionMap.Position pos) {
return defineCodeBodyType(name, JavaScriptTypes.Function, pos);
public IClass defineFunctionType(String name, CAstSourcePositionMap.Position pos, CAstEntity entity, WalkContext context) {
return makeCodeBodyType(name, JavaScriptTypes.Function, pos, entity, context);
}
public IClass defineScriptType(String name, CAstSourcePositionMap.Position pos) {
return defineCodeBodyType(name, JavaScriptTypes.Script, pos);
public IClass defineScriptType(String name, CAstSourcePositionMap.Position pos, CAstEntity entity, WalkContext context) {
return makeCodeBodyType(name, JavaScriptTypes.Script, pos, entity, context);
}
public IMethod defineCodeBodyCode(String clsName, AbstractCFG cfg, SymbolTable symtab, boolean hasCatchBlock,
TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo, DebuggingInformation debugInfo) {
JavaScriptCodeBody C = (JavaScriptCodeBody) lookupClass(clsName, cha);
assert C != null : clsName;
return C.setCodeBody(new JavaScriptMethodObject(C, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, lexicalInfo,
debugInfo));
return C.setCodeBody(makeCodeBodyCode(cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, lexicalInfo, debugInfo, C));
}
public JavaScriptMethodObject makeCodeBodyCode(AbstractCFG cfg, SymbolTable symtab, boolean hasCatchBlock,
TypeReference[][] caughtTypes, boolean hasMonitorOp, AstLexicalInformation lexicalInfo, DebuggingInformation debugInfo,
IClass C) {
return new JavaScriptMethodObject(C, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, lexicalInfo,
debugInfo);
}
final JavaScriptRootClass ROOT = new JavaScriptRootClass(this, null);

View File

@ -125,9 +125,9 @@ public class JSAstTranslator extends AstTranslator {
protected void declareFunction(CAstEntity N, WalkContext context) {
String fnName = composeEntityName(context, N);
if (N.getKind() == CAstEntity.SCRIPT_ENTITY) {
((JavaScriptLoader) loader).defineScriptType("L" + fnName, N.getPosition());
((JavaScriptLoader) loader).defineScriptType("L" + fnName, N.getPosition(), N, context);
} else if (N.getKind() == CAstEntity.FUNCTION_ENTITY) {
((JavaScriptLoader) loader).defineFunctionType("L" + fnName, N.getPosition());
((JavaScriptLoader) loader).defineFunctionType("L" + fnName, N.getPosition(), N, context);
} else {
Assertions.UNREACHABLE();
}
@ -142,9 +142,6 @@ public class JSAstTranslator extends AstTranslator {
if (DEBUG)
System.err.println(cfg);
// force creation of these constants by calling the getter methods
symtab.getNullConstant();
((JavaScriptLoader) loader).defineCodeBodyCode("L" + fnName, cfg, symtab, hasCatchBlock, caughtTypes, hasMonitorOp, LI,
debugInfo);
@ -211,7 +208,7 @@ public class JSAstTranslator extends AstTranslator {
context.currentScope().getConstantValue(field);
context.cfg().addInstruction(((JSInstructionFactory) insts).GetInstruction(result, x, field));
} else {
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyRead(result, x, getValue(elt)));
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyRead(result, x, context.getValue(elt)));
}
// generate code to handle read of non-existent property
@ -240,7 +237,7 @@ public class JSAstTranslator extends AstTranslator {
}
context.cfg().addInstruction(put);
} else {
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(receiver, getValue(elt), rval));
context.cfg().addInstruction(((JSInstructionFactory) insts).PropertyWrite(receiver, context.getValue(elt), rval));
}
}
@ -328,26 +325,26 @@ public class JSAstTranslator extends AstTranslator {
} else {
context.cfg().addInstruction(((JSInstructionFactory) insts).IsDefinedInstruction(result, ref, getValue(f)));
context.cfg().addInstruction(((JSInstructionFactory) insts).IsDefinedInstruction(result, ref, context.getValue(f)));
}
}
protected boolean visitInstanceOf(CAstNode n, Context c, CAstVisitor visitor) {
protected boolean visitInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
WalkContext context = (WalkContext) c;
int result = context.currentScope().allocateTempValue();
setValue(n, result);
context.setValue(n, result);
return false;
}
protected void leaveInstanceOf(CAstNode n, Context c, CAstVisitor visitor) {
protected void leaveInstanceOf(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
WalkContext context = (WalkContext) c;
int result = getValue(n);
int result = context.getValue(n);
visit(n.getChild(0), context, visitor);
int value = getValue(n.getChild(0));
int value = context.getValue(n.getChild(0));
visit(n.getChild(1), context, visitor);
int type = getValue(n.getChild(1));
int type = context.getValue(n.getChild(1));
context.cfg().addInstruction(new JavaScriptInstanceOf(result, value, type));
}
@ -362,18 +359,18 @@ public class JSAstTranslator extends AstTranslator {
//context.cfg().addInstruction(((JSInstructionFactory) insts).PutInstruction(1, tempVal, "arguments"));
}
protected boolean doVisit(CAstNode n, Context cntxt, CAstVisitor visitor) {
protected boolean doVisit(CAstNode n, WalkContext cntxt, CAstVisitor<WalkContext> visitor) {
WalkContext context = (WalkContext) cntxt;
switch (n.getKind()) {
case CAstNode.TYPE_OF: {
int result = context.currentScope().allocateTempValue();
this.visit(n.getChild(0), context, this);
int ref = getValue(n.getChild(0));
int ref = context.getValue(n.getChild(0));
context.cfg().addInstruction(((JSInstructionFactory) insts).TypeOfInstruction(result, ref));
setValue(n, result);
context.setValue(n, result);
return true;
}
@ -381,7 +378,7 @@ public class JSAstTranslator extends AstTranslator {
case JavaScriptCAstNode.EXIT_WITH: {
this.visit(n.getChild(0), context, this);
int ref = getValue(n.getChild(0));
int ref = context.getValue(n.getChild(0));
context.cfg().addInstruction(((JSInstructionFactory) insts).WithRegion(ref, n.getKind() == JavaScriptCAstNode.ENTER_WITH));

View File

@ -0,0 +1,102 @@
package com.ibm.wala.cast.js.translator;
import com.ibm.wala.cast.ir.translator.ConstantFoldingRewriter;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.impl.CAstOperator;
public class JSConstantFoldingRewriter extends ConstantFoldingRewriter {
public JSConstantFoldingRewriter(CAst Ast) {
super(Ast);
}
@Override
protected Object eval(CAstOperator op, Object lhs, Object rhs) {
if (op == CAstOperator.OP_ADD) {
if (lhs instanceof String || rhs instanceof String) {
return "" + lhs + rhs;
} else if (lhs instanceof Number && rhs instanceof Number) {
return new Double(((Number)lhs).doubleValue() + ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_BIT_AND) {
} else if (op == CAstOperator.OP_BIT_OR) {
} else if (op == CAstOperator.OP_BIT_XOR) {
} else if (op == CAstOperator.OP_BITNOT) {
} else if (op == CAstOperator.OP_CONCAT) {
if (lhs instanceof String || rhs instanceof String) {
return "" + lhs + rhs;
}
} else if (op == CAstOperator.OP_DIV) {
if (lhs instanceof Number && rhs instanceof Number) {
return new Double(((Number)lhs).doubleValue() / ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_EQ) {
} else if (op == CAstOperator.OP_GE) {
if (lhs instanceof Number && rhs instanceof Number) {
return Boolean.valueOf(((Number)lhs).doubleValue() >= ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_GT) {
if (lhs instanceof Number && rhs instanceof Number) {
return Boolean.valueOf(((Number)lhs).doubleValue() > ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_LE) {
if (lhs instanceof Number && rhs instanceof Number) {
return Boolean.valueOf(((Number)lhs).doubleValue() <= ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_LSH) {
} else if (op == CAstOperator.OP_LT) {
if (lhs instanceof Number && rhs instanceof Number) {
return Boolean.valueOf(((Number)lhs).doubleValue() < ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_MOD) {
if (lhs instanceof Number && rhs instanceof Number) {
return new Double(((Number)lhs).doubleValue() % ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_MUL) {
if (lhs instanceof Number && rhs instanceof Number) {
return new Double(((Number)lhs).doubleValue() * ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_NE) {
} else if (op == CAstOperator.OP_NOT) {
} else if (op == CAstOperator.OP_REL_AND) {
} else if (op == CAstOperator.OP_REL_OR) {
} else if (op == CAstOperator.OP_REL_XOR) {
} else if (op == CAstOperator.OP_RSH) {
} else if (op == CAstOperator.OP_STRICT_EQ) {
} else if (op == CAstOperator.OP_STRICT_NE) {
} else if (op == CAstOperator.OP_SUB) {
if (lhs instanceof Number && rhs instanceof Number) {
return new Double(((Number)lhs).doubleValue() - ((Number)rhs).doubleValue());
}
} else if (op == CAstOperator.OP_URSH) {
}
// no constant value
return null;
}
}

View File

@ -0,0 +1,279 @@
package com.ibm.wala.cast.js.translator;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
import com.ibm.wala.cast.ir.translator.TranslatorToCAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.debug.Assertions;
public interface JavaScriptTranslatorToCAst extends TranslatorToCAst {
interface WalkContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.WalkContext<C, T> {
String script();
T top();
/**
* Add a name declaration to this context. For variables or constants, n
* should be a {@link CAstNode#DECL_STMT}, and the initialization of the
* variable (if any) may occur in a separate assignment. For functions, n
* should be a {@link CAstNode#FUNCTION_STMT}, including the function body.
*/
void addNameDecl(CAstNode n);
Collection<CAstNode> getNameDecls();
CAstNode getCatchTarget();
CAstNode getBaseVarIfRelevant(T node);
boolean foundBase(T node);
void updateBase(T from, T to);
}
public static class RootContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.RootContext<C, T> implements WalkContext<C,T> {
public String script() { return null; }
public T top() {
Assertions.UNREACHABLE();
return null;
}
public void addNameDecl(CAstNode v) {
Assertions.UNREACHABLE();
}
public Collection<CAstNode> getNameDecls() {
Assertions.UNREACHABLE();
return null;
}
public CAstNode getCatchTarget() {
Assertions.UNREACHABLE();
return null;
}
public CAstNode getBaseVarIfRelevant(T node) { return null; }
public boolean foundBase(T node) { return false; }
public void updateBase(T from, T to) { }
}
class DelegatingContext<C extends WalkContext<C, T>, T> extends TranslatorToCAst.DelegatingContext<C, T> implements WalkContext<C,T> {
protected DelegatingContext(C parent) {
super(parent);
}
public String script() {
return parent.script();
}
public T top() {
return parent.top();
}
public void addNameDecl(CAstNode n) {
parent.addNameDecl(n);
}
public Collection<CAstNode> getNameDecls() {
return parent.getNameDecls();
}
public CAstNode getCatchTarget() {
return parent.getCatchTarget();
}
public CAstNode getBaseVarIfRelevant(T node) {
return parent.getBaseVarIfRelevant(node);
}
public boolean foundBase(T node) {
return parent.foundBase(node);
}
public void updateBase(T from, T to) {
parent.updateBase(from, to);
}
}
public static class FunctionContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T topNode;
private final CAstSourcePositionRecorder pos = new CAstSourcePositionRecorder();
private final CAstControlFlowRecorder cfg = new CAstControlFlowRecorder(pos);
private final Map<CAstNode, Collection<CAstEntity>> scopedEntities = HashMapFactory.make();
private final Vector<CAstNode> initializers = new Vector<CAstNode>();
protected FunctionContext(C parent, T s) {
super(parent);
this.topNode = s;
}
@Override
public T top() { return topNode; }
@Override
public CAstNode getCatchTarget() { return CAstControlFlowMap.EXCEPTION_TO_EXIT; }
@Override
public void addScopedEntity(CAstNode construct, CAstEntity e) {
if (! scopedEntities.containsKey(construct)) {
scopedEntities.put(construct, new HashSet<CAstEntity>(1));
}
scopedEntities.get(construct).add(e);
}
@Override
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return scopedEntities;
}
@Override
public void addNameDecl(CAstNode v) { initializers.add(v); }
@Override
public Collection<CAstNode> getNameDecls() { return initializers; }
@Override
public CAstControlFlowRecorder cfg() { return cfg; }
@Override
public CAstSourcePositionRecorder pos() { return pos; }
}
public static class ScriptContext<C extends WalkContext<C, T>, T> extends FunctionContext<C,T> {
private final String script;
ScriptContext(C parent, T s, String script) {
super(parent, s);
this.script = script;
}
public String script() { return script; }
}
public static class TryCatchContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final CAstNode catchNode;
protected TryCatchContext(C parent, CAstNode catchNode) {
super(parent);
this.catchNode = catchNode;
}
public CAstNode getCatchTarget() { return catchNode; }
}
class BreakContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
private final T breakTarget;
protected final String label;
protected BreakContext(C parent, T breakTarget, String label) {
super(parent);
this.breakTarget = breakTarget;
this.label = label;
}
@Override
public T getBreakFor(String l) {
return ((l == null)? label==null: label.equals(l))? breakTarget: super.getBreakFor(l);
}
}
public class LoopContext<C extends WalkContext<C, T>, T> extends BreakContext<C,T> {
private final T continueTo;
protected LoopContext(C parent, T breakTo, T continueTo, String label) {
super(parent, breakTo, label);
this.continueTo = continueTo;
}
@Override
public T getContinueFor(String l) {
return ((l == null)? label==null: label.equals(l))? continueTo: super.getContinueFor(l);
}
}
/**
* Used to determine the value to be passed as the 'this' argument for a
* function call. This is needed since in JavaScript, you can write a call
* e(...) where e is some arbitrary expression, and in the case where e is a
* property access like e'.f, we must discover that the value of expression e'
* is passed as the 'this' parameter.
*
* The general strategy is to store the value of the expression passed as the
* 'this' parameter in baseVar, and then to use baseVar as the actual argument
* sub-node for the CAst call node
*/
public class BaseCollectingContext<C extends WalkContext<C, T>, T> extends DelegatingContext<C,T> {
/**
* node for which we actually care about what the base pointer is. this
* helps to handle cases like x.y.f(), where we would like to store x.y in
* baseVar, but not x when we recurse.
*/
private final Set<T> baseFor = new HashSet<T>();
/**
* the variable to be used to store the value of the expression passed as
* the 'this' parameter
*/
private final CAstNode baseVar;
/**
* have we discovered a value to be passed as the 'this' parameter?
*/
private boolean foundBase = false;
protected BaseCollectingContext(C parent, T initialBaseFor, CAstNode baseVar) {
super(parent);
baseFor.add( initialBaseFor );
this.baseVar = baseVar;
}
/**
* if node is one that we care about, return baseVar, and as a side effect
* set foundBase to true. Otherwise, return <code>null</code>.
*/
@Override
public CAstNode getBaseVarIfRelevant(T node) {
if (baseFor.contains( node )) {
foundBase = true;
return baseVar;
} else {
return null;
}
}
@Override
public boolean foundBase(T node) {
return foundBase;
}
/**
* if we currently care about the base pointer of from, switch to searching
* for the base pointer of to. Used for cases like comma expressions: if we
* have (x,y.f)(), we want to assign y to baseVar
*/
@Override
public void updateBase(T from, T to) {
if (baseFor.contains(from)) baseFor.add(to);
}
}
}

View File

@ -4,6 +4,7 @@ import java.util.Map;
import com.ibm.wala.cast.ir.translator.AstTranslator.InternalCAstSymbol;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstRewriter;
@ -207,15 +208,15 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
return result;
}
protected CAstNode copyNodes(CAstNode root, RewriteContext context, Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) {
protected CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, RewriteContext context, Map<Pair<CAstNode, ExpanderKey>, CAstNode> nodeMap) {
int kind = root.getKind();
if (kind == CAstNode.OBJECT_REF && context.inRead()) {
// if we see a property access (OBJECT_REF) in a read context, transform
// to a loop traversing the prototype chain
CAstNode readLoop;
CAstNode receiver = copyNodes(root.getChild(0), READ, nodeMap);
CAstNode element = copyNodes(root.getChild(1), READ, nodeMap);
CAstNode receiver = copyNodes(root.getChild(0), cfg, READ, nodeMap);
CAstNode element = copyNodes(root.getChild(1), cfg, READ, nodeMap);
if (element.getKind() == CAstNode.CONSTANT && element.getValue() instanceof String) {
readLoop = makeConstRead(root, receiver, element, context, nodeMap);
} else {
@ -227,9 +228,9 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
// handle cases like x.f++, represented as ASSIGN_POST_OP(x.f,1,+)
AssignPreOrPostOpContext ctxt = new AssignPreOrPostOpContext();
// generate loop for the first child (x.f for example), keeping the loop var and element var in ctxt
CAstNode lval = copyNodes(root.getChild(0), ctxt, nodeMap);
CAstNode rval = copyNodes(root.getChild(1), READ, nodeMap);
CAstNode op = copyNodes(root.getChild(2), READ, nodeMap);
CAstNode lval = copyNodes(root.getChild(0), cfg, ctxt, nodeMap);
CAstNode rval = copyNodes(root.getChild(1), cfg, READ, nodeMap);
CAstNode op = copyNodes(root.getChild(2), cfg, READ, nodeMap);
if (ctxt.receiverTemp != null) { // if we found a nested property access
String temp1 = TEMP_NAME + (readTempCounter++);
String temp2 = TEMP_NAME + (readTempCounter++);
@ -257,8 +258,8 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
} else if (kind == CAstNode.ASSIGN) {
// use ASSIGN context for LHS so we don't translate property accesses there
CAstNode copy = Ast.makeNode(CAstNode.ASSIGN, copyNodes(root.getChild(0), ASSIGN, nodeMap),
copyNodes(root.getChild(1), READ, nodeMap));
CAstNode copy = Ast.makeNode(CAstNode.ASSIGN, copyNodes(root.getChild(0), cfg, ASSIGN, nodeMap),
copyNodes(root.getChild(1), cfg, READ, nodeMap));
nodeMap.put(Pair.make(root, context.key()), copy);
return copy;
@ -266,9 +267,9 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
CAstNode children[] = new CAstNode[root.getChildCount()];
int last = (children.length - 1);
for (int i = 0; i < last; i++) {
children[i] = copyNodes(root.getChild(i), READ, nodeMap);
children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap);
}
children[last] = copyNodes(root.getChild(last), context, nodeMap);
children[last] = copyNodes(root.getChild(last), cfg, context, nodeMap);
CAstNode copy = Ast.makeNode(CAstNode.BLOCK_EXPR, children);
nodeMap.put(Pair.make(root, context.key()), copy);
@ -286,7 +287,12 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
} else {
CAstNode children[] = new CAstNode[root.getChildCount()];
for (int i = 0; i < children.length; i++) {
children[i] = copyNodes(root.getChild(i), READ, nodeMap);
children[i] = copyNodes(root.getChild(i), cfg, READ, nodeMap);
}
for(Object label: cfg.getTargetLabels(root)) {
if (label instanceof CAstNode) {
copyNodes((CAstNode)label, cfg, READ, nodeMap);
}
}
CAstNode copy = Ast.makeNode(kind, children);
nodeMap.put(Pair.make(root, context.key()), copy);

View File

@ -1,35 +0,0 @@
/******************************************************************************
* 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.translator;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import com.ibm.wala.classLoader.ModuleEntry;
import com.ibm.wala.classLoader.SourceFileModule;
public abstract class TranslatorBase {
public abstract void translate(ModuleEntry M, String N) throws IOException;
public void translate(List modules) throws IOException {
Iterator MS = modules.iterator();
while (MS.hasNext()) {
ModuleEntry M = (ModuleEntry) MS.next();
if (M instanceof SourceFileModule) {
translate(M, ((SourceFileModule) M).getClassName());
} else {
translate(M, M.getName());
}
}
}
}

View File

@ -277,11 +277,8 @@ public abstract class AstSSAPropagationCallGraphBuilder extends SSAPropagationCa
protected static class AstConstraintVisitor extends ConstraintVisitor implements AstInstructionVisitor {
private final CallGraph cg;
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
public AstConstraintVisitor(AstSSAPropagationCallGraphBuilder builder, CGNode node) {
super(builder, node);
this.cg = builder.callGraph;
}
protected AstSSAPropagationCallGraphBuilder getBuilder() {

View File

@ -61,7 +61,7 @@ public abstract class ScriptEntryPoints implements Iterable<Entrypoint> {
}
int functionVn = getMethod().isStatic()? -1: makeArgument(m, 0);
int paramVns[] = new int[Math.max(0, getNumberOfParameters() - 1)];
int paramVns[] = new int[Math.min(0, getNumberOfParameters() - 1)];
for (int j = 0; j < paramVns.length; j++) {
paramVns[j] = makeArgument(m, j + 1);
}

View File

@ -17,7 +17,6 @@ import java.net.URL;
import java.util.Collections;
import java.util.Iterator;
import com.ibm.wala.cast.ir.ssa.AstIRFactory;
import com.ibm.wala.cast.loader.SingleClassLoaderFactory;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.classLoader.Language;
@ -30,6 +29,7 @@ import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.IRFactory;
import com.ibm.wala.util.debug.Assertions;
public class Util {
@ -37,7 +37,7 @@ public class Util {
/**
* flag to prevent dumping of verbose call graph / pointer analysis output
*/
private static final boolean AVOID_DUMP = true;
public static boolean AVOID_DUMP = true;
public static SourceFileModule makeSourceModule(URL script, String dir, String name) {
// DO NOT use File.separator here, since this name is matched against
@ -73,8 +73,8 @@ public class Util {
return result;
}
public static AnalysisCache makeCache() {
return new AnalysisCache(AstIRFactory.makeDefaultFactory());
public static AnalysisCache makeCache(IRFactory<IMethod> factory) {
return new AnalysisCache(factory);
}
public static String getShortName(CGNode nd) {

View File

@ -36,6 +36,34 @@ public class AstIRFactory implements IRFactory {
return ((AstMethod) method).getControlFlowGraph();
}
public static class AstDefaultIRFactory extends DefaultIRFactory {
private final AstIRFactory astFactory;
public AstDefaultIRFactory() {
this(new AstIRFactory());
}
public AstDefaultIRFactory(AstIRFactory astFactory) {
this.astFactory = astFactory;
}
public IR makeIR(IMethod method, Context context, SSAOptions options) {
if (method instanceof AstMethod) {
return astFactory.makeIR(method, context, options);
} else {
return super.makeIR(method, context, options);
}
}
public ControlFlowGraph makeCFG(IMethod method, Context context) {
if (method instanceof AstMethod) {
return astFactory.makeCFG(method, context);
} else {
return super.makeCFG(method, context);
}
}
}
public class AstIR extends IR {
private final LexicalInformation lexicalInfo;
@ -101,7 +129,6 @@ public class AstIRFactory implements IRFactory {
public IR makeIR(final IMethod method, final Context context, final SSAOptions options) {
assert method instanceof AstMethod : method.toString();
// Pair<IMethod,Context> key = Pair.make(method, context);
AbstractCFG oldCfg = ((AstMethod) method).cfg();
SSAInstruction[] oldInstrs = (SSAInstruction[]) oldCfg.getInstructions();
@ -115,25 +142,7 @@ public class AstIRFactory implements IRFactory {
}
public static IRFactory<IMethod> makeDefaultFactory() {
return new DefaultIRFactory() {
private final AstIRFactory astFactory = new AstIRFactory();
public IR makeIR(IMethod method, Context context, SSAOptions options) {
if (method instanceof AstMethod) {
return astFactory.makeIR(method, context, options);
} else {
return super.makeIR(method, context, options);
}
}
public ControlFlowGraph makeCFG(IMethod method, Context context) {
if (method instanceof AstMethod) {
return astFactory.makeCFG(method, context);
} else {
return super.makeCFG(method, context);
}
}
};
return new AstDefaultIRFactory();
}
public boolean contextIsIrrelevant(IMethod method) {

View File

@ -0,0 +1,76 @@
package com.ibm.wala.cast.ir.translator;
import java.util.Map;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstBasicRewriter;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.util.collections.Pair;
public abstract class ConstantFoldingRewriter extends CAstBasicRewriter {
protected ConstantFoldingRewriter(CAst Ast) {
super(Ast, true);
}
protected abstract Object eval(CAstOperator op, Object lhs, Object rhs);
@Override
protected CAstNode copyNodes(CAstNode root,
CAstControlFlowMap cfg,
NonCopyingContext context,
Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap)
{
CAstNode result;
if (root.getKind() == CAstNode.BINARY_EXPR) {
CAstNode left = copyNodes(root.getChild(1), cfg, context, nodeMap);
CAstNode right = copyNodes(root.getChild(2), cfg, context, nodeMap);
Object v;
if (left.getKind() == CAstNode.CONSTANT && right.getKind() == CAstNode.CONSTANT && (v = eval((CAstOperator) root.getChild(0), left.getValue(), right.getValue())) != null) {
result = Ast.makeConstant(v);
} else {
result = Ast.makeNode(CAstNode.BINARY_EXPR, root.getChild(0), left, right);
}
} else if (root.getKind() == CAstNode.IF_EXPR || root.getKind() == CAstNode.IF_STMT) {
CAstNode expr = copyNodes(root.getChild(0), cfg, context, nodeMap);
if (expr.getKind() == CAstNode.CONSTANT && expr.getValue() == Boolean.TRUE) {
result = copyNodes(root.getChild(1), cfg, context, nodeMap);
} else if (expr.getKind() == CAstNode.CONSTANT && root.getChildCount() > 2 && expr.getValue() == Boolean.FALSE) {
result = copyNodes(root.getChild(2), cfg, context, nodeMap);
} else {
CAstNode then = copyNodes(root.getChild(1), cfg, context, nodeMap);
if (root.getChildCount() == 3) {
result = Ast.makeNode(root.getKind(), expr, then, copyNodes(root.getChild(2), cfg, context, nodeMap));
} else {
result = Ast.makeNode(root.getKind(), expr, then);
}
}
} else if (root.getKind() == CAstNode.CONSTANT) {
result = Ast.makeConstant(root.getValue());
} else if (root.getKind() == CAstNode.OPERATOR) {
result = root;
} else {
CAstNode children[] = new CAstNode[root.getChildCount()];
for (int i = 0; i < children.length; i++) {
children[i] = copyNodes(root.getChild(i), cfg, context, nodeMap);
}
for(Object label: cfg.getTargetLabels(root)) {
if (label instanceof CAstNode) {
copyNodes((CAstNode)label, cfg, context, nodeMap);
}
}
CAstNode copy = Ast.makeNode(root.getKind(), children);
result = copy;
}
nodeMap.put(Pair.make(root, context.key()), result);
return result;
}
}

View File

@ -1,15 +1,183 @@
package com.ibm.wala.cast.ir.translator;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.cast.tree.impl.CAstCloner;
import com.ibm.wala.cast.tree.impl.CAstControlFlowRecorder;
import com.ibm.wala.cast.tree.impl.CAstNodeTypeMapRecorder;
import com.ibm.wala.cast.tree.impl.CAstRewriter;
import com.ibm.wala.cast.tree.impl.CAstRewriter.CopyKey;
import com.ibm.wala.cast.tree.impl.CAstRewriter.RewriteContext;
import com.ibm.wala.cast.tree.impl.CAstRewriterFactory;
import com.ibm.wala.cast.tree.impl.CAstSourcePositionRecorder;
public interface TranslatorToCAst {
public <C extends RewriteContext<K>, K extends CopyKey<K>> void addRewriter(CAstRewriterFactory<C, K> factory, boolean prepend);
public CAstEntity translateToCAst() throws IOException;
public interface WalkContext<C extends WalkContext<C, T>, T> {
/**
* get a mapping from CAstNodes to the scoped entities (e.g. functions or
* local classes) introduced by those nodes. Also maps <code>null</code> to
* those entities not corresponding to any node (e.g nested classes)
*/
Map<CAstNode, Collection<CAstEntity>> getScopedEntities();
/**
* associate a child entity with a given CAstNode, e.g. for a function declaration
*/
void addScopedEntity(CAstNode newNode, CAstEntity visit);
/**
* for recording control-flow relationships among the CAst nodes
*/
CAstControlFlowRecorder cfg();
/**
* for recording source positions
*/
CAstSourcePositionRecorder pos();
/**
* for recording types of nodes
*/
CAstNodeTypeMapRecorder getNodeTypeMap();
/**
* for a 'continue' style goto, return the control flow target
*/
T getContinueFor(String label);
/**
* for a 'break' style goto, return the control flow target
*/
T getBreakFor(String label);
}
public class RootContext <C extends WalkContext<C, T>, T> implements WalkContext<C, T> {
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
assert false;
return Collections.emptyMap();
}
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
assert false;
}
public CAstControlFlowRecorder cfg() {
assert false;
return null;
}
public CAstSourcePositionRecorder pos() {
assert false;
return null;
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
assert false;
return null;
}
public T getContinueFor(String label) {
assert false;
return null;
}
public T getBreakFor(String label) {
assert false;
return null;
}
}
public class DelegatingContext<C extends WalkContext<C, T>, T> implements WalkContext<C, T> {
protected final C parent;
protected DelegatingContext(C parent) {
this.parent = parent;
}
public CAstControlFlowRecorder cfg() {
return parent.cfg();
}
public CAstSourcePositionRecorder pos() {
return parent.pos();
}
public CAstNodeTypeMapRecorder getNodeTypeMap() {
return parent.getNodeTypeMap();
}
public T getContinueFor(String label) {
return parent.getContinueFor(label);
}
public T getBreakFor(String label) {
return parent.getBreakFor(label);
}
public void addScopedEntity(CAstNode newNode, CAstEntity visit) {
parent.addScopedEntity(newNode, visit);
}
public Map<CAstNode, Collection<CAstEntity>> getScopedEntities() {
return parent.getScopedEntities();
}
}
public static class DoLoopTranslator {
private final boolean replicateForDoLoops;
private final CAst Ast;
public DoLoopTranslator(boolean replicateForDoLoops, CAst ast) {
this.replicateForDoLoops = replicateForDoLoops;
Ast = ast;
}
public CAstNode translateDoLoop(CAstNode loopTest, CAstNode loopBody, CAstNode continueNode, CAstNode breakNode, WalkContext<?,?> wc) {
if (replicateForDoLoops) {
loopBody = Ast.makeNode(CAstNode.BLOCK_STMT, loopBody, continueNode);
CAstRewriter.Rewrite x = (new CAstCloner(Ast, false)).copy(loopBody, wc.cfg(), wc.pos(), wc.getNodeTypeMap(), null);
CAstNode otherBody = x.newRoot();
wc.cfg().addAll(x.newCfg());
wc.pos().addAll(x.newPos());
wc.getNodeTypeMap().addAll(x.newTypes());
return Ast.makeNode(CAstNode.BLOCK_STMT,
loopBody,
Ast.makeNode(CAstNode.LOOP, loopTest, otherBody),
breakNode);
} else {
CAstNode header = Ast.makeNode(CAstNode.EMPTY);
CAstNode loopGoto = Ast.makeNode(CAstNode.IFGOTO, loopTest);
wc.cfg().map(header, header);
wc.cfg().map(loopGoto, loopGoto);
wc.cfg().add(loopGoto, header, Boolean.TRUE);
return Ast.makeNode(CAstNode.BLOCK_STMT,
header,
Ast.makeNode(CAstNode.BLOCK_STMT, loopBody, continueNode),
loopGoto,
breakNode);
}
}
};
}

View File

@ -10,7 +10,6 @@
*****************************************************************************/
package com.ibm.wala.cast.loader;
import java.io.InputStream;
import java.net.URL;
import java.util.Collection;
@ -30,6 +29,7 @@ import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.strings.Atom;
abstract public class AstFunctionClass implements IClass, ClassConstants {
private final IClassLoader loader;
protected IMethod functionBody;

View File

@ -12,7 +12,9 @@ package com.ibm.wala.cast.loader;
import java.util.Collection;
import com.ibm.wala.cast.ir.translator.AstTranslator;
import com.ibm.wala.cast.ir.translator.AstTranslator.AstLexicalInformation;
import com.ibm.wala.cast.tree.CAstEntity;
import com.ibm.wala.cast.tree.CAstQualifier;
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cfg.AbstractCFG;
@ -30,6 +32,11 @@ import com.ibm.wala.util.strings.Atom;
public abstract class AstMethod implements IMethod {
public interface Retranslatable {
void retranslate(AstTranslator xlator);
CAstEntity getEntity();
}
public interface DebuggingInformation {
Position getCodeBodyPosition();

View File

@ -111,6 +111,8 @@ public interface CAstNode {
public static final int MONITOR_ENTER = 23;
public static final int MONITOR_EXIT = 24;
public static final int ECHO = 25;
public static final int YIELD_STMT = 26;
public static final int FORIN_LOOP = 27;
// expression kinds
public static final int FUNCTION_EXPR = 100;

View File

@ -4,6 +4,7 @@ import java.util.HashMap;
import java.util.Map;
import com.ibm.wala.cast.tree.CAst;
import com.ibm.wala.cast.tree.CAstControlFlowMap;
import com.ibm.wala.cast.tree.CAstNode;
import com.ibm.wala.util.collections.Pair;
import com.ibm.wala.util.debug.Assertions;
@ -58,6 +59,6 @@ public abstract class CAstBasicRewriter
super(Ast, recursive, new NonCopyingContext());
}
protected abstract CAstNode copyNodes(CAstNode root, NonCopyingContext context, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap);
protected abstract CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext context, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap);
}

View File

@ -31,14 +31,14 @@ public class CAstCloner extends CAstBasicRewriter {
this(Ast, false);
}
protected CAstNode copyNodes(CAstNode root, NonCopyingContext c, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
return copyNodesHackForEclipse(root, c, nodeMap);
protected CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext c, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
return copyNodesHackForEclipse(root, cfg, c, nodeMap);
}
/**
* what is the hack here? --MS
*/
protected CAstNode copyNodesHackForEclipse(CAstNode root, NonCopyingContext c, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
protected CAstNode copyNodesHackForEclipse(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext c, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
if (root instanceof CAstOperator) {
nodeMap.put(Pair.make(root, c.key()), root);
return root;
@ -51,7 +51,7 @@ public class CAstCloner extends CAstBasicRewriter {
CAstNode newChildren[] = new CAstNode[root.getChildCount()];
for (int i = 0; i < root.getChildCount(); i++) {
newChildren[i] = copyNodes(root.getChild(i), c, nodeMap);
newChildren[i] = copyNodes(root.getChild(i), cfg, c, nodeMap);
}
CAstNode copy = Ast.makeNode(root.getKind(), newChildren);

View File

@ -140,6 +140,14 @@ public class CAstControlFlowRecorder implements CAstControlFlowMap {
assert from != null;
assert to != null;
if (CAstToNode.containsKey(to)) {
to = CAstToNode.get(to);
}
if (CAstToNode.containsKey(from)) {
from = CAstToNode.get(from);
}
table.put(new Key(label, from), to);
Set<Object> ls = labelMap.get(from);
@ -170,8 +178,12 @@ public class CAstControlFlowRecorder implements CAstControlFlowMap {
public void addAll(CAstControlFlowMap other) {
for (CAstNode n : other.getMappedNodes()) {
if (! CAstToNode.containsKey(n)) {
map(n, n);
}
for (Object l : other.getTargetLabels(n)) {
add(n, l, other.getTarget(n, l));
CAstNode to = other.getTarget(n, l);
add(n, to, l);
}
}
}

View File

@ -119,7 +119,7 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
* how (original node, copy key) pairs are mapped to nodes in the rewritten
* tree.
*/
protected abstract CAstNode copyNodes(CAstNode root, C context, Map<Pair<CAstNode, K>, CAstNode> nodeMap);
protected abstract CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, C context, Map<Pair<CAstNode, K>, CAstNode> nodeMap);
/**
* in {@link #copyFlow(Map, CAstControlFlowMap, CAstSourcePositionMap)}, if
@ -170,9 +170,9 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
if (oldSources.contains(oldSource)) {
Iterator<Object> LS = orig.getTargetLabels(oldSource).iterator();
if (orig.getTarget(oldSource, null) != null) {
LS = IteratorPlusOne.make(LS, null);
}
//if (orig.getTarget(oldSource, null) != null) {
// LS = IteratorPlusOne.make(LS, null);
//}
while (LS.hasNext()) {
Object origLabel = LS.next();
@ -238,7 +238,9 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
allNewTargetNodes.removeAll(newMap.getMappedNodes());
for (CAstNode newTarget : allNewTargetNodes) {
newMap.map(newTarget, newTarget);
if (newTarget != CAstControlFlowMap.EXCEPTION_TO_EXIT) {
newMap.map(newTarget, newTarget);
}
}
@ -341,7 +343,7 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
public Rewrite rewrite(final CAstNode root, final CAstControlFlowMap cfg, final CAstSourcePositionMap pos, final CAstNodeTypeMap types,
final Map<CAstNode, Collection<CAstEntity>> children) {
final Map<Pair<CAstNode, K>, CAstNode> nodes = HashMapFactory.make();
final CAstNode newRoot = copyNodes(root, rootContext, nodes);
final CAstNode newRoot = copyNodes(root, cfg, rootContext, nodes);
return new Rewrite() {
private CAstControlFlowMap theCfg = null;

View File

@ -53,12 +53,13 @@ public class CAstPrinter {
case CAstNode.LABEL_STMT: return "LABEL_STMT";
case CAstNode.IFGOTO: return "IFGOTO";
case CAstNode.EMPTY: return "EMPTY";
case CAstNode.RETURN_WITHOUT_BRANCH: return "RET_WO_BRANCH";
case CAstNode.YIELD_STMT: return "YIELD";
case CAstNode.CATCH: return "CATCH";
case CAstNode.UNWIND: return "UNWIND";
case CAstNode.MONITOR_ENTER: return "MONITOR_ENTER";
case CAstNode.MONITOR_EXIT: return "MONITOR_EXIT";
case CAstNode.ECHO: return "ECHO";
case CAstNode.FORIN_LOOP: return "FOR..IN";
// expression kinds
case CAstNode.FUNCTION_EXPR: return "FUNCTION_EXPR";
@ -85,8 +86,6 @@ public class CAstPrinter {
case CAstNode.ARRAY_REF: return "ARRAY_REF";
case CAstNode.ARRAY_LENGTH: return "ARRAY_LENGTH";
case CAstNode.TYPE_OF: return "TYPE_OF";
case CAstNode.EACH_ELEMENT_HAS_NEXT: return "EACH_ELEMENT_HAS_NEXT";
case CAstNode.EACH_ELEMENT_GET: return "EACH_ELEMENT_GET";
case CAstNode.LIST_EXPR: return "LIST_EXPR";
case CAstNode.EMPTY_LIST_EXPR: return "EMPTY_LIST_EXPR";
case CAstNode.IS_DEFINED_EXPR: return "IS_DEFINED_EXPR";

View File

@ -16,4 +16,20 @@ package com.ibm.wala.ipa.callgraph;
*/
public interface ContextItem {
public class Value<T> implements ContextItem {
private final T v;
public Value(T v) {
this.v = v;
}
public T getValue() {
return v;
}
public static <T> Value make(T v) {
return new Value<T>(v);
}
}
}