comments
git-svn-id: https://wala.svn.sourceforge.net/svnroot/wala/trunk@4146 f5eafffb-2e1d-0410-98e4-8ec43c5233c4
This commit is contained in:
parent
d838a6c42f
commit
a1b36e3488
|
@ -25,14 +25,28 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
|
||||
abstract static class RewriteContext extends CAstBasicRewriter.NonCopyingContext {
|
||||
|
||||
/**
|
||||
* are we in a context where a property access should be treated as a read?
|
||||
* e.g., should return false if we are handling the LHS of an assignment
|
||||
*/
|
||||
abstract boolean inRead();
|
||||
|
||||
/**
|
||||
* are we handling a sub-node of an assignment?
|
||||
*/
|
||||
abstract boolean inAssignment();
|
||||
|
||||
/**
|
||||
* @see AssignPreOrPostOpContext
|
||||
*/
|
||||
abstract void setAssign(CAstNode receiverTemp, CAstNode elementTemp);
|
||||
}
|
||||
|
||||
private final class AssignOpContext extends RewriteContext {
|
||||
/**
|
||||
* for handling property reads within assignments with pre or post-ops, e.g.,
|
||||
* x.f++
|
||||
*/
|
||||
private final class AssignPreOrPostOpContext extends RewriteContext {
|
||||
private CAstNode receiverTemp;
|
||||
|
||||
private CAstNode elementTemp;
|
||||
|
@ -45,6 +59,11 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* store the CAstNodes used to represent the loop variable for the
|
||||
* prototype-chain traversal (receiverTemp) and the desired property
|
||||
* (elementTemp)
|
||||
*/
|
||||
public void setAssign(CAstNode receiverTemp, CAstNode elementTemp) {
|
||||
this.receiverTemp = receiverTemp;
|
||||
this.elementTemp = elementTemp;
|
||||
|
@ -84,6 +103,18 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
super(Ast, true, READ);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a CAstNode l representing a loop that traverses the prototype chain
|
||||
* from receiver searching for the constant property element. update nodeMap
|
||||
* to map root to an expression that reads the property from the right node.
|
||||
*
|
||||
* @param root
|
||||
* @param receiver
|
||||
* @param element
|
||||
* @param context
|
||||
* @param nodeMap
|
||||
* @return
|
||||
*/
|
||||
private CAstNode makeConstRead(CAstNode root, CAstNode receiver, CAstNode element, RewriteContext context,
|
||||
Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
|
||||
CAstNode get, result;
|
||||
|
@ -100,14 +131,17 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
result = Ast
|
||||
.makeNode(
|
||||
CAstNode.BLOCK_EXPR,
|
||||
// declare loop variable and initialize to the receiver
|
||||
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(receiverTemp, false, false)), receiver),
|
||||
Ast.makeNode(
|
||||
CAstNode.LOOP,
|
||||
Ast.makeNode(CAstNode.LOOP,
|
||||
// while the desired property of the loop variable is not
|
||||
// defined...
|
||||
Ast.makeNode(
|
||||
CAstNode.UNARY_EXPR,
|
||||
CAstOperator.OP_NOT,
|
||||
Ast.makeNode(CAstNode.IS_DEFINED_EXPR, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
||||
Ast.makeConstant(elt))),
|
||||
// set the loop variable to be its prototype
|
||||
Ast.makeNode(
|
||||
CAstNode.ASSIGN,
|
||||
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(receiverTemp)),
|
||||
|
@ -122,6 +156,12 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* similar to makeConstRead(), but desired property is some expression instead
|
||||
* of a constant
|
||||
*
|
||||
* @see #makeConstRead(CAstNode, CAstNode, CAstNode, RewriteContext, Map)
|
||||
*/
|
||||
private CAstNode makeVarRead(CAstNode root, CAstNode receiver, CAstNode element, RewriteContext context,
|
||||
Map<Pair<CAstNode, NoKey>, CAstNode> nodeMap) {
|
||||
String receiverTemp = TEMP_NAME + (readTempCounter++);
|
||||
|
@ -157,10 +197,12 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
return result;
|
||||
}
|
||||
|
||||
protected CAstNode copyNodes(CAstNode root, RewriteContext context, Map<Pair<CAstNode,NoKey>, CAstNode> nodeMap) {
|
||||
protected CAstNode copyNodes(CAstNode root, RewriteContext context, Map<Pair<CAstNode, NoKey>, 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);
|
||||
|
@ -172,21 +214,28 @@ public class PropertyReadExpander extends CAstRewriter<PropertyReadExpander.Rewr
|
|||
return readLoop;
|
||||
|
||||
} else if (kind == CAstNode.ASSIGN_PRE_OP || kind == CAstNode.ASSIGN_POST_OP) {
|
||||
AssignOpContext ctxt = new AssignOpContext();
|
||||
// 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);
|
||||
if (ctxt.receiverTemp != null) {
|
||||
if (ctxt.receiverTemp != null) { // if we found a nested property access
|
||||
String temp1 = TEMP_NAME + (readTempCounter++);
|
||||
String temp2 = TEMP_NAME + (readTempCounter++);
|
||||
CAstNode copy = Ast.makeNode(
|
||||
CAstNode.BLOCK_EXPR,
|
||||
// assign lval to temp1 (where lval is a block that includes the prototype chain loop)
|
||||
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(temp1, true, false)), lval),
|
||||
// ? --MS
|
||||
rval,
|
||||
// assign temp2 the new value to be assigned
|
||||
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new InternalCAstSymbol(temp2, true, false)),
|
||||
Ast.makeNode(CAstNode.BINARY_EXPR, op, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp1)), rval)),
|
||||
// write temp2 into the property
|
||||
Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.OBJECT_REF, ctxt.receiverTemp, ctxt.elementTemp),
|
||||
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(temp2))),
|
||||
// final value depends on whether we had a pre op or post op
|
||||
Ast.makeNode(CAstNode.VAR, Ast.makeConstant((kind == CAstNode.ASSIGN_PRE_OP) ? temp2 : temp1)));
|
||||
nodeMap.put(Pair.make(root, context.key()), copy);
|
||||
return copy;
|
||||
|
@ -197,6 +246,7 @@ 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));
|
||||
nodeMap.put(Pair.make(root, context.key()), copy);
|
||||
|
|
|
@ -97,7 +97,8 @@ public abstract class CAstRewriter<C extends CAstRewriter.RewriteContext<K>, K e
|
|||
|
||||
/**
|
||||
* rewrite the CAst rooted at root, updating nodeMap with a mapping from
|
||||
* (original node,key) pairs to new nodes
|
||||
* (original node,key) pairs to new nodes. Return the node to which root was
|
||||
* mapped by the call.
|
||||
*/
|
||||
protected abstract CAstNode copyNodes(CAstNode root, C context, Map<Pair<CAstNode, K>, CAstNode> nodeMap);
|
||||
|
||||
|
|
Loading…
Reference in New Issue