ast-based constant folding
This commit is contained in:
parent
bc4939db97
commit
27a8fff714
|
@ -27,6 +27,7 @@ import com.ibm.wala.cast.tree.CAstEntity;
|
|||
import com.ibm.wala.cast.tree.CAstNode;
|
||||
import com.ibm.wala.cast.tree.impl.CAstImpl;
|
||||
import com.ibm.wala.cast.tree.rewrite.CAstBasicRewriter;
|
||||
import com.ibm.wala.cast.tree.rewrite.CAstBasicRewriter.NonCopyingContext;
|
||||
import com.ibm.wala.cast.util.CAstPattern;
|
||||
import com.ibm.wala.cast.util.CAstPattern.Segments;
|
||||
import com.ibm.wala.cfg.AbstractCFG;
|
||||
|
@ -183,12 +184,12 @@ public class ArgumentSpecialization {
|
|||
if (v != null) {
|
||||
final JavaScriptLoader myloader = (JavaScriptLoader) method.getDeclaringClass().getClassLoader();
|
||||
|
||||
class FixedArgumentsRewriter extends CAstBasicRewriter {
|
||||
class FixedArgumentsRewriter extends CAstBasicRewriter<NonCopyingContext> {
|
||||
private final CAstEntity e;
|
||||
private final Map<String, CAstNode> argRefs = HashMapFactory.make();
|
||||
|
||||
public FixedArgumentsRewriter(CAst Ast) {
|
||||
super(Ast, false);
|
||||
super(Ast, new NonCopyingContext(), false);
|
||||
this.e = m.getEntity();
|
||||
for(Segments s : CAstPattern.findAll(destructuredAccessPattern, m.getEntity())) {
|
||||
argRefs.put(s.getSingle("name").getValue().toString(), s.getSingle("value"));
|
||||
|
|
|
@ -0,0 +1,192 @@
|
|||
package com.ibm.wala.cast.test;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import com.ibm.wala.cast.tree.CAst;
|
||||
import com.ibm.wala.cast.tree.CAstAnnotation;
|
||||
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.CAstNodeTypeMap;
|
||||
import com.ibm.wala.cast.tree.CAstQualifier;
|
||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
|
||||
import com.ibm.wala.cast.tree.CAstType;
|
||||
import com.ibm.wala.cast.tree.impl.CAstImpl;
|
||||
import com.ibm.wala.cast.tree.impl.CAstOperator;
|
||||
import com.ibm.wala.cast.tree.rewrite.AstConstantFolder;
|
||||
import com.ibm.wala.cast.util.AstConstantCollector;
|
||||
import com.ibm.wala.cast.util.CAstPattern;
|
||||
import com.ibm.wala.cast.util.CAstPattern.Segments;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
|
||||
public class TestConstantCollector {
|
||||
|
||||
private CAst ast = new CAstImpl();
|
||||
|
||||
private static CAstEntity fakeEntity(CAstNode root) {
|
||||
return new CAstEntity() {
|
||||
|
||||
@Override
|
||||
public int getKind() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSignature() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getArgumentNames() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstNode[] getArgumentDefaults() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getArgumentCount() {
|
||||
// TODO Auto-generated method stub
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
|
||||
return EmptyIterator.instance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstNode getAST() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstControlFlowMap getControlFlow() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstSourcePositionMap getSourceMap() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstNodeTypeMap getNodeTypeMap() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CAstQualifier> getQualifiers() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstType getType() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<CAstAnnotation> getAnnotations() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private CAstNode root1 =
|
||||
ast.makeNode(CAstNode.BLOCK_STMT,
|
||||
ast.makeNode(CAstNode.ASSIGN,
|
||||
ast.makeNode(CAstNode.VAR,
|
||||
ast.makeConstant("var1")),
|
||||
ast.makeConstant(15)));
|
||||
|
||||
@Test
|
||||
public void testSegmentsRoot1() {
|
||||
Collection<Segments> x = CAstPattern.findAll(AstConstantCollector.simpleValuePattern, fakeEntity(root1));
|
||||
assert x.size() == 1;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot1() {
|
||||
Map<String,Object> x = AstConstantCollector.collectConstants(fakeEntity(root1));
|
||||
assert x.size() == 1;
|
||||
}
|
||||
|
||||
private CAstNode root2 =
|
||||
ast.makeNode(CAstNode.BLOCK_STMT,
|
||||
ast.makeNode(CAstNode.ASSIGN,
|
||||
ast.makeNode(CAstNode.VAR,
|
||||
ast.makeConstant("var1")),
|
||||
ast.makeConstant(15)),
|
||||
ast.makeNode(CAstNode.ASSIGN,
|
||||
ast.makeNode(CAstNode.VAR,
|
||||
ast.makeConstant("var1")),
|
||||
ast.makeConstant(14)));
|
||||
|
||||
@Test
|
||||
public void testSegmentsRoot2() {
|
||||
Collection<Segments> x = CAstPattern.findAll(AstConstantCollector.simpleValuePattern, fakeEntity(root2));
|
||||
assert x.size() == 2;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot2() {
|
||||
Map<String,Object> x = AstConstantCollector.collectConstants(fakeEntity(root2));
|
||||
assert x.size() == 0;
|
||||
}
|
||||
|
||||
private CAstNode root3 =
|
||||
ast.makeNode(CAstNode.BLOCK_EXPR,
|
||||
ast.makeNode(CAstNode.ASSIGN,
|
||||
ast.makeNode(CAstNode.VAR,
|
||||
ast.makeConstant("var1")),
|
||||
ast.makeConstant(15)),
|
||||
ast.makeNode(CAstNode.BINARY_EXPR,
|
||||
CAstOperator.OP_ADD,
|
||||
ast.makeConstant(10),
|
||||
ast.makeNode(CAstNode.VAR, ast.makeConstant("var1"))));
|
||||
|
||||
public static final CAstPattern toCodePattern3 = CAstPattern.parse("BINARY_EXPR(*,\"10\",\"15\")");
|
||||
|
||||
@Test
|
||||
public void testRoot3() {
|
||||
CAstEntity ce = fakeEntity(root3);
|
||||
CAstEntity nce = AstConstantFolder.fold(ce);
|
||||
Collection<Segments> matches = CAstPattern.findAll(toCodePattern3, nce);
|
||||
assert matches.size() == 1;
|
||||
}
|
||||
}
|
|
@ -4604,7 +4604,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
|
|||
nodeMap.put(Pair.make(root, c.key()), expr);
|
||||
return expr;
|
||||
} else {
|
||||
return super.copyNodesHackForEclipse(root, cfg, c, nodeMap);
|
||||
return super.copyNodes(root, cfg, c, nodeMap);
|
||||
}
|
||||
}
|
||||
}).rewrite(included);
|
||||
|
|
|
@ -17,12 +17,13 @@ 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.rewrite.CAstBasicRewriter;
|
||||
import com.ibm.wala.cast.tree.rewrite.CAstBasicRewriter.NonCopyingContext;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
|
||||
public abstract class ConstantFoldingRewriter extends CAstBasicRewriter {
|
||||
public abstract class ConstantFoldingRewriter extends CAstBasicRewriter<NonCopyingContext> {
|
||||
|
||||
protected ConstantFoldingRewriter(CAst Ast) {
|
||||
super(Ast, true);
|
||||
super(Ast, new NonCopyingContext(), true);
|
||||
}
|
||||
|
||||
protected abstract Object eval(CAstOperator op, Object lhs, Object rhs);
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
package com.ibm.wala.cast.tree.rewrite;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.CAstNodeTypeMap;
|
||||
import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
||||
import com.ibm.wala.cast.tree.impl.CAstImpl;
|
||||
import com.ibm.wala.cast.tree.impl.DelegatingEntity;
|
||||
import com.ibm.wala.cast.tree.rewrite.CAstBasicRewriter.NonCopyingContext;
|
||||
import com.ibm.wala.cast.tree.rewrite.CAstRewriter.Rewrite;
|
||||
import com.ibm.wala.cast.util.AstConstantCollector;
|
||||
import com.ibm.wala.util.collections.EmptyIterator;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
|
||||
public class AstConstantFolder {
|
||||
static class AssignSkipContext extends NonCopyingContext {
|
||||
private Set<CAstNode> skip = HashSetFactory.make();
|
||||
}
|
||||
|
||||
public static CAstEntity fold(CAstEntity ce) {
|
||||
Map<String,Object> constants = AstConstantCollector.collectConstants(ce);
|
||||
if (constants.isEmpty()) {
|
||||
return ce;
|
||||
} else {
|
||||
Rewrite nce = new CAstCloner(new CAstImpl(), new AssignSkipContext(), true) {
|
||||
|
||||
@Override
|
||||
protected CAstNode copyNodes(CAstNode root, CAstControlFlowMap cfg, NonCopyingContext c,
|
||||
Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
|
||||
|
||||
if (root.getKind() == CAstNode.ASSIGN) {
|
||||
((AssignSkipContext)c).skip.add(root.getChild(0));
|
||||
}
|
||||
|
||||
if (root.getKind() == CAstNode.VAR && constants.containsKey(root.getChild(0).getValue()) && ! ((AssignSkipContext)c).skip.contains(root)) {
|
||||
return Ast.makeConstant(constants.get(root.getChild(0).getValue()));
|
||||
} else {
|
||||
return super.copyNodes(root, cfg, c, nodeMap);
|
||||
}
|
||||
}
|
||||
|
||||
}.rewrite(ce.getAST(), ce.getControlFlow(), ce.getSourceMap(), ce.getNodeTypeMap(), ce.getAllScopedEntities());
|
||||
return new DelegatingEntity(ce) {
|
||||
|
||||
@Override
|
||||
public CAstNode getAST() {
|
||||
return nce.newRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstControlFlowMap getControlFlow() {
|
||||
return nce.newCfg();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstSourcePositionMap getSourceMap() {
|
||||
return nce.newPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CAstNodeTypeMap getNodeTypeMap() {
|
||||
return nce.newTypes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<CAstNode, Collection<CAstEntity>> getAllScopedEntities() {
|
||||
return nce.newChildren();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<CAstEntity> getScopedEntities(CAstNode construct) {
|
||||
Collection<CAstEntity> children = nce.newChildren().get(construct);
|
||||
return children==null? EmptyIterator.instance(): children.iterator();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,8 +23,8 @@ import com.ibm.wala.util.debug.Assertions;
|
|||
* abstract base class for {@link CAstRewriter}s that do no cloning of nodes
|
||||
*
|
||||
*/
|
||||
public abstract class CAstBasicRewriter
|
||||
extends CAstRewriter<CAstBasicRewriter.NonCopyingContext,
|
||||
public abstract class CAstBasicRewriter<T extends CAstBasicRewriter.NonCopyingContext>
|
||||
extends CAstRewriter<T,
|
||||
CAstBasicRewriter.NoKey>
|
||||
{
|
||||
|
||||
|
@ -69,11 +69,11 @@ public abstract class CAstBasicRewriter
|
|||
}
|
||||
}
|
||||
|
||||
protected CAstBasicRewriter(CAst Ast, boolean recursive) {
|
||||
super(Ast, recursive, new NonCopyingContext());
|
||||
protected CAstBasicRewriter(CAst Ast, T context, boolean recursive) {
|
||||
super(Ast, recursive, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, NonCopyingContext context, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap);
|
||||
protected abstract CAstNode copyNodes(CAstNode root, final CAstControlFlowMap cfg, T context, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap);
|
||||
|
||||
}
|
||||
|
|
|
@ -22,25 +22,22 @@ import com.ibm.wala.cast.tree.CAstSourcePositionMap;
|
|||
import com.ibm.wala.cast.tree.impl.CAstOperator;
|
||||
import com.ibm.wala.util.collections.Pair;
|
||||
|
||||
public class CAstCloner extends CAstBasicRewriter {
|
||||
public class CAstCloner extends CAstBasicRewriter<CAstBasicRewriter.NonCopyingContext> {
|
||||
|
||||
public CAstCloner(CAst Ast, boolean recursive) {
|
||||
super(Ast, recursive);
|
||||
this(Ast, new NonCopyingContext(), recursive);
|
||||
}
|
||||
|
||||
public CAstCloner(CAst Ast) {
|
||||
this(Ast, false);
|
||||
}
|
||||
|
||||
protected CAstCloner(CAst Ast, NonCopyingContext context, boolean recursive) {
|
||||
super(Ast, context, recursive);
|
||||
}
|
||||
|
||||
@Override
|
||||
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, final CAstControlFlowMap cfg, NonCopyingContext c, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
|
||||
final Pair<CAstNode, NoKey> pairKey = Pair.make(root, c.key());
|
||||
if (root instanceof CAstOperator) {
|
||||
nodeMap.put(pairKey, root);
|
||||
|
|
|
@ -361,7 +361,7 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
|
|||
|
||||
@Override
|
||||
public CAstControlFlowMap newCfg() {
|
||||
if (theCfg == null)
|
||||
if (theCfg == null && cfg != null)
|
||||
theCfg = copyFlow(nodes, cfg, newPos());
|
||||
return theCfg;
|
||||
}
|
||||
|
@ -375,7 +375,7 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
|
|||
|
||||
@Override
|
||||
public CAstNodeTypeMap newTypes() {
|
||||
if (theTypes == null)
|
||||
if (theTypes == null && types != null)
|
||||
theTypes = copyTypes(nodes, types);
|
||||
return theTypes;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package com.ibm.wala.cast.util;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.ibm.wala.cast.tree.CAstEntity;
|
||||
import com.ibm.wala.cast.tree.CAstNode;
|
||||
import com.ibm.wala.cast.util.CAstPattern.Segments;
|
||||
import com.ibm.wala.util.collections.HashMapFactory;
|
||||
import com.ibm.wala.util.collections.HashSetFactory;
|
||||
|
||||
public class AstConstantCollector {
|
||||
|
||||
public static final CAstPattern simplePreUpdatePattern = CAstPattern.parse("ASSIGN_PRE_OP(VAR(<name>CONSTANT()),**)");
|
||||
|
||||
public static final CAstPattern simplePostUpdatePattern = CAstPattern.parse("ASSIGN_POST_OP(VAR(<name>CONSTANT()),**)");
|
||||
|
||||
public static final CAstPattern simpleValuePattern = CAstPattern.parse("ASSIGN(VAR(<name>CONSTANT()),<value>*)");
|
||||
|
||||
public static Map<String,Object> collectConstants(CAstEntity function, Map<String,Object> values) {
|
||||
if (function.getAST() != null) {
|
||||
Set<String> bad = HashSetFactory.make();
|
||||
for(Segments s : CAstPattern.findAll(simplePreUpdatePattern, function)) {
|
||||
bad.add((String) s.getSingle("name").getValue());
|
||||
}
|
||||
for(Segments s : CAstPattern.findAll(simplePostUpdatePattern, function)) {
|
||||
bad.add((String) s.getSingle("name").getValue());
|
||||
}
|
||||
for(Segments s : CAstPattern.findAll(simpleValuePattern, function)) {
|
||||
String var = (String) s.getSingle("name").getValue();
|
||||
if (s.getSingle("value").getKind() != CAstNode.CONSTANT) {
|
||||
bad.add(var);
|
||||
} else {
|
||||
Object val = s.getSingle("value").getValue();
|
||||
if (! bad.contains(var)) {
|
||||
if (values.containsKey(var)) {
|
||||
if (!values.get(var).equals(val)) {
|
||||
values.remove(var);
|
||||
bad.add(var);
|
||||
}
|
||||
} else {
|
||||
values.put(var, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(Collection<CAstEntity> ces : function.getAllScopedEntities().values()) {
|
||||
for(CAstEntity ce : ces) {
|
||||
collectConstants(ce, values);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static Map<String,Object> collectConstants(CAstEntity function) {
|
||||
Map<String,Object> values = HashMapFactory.make();
|
||||
collectConstants(function, values);
|
||||
return values;
|
||||
}
|
||||
}
|
|
@ -408,6 +408,13 @@ public class CAstPattern {
|
|||
visit(top, c, this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean doVisit(CAstNode n, Context context, CAstVisitor<Context> visitor) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static class Parser {
|
||||
|
|
|
@ -3,6 +3,5 @@ source.. = src/,\
|
|||
output.. = bin/test
|
||||
bin.includes = META-INF/,\
|
||||
.,\
|
||||
plugin.xml,\
|
||||
plugin.properties
|
||||
plugin.properties
|
||||
javacProjectSettings = true
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<?eclipse version="3.2"?>
|
||||
<!DOCTYPE plugin>
|
||||
<plugin>
|
||||
<extension id="HeadlessWALA"
|
||||
point="org.eclipse.core.runtime.applications">
|
||||
<application>
|
||||
<run class="com.ibm.wala.eclipse.headless.Main"/>
|
||||
</application>
|
||||
</extension>
|
||||
</plugin>
|
|
@ -118,7 +118,7 @@ public class AnalysisScope {
|
|||
*/
|
||||
private SetOfClasses exclusions;
|
||||
|
||||
final protected LinkedHashMap<Atom, ClassLoaderReference> loadersByName = new LinkedHashMap<>();
|
||||
public final LinkedHashMap<Atom, ClassLoaderReference> loadersByName = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Special class loader for array instances
|
||||
|
|
Loading…
Reference in New Issue