fixes for for ... in ... form in JavaScript

This commit is contained in:
Julian Dolby 2015-07-24 22:44:10 -04:00
parent 364fe7fa99
commit 563b6ba6aa
14 changed files with 74 additions and 104 deletions

View File

@ -590,12 +590,12 @@ public abstract class JavaSourceLoaderImpl extends ClassLoaderImpl {
}
@Override
public com.ibm.wala.cast.ir.ssa.EachElementGetInstruction EachElementGetInstruction(int iindex, int value, int objectRef) {
public com.ibm.wala.cast.ir.ssa.EachElementGetInstruction EachElementGetInstruction(int iindex, int value, int objectRef, int propRef) {
throw new UnsupportedOperationException();
}
@Override
public com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int value, int objectRef) {
public com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int value, int objectRef, int propRef) {
throw new UnsupportedOperationException();
}

View File

@ -107,7 +107,6 @@ import com.ibm.wala.cast.tree.CAstType;
import com.ibm.wala.cast.tree.impl.CAstOperator;
import com.ibm.wala.cast.tree.impl.CAstSymbolImpl;
import com.ibm.wala.cast.tree.visit.CAstVisitor;
import com.ibm.wala.cast.tree.visit.CAstVisitor.Context;
import com.ibm.wala.cast.util.CAstPattern;
import com.ibm.wala.classLoader.SourceModule;
import com.ibm.wala.util.collections.EmptyIterator;
@ -828,47 +827,46 @@ public class RhinoToAstTranslator {
CAstNode object = visit(node.getIteratedObject(), arg);
String tempName = "for in loop temp";
CAstNode[] loopHeader = new CAstNode[]{
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(tempName, JSAstTranslator.Any))),
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(tempName, JSAstTranslator.Any)), readName(arg, null, "$$undefined")),
Ast.makeNode(CAstNode.ASSIGN, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName)), object)
};
CAstNode initNode;
String name;
AstNode var = node.getIterator();
assert var instanceof Name || var instanceof VariableDeclaration || var instanceof LetNode : var.getClass() + " " + var;
if (var instanceof Name) {
name = ((Name)var).getString();
initNode =
Ast.makeNode(CAstNode.ASSIGN,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(((Name)var).getString())),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName))));
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(name)),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName)),
readName(arg, null, name)));
} else {
boolean isLet;
VariableDeclaration decl;
if (var instanceof LetNode) {
isLet = true;
decl = ((LetNode)var).getVariables();
} else {
isLet = false;
decl = (VariableDeclaration)var;
}
assert decl.getVariables().size() == 1;
VariableInitializer init = decl.getVariables().iterator().next();
if (isLet) {
initNode =
Ast.makeNode(CAstNode.DECL_STMT,
Ast.makeConstant(new CAstSymbolImpl(init.getTarget().getString(), JSAstTranslator.Any)),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName))));
} else {
arg.addNameDecl(
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(init.getTarget().getString(), JSAstTranslator.Any)),
readName(arg, null, "$$undefined")));
name = init.getTarget().getString();
arg.addNameDecl(
Ast.makeNode(CAstNode.DECL_STMT, Ast.makeConstant(new CAstSymbolImpl(name, JSAstTranslator.Any)),
readName(arg, null, "$$undefined")));
initNode =
Ast.makeNode(CAstNode.ASSIGN,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(name)),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName)),
readName(arg, null, name)));
initNode =
Ast.makeNode(CAstNode.ASSIGN,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(init.getTarget().getString())),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET, Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName))));
}
}
// body
@ -892,8 +890,12 @@ public class RhinoToAstTranslator {
loopHeader[1],
contLabel,
Ast.makeNode(CAstNode.LOOP,
Ast.makeNode(CAstNode.EACH_ELEMENT_HAS_NEXT,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName))),
Ast.makeNode(CAstNode.BINARY_EXPR,
CAstOperator.OP_NE,
Ast.makeConstant(null),
Ast.makeNode(CAstNode.EACH_ELEMENT_GET,
Ast.makeNode(CAstNode.VAR, Ast.makeConstant(tempName)),
readName(arg, null, name))),
body),
breakLabel));
arg.cfg().map(node, loop);

View File

@ -67,6 +67,7 @@ import com.ibm.wala.shrikeBT.BinaryOpInstruction;
import com.ibm.wala.shrikeBT.IUnaryOpInstruction;
import com.ibm.wala.ssa.DefUse;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
import com.ibm.wala.ssa.SSAAbstractInvokeInstruction;
import com.ibm.wala.ssa.SSABinaryOpInstruction;
import com.ibm.wala.ssa.SSAInstruction;
@ -731,7 +732,7 @@ public class JSSSAPropagationCallGraphBuilder extends AstSSAPropagationCallGraph
return node;
}
private SSABinaryOpInstruction getInstruction() {
private SSAAbstractBinaryInstruction getInstruction() {
return instruction;
}

View File

@ -125,7 +125,9 @@ public class JavaScriptFunctionApplyContextInterpreter extends AstContextInsensi
// read an arbitrary property name via EachElementGet
int curValNum = nargs + 2;
int eachElementGetResult = curValNum++;
S.addStatement(insts.EachElementGetInstruction(S.getNumberOfStatements(), eachElementGetResult, 4));
int nullPredVn = curValNum++;
S.addConstant(nullPredVn, new ConstantValue(null));
S.addStatement(insts.EachElementGetInstruction(S.getNumberOfStatements(), eachElementGetResult, 4, nullPredVn));
S.getNextProgramCounter();
// read value from the arbitrary property name
int propertyReadResult = curValNum++;

View File

@ -76,6 +76,7 @@ import com.ibm.wala.shrikeBT.IBinaryOpInstruction.IOperator;
import com.ibm.wala.shrikeBT.IComparisonInstruction.Operator;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
import com.ibm.wala.ssa.SSAAddressOfInstruction;
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
@ -283,13 +284,13 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
@Override
public com.ibm.wala.cast.ir.ssa.EachElementGetInstruction EachElementGetInstruction(int iindex, int value, int objectRef) {
return new EachElementGetInstruction(iindex, value, objectRef);
public com.ibm.wala.cast.ir.ssa.EachElementGetInstruction EachElementGetInstruction(int iindex, int value, int objectRef, int prevProp) {
return new EachElementGetInstruction(iindex, value, objectRef, prevProp);
}
@Override
public com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int value, int objectRef) {
return new EachElementHasNextInstruction(iindex, value, objectRef);
public com.ibm.wala.cast.ir.ssa.EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int value, int objectRef, int prop) {
return new EachElementHasNextInstruction(iindex, value, objectRef, prop);
}
@Override
@ -373,7 +374,7 @@ public class JavaScriptLoader extends CAstAbstractModuleLoader {
}
@Override
public SSABinaryOpInstruction BinaryOpInstruction(int iindex, IOperator operator, boolean overflow, boolean unsigned, int result,
public SSAAbstractBinaryInstruction BinaryOpInstruction(int iindex, IOperator operator, boolean overflow, boolean unsigned, int result,
int val1, int val2, boolean mayBeInteger) {
return new SSABinaryOpInstruction(iindex, operator, result, val1, val2, mayBeInteger) {
@Override

View File

@ -47,8 +47,8 @@ public interface AstInstructionFactory extends SSAInstructionFactory {
AstLexicalWrite LexicalWrite(int iindex, String definer, String globalName, TypeReference type, int rhs);
EachElementGetInstruction EachElementGetInstruction(int iindex, int lValue, int objectRef);
EachElementGetInstruction EachElementGetInstruction(int iindex, int lValue, int objectRef, int previousProp);
EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int lValue, int objectRef);
EachElementHasNextInstruction EachElementHasNextInstruction(int iindex, int lValue, int objectRef, int previousProp);
}

View File

@ -13,7 +13,7 @@ package com.ibm.wala.cast.ir.ssa;
import java.util.Collection;
import java.util.Collections;
import com.ibm.wala.ssa.SSAAbstractUnaryInstruction;
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SymbolTable;
@ -29,15 +29,15 @@ import com.ibm.wala.types.TypeReference;
*
* @author Julian Dolby (dolby@us.ibm.com)
*/
public class EachElementGetInstruction extends SSAAbstractUnaryInstruction {
public class EachElementGetInstruction extends SSAAbstractBinaryInstruction {
public EachElementGetInstruction(int iindex, int lValue, int objectRef) {
super(iindex, lValue, objectRef);
public EachElementGetInstruction(int iindex, int lValue, int objectRef, int previousProp) {
super(iindex, lValue, objectRef, previousProp);
}
@Override
public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) {
return ((AstInstructionFactory)insts).EachElementGetInstruction(iindex, (defs == null) ? getDef(0) : defs[0], (uses == null) ? getUse(0) : uses[0]);
return ((AstInstructionFactory)insts).EachElementGetInstruction(iindex, (defs == null) ? getDef(0) : defs[0], (uses == null) ? getUse(0) : uses[0], (uses == null) ? getUse(1) : uses[1]);
}
@Override
@ -54,4 +54,9 @@ public class EachElementGetInstruction extends SSAAbstractUnaryInstruction {
public Collection<TypeReference> getExceptionTypes() {
return Collections.emptySet();
}
@Override
public boolean isFallThrough() {
return true;
}
}

View File

@ -13,7 +13,7 @@ package com.ibm.wala.cast.ir.ssa;
import java.util.Collection;
import java.util.Collections;
import com.ibm.wala.ssa.SSAAbstractUnaryInstruction;
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstructionFactory;
import com.ibm.wala.ssa.SymbolTable;
@ -21,23 +21,22 @@ import com.ibm.wala.types.TypeReference;
/**
* This instruction represents iterating through the properties of its receiver object. The use represents an object,
* and the l-value represents a boolean indicating whether the object has more properties. This instruction does not
* currently take the previously-returned property as an argument, so it is a somewhat incomplete model as of now.
* and the l-value represents a boolean indicating whether the object has more properties.
*
* Iterating across the fields or properties of a given object is a common idiom in scripting languages, which is why
* the IR has first-class support for it.
*
* @author Julian Dolby (dolby@us.ibm.com)
*/
public class EachElementHasNextInstruction extends SSAAbstractUnaryInstruction {
public class EachElementHasNextInstruction extends SSAAbstractBinaryInstruction {
public EachElementHasNextInstruction(int iindex, int lValue, int objectRef) {
super(iindex, lValue, objectRef);
public EachElementHasNextInstruction(int iindex, int lValue, int objectRef, int previousPropVal) {
super(iindex, lValue, objectRef, previousPropVal);
}
@Override
public SSAInstruction copyForSSA(SSAInstructionFactory insts, int[] defs, int[] uses) {
return ((AstInstructionFactory)insts).EachElementHasNextInstruction(iindex, (defs == null) ? getDef(0) : defs[0], (uses == null) ? getUse(0) : uses[0]);
return ((AstInstructionFactory)insts).EachElementHasNextInstruction(iindex, (defs == null) ? getDef(0) : defs[0], (uses == null) ? getUse(0) : uses[0], (uses == null) ? getUse(1) : uses[1]);
}
@Override
@ -54,4 +53,9 @@ public class EachElementHasNextInstruction extends SSAAbstractUnaryInstruction {
public Collection<TypeReference> getExceptionTypes() {
return Collections.emptySet();
}
@Override
public boolean isFallThrough() {
return true;
}
}

View File

@ -4502,7 +4502,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
protected void leaveEachElementGet(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
int result = c.currentScope().allocateTempValue();
c.setValue(n, result);
c.cfg().addInstruction(new EachElementGetInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0))));
c.cfg().addInstruction(new EachElementGetInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0)), c.getValue(n.getChild(1))));
}
@Override
@ -4514,7 +4514,7 @@ public abstract class AstTranslator extends CAstVisitor<AstTranslator.WalkContex
protected void leaveEachElementHasNext(CAstNode n, WalkContext c, CAstVisitor<WalkContext> visitor) {
int result = c.currentScope().allocateTempValue();
c.setValue(n, result);
c.cfg().addInstruction(new EachElementHasNextInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0))));
c.cfg().addInstruction(new EachElementHasNextInstruction(c.cfg().currentInstruction, result, c.getValue(n.getChild(0)), c.getValue(n.getChild(1))));
}
@Override

View File

@ -807,6 +807,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
if (visitor.visitEachElementGet(n, context, visitor))
break;
visitor.visit(n.getChild(0), context, visitor);
visitor.visit(n.getChild(1), context, visitor);
visitor.leaveEachElementGet(n, context, visitor);
break;
}
@ -815,6 +816,7 @@ public abstract class CAstVisitor<C extends CAstVisitor.Context> {
if (visitor.visitEachElementHasNext(n, context, visitor))
break;
visitor.visit(n.getChild(0), context, visitor);
visitor.visit(n.getChild(1), context, visitor);
visitor.leaveEachElementHasNext(n, context, visitor);
break;
}

View File

@ -33,6 +33,7 @@ import com.ibm.wala.shrikeBT.Instruction;
import com.ibm.wala.shrikeCT.BootstrapMethodsReader.BootstrapMethod;
import com.ibm.wala.shrikeCT.ConstantPoolParser.ReferenceToken;
import com.ibm.wala.shrikeCT.InvalidClassFileException;
import com.ibm.wala.ssa.SSAAbstractBinaryInstruction;
import com.ibm.wala.ssa.SSAAddressOfInstruction;
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
@ -116,7 +117,7 @@ public class JavaLanguage extends LanguageImpl implements BytecodeLanguage, Cons
}
@Override
public SSABinaryOpInstruction BinaryOpInstruction(int iindex, IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned,
public SSAAbstractBinaryInstruction BinaryOpInstruction(int iindex, IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned,
int result, int val1, int val2, boolean mayBeInteger) {
assert !overflow;
// assert (!unsigned) : "BinaryOpInstuction: unsigned disallowed! iIndex: " + iindex + ", operation: " + val1 + " " + operator.toString() + " " + val2 ;

View File

@ -13,13 +13,7 @@ package com.ibm.wala.ssa;
import com.ibm.wala.shrikeBT.BinaryOpInstruction;
import com.ibm.wala.shrikeBT.IBinaryOpInstruction;
public abstract class SSABinaryOpInstruction extends SSAInstruction {
private final int result;
private final int val1;
private final int val2;
public abstract class SSABinaryOpInstruction extends SSAAbstractBinaryInstruction {
private final IBinaryOpInstruction.IOperator operator;
@ -29,10 +23,7 @@ public abstract class SSABinaryOpInstruction extends SSAInstruction {
private final boolean mayBeInteger;
protected SSABinaryOpInstruction(int iindex, IBinaryOpInstruction.IOperator operator, int result, int val1, int val2, boolean mayBeInteger) {
super(iindex);
this.result = result;
this.val1 = val1;
this.val2 = val2;
super(iindex, result, val1, val2);
this.operator = operator;
this.mayBeInteger = mayBeInteger;
if (val1 <= 0) {
@ -64,49 +55,6 @@ public abstract class SSABinaryOpInstruction extends SSAInstruction {
return operator;
}
@Override
public boolean hasDef() {
return true;
}
@Override
public int getDef() {
return result;
}
@Override
public int getDef(int i) {
assert i == 0;
return result;
}
/**
* @see com.ibm.wala.ssa.SSAInstruction#getNumberOfUses()
*/
@Override
public int getNumberOfDefs() {
return 1;
}
@Override
public int getNumberOfUses() {
return 2;
}
/**
* @see com.ibm.wala.ssa.SSAInstruction#getUse(int)
*/
@Override
public int getUse(int j) {
assert j <= 1;
return (j == 0) ? val1 : val2;
}
@Override
public int hashCode() {
return 6311 * result ^ 2371 * val1 + val2;
}
/*
* @see com.ibm.wala.ssa.Instruction#isPEI()
*/

View File

@ -38,7 +38,7 @@ public interface SSAInstructionFactory {
SSAArrayStoreInstruction ArrayStoreInstruction(int iindex, int arrayref, int index, int value, TypeReference declaredType);
SSABinaryOpInstruction BinaryOpInstruction(int iindex, IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned,
SSAAbstractBinaryInstruction BinaryOpInstruction(int iindex, IBinaryOpInstruction.IOperator operator, boolean overflow, boolean unsigned,
int result, int val1, int val2, boolean mayBeInteger);
SSACheckCastInstruction CheckCastInstruction(int iindex, int result, int val, int[] typeValues, boolean isPEI);

View File

@ -56,6 +56,10 @@ public final class MethodReference extends MemberReference {
public final static Selector clinitSelector = new Selector(clinitName, defaultInitDesc);
public final static Atom finalizeName = Atom.findOrCreateUnicodeAtom("finalize");
public final static Selector finalizeSelector = new Selector(finalizeName, defaultInitDesc);
public final static Atom runAtom = Atom.findOrCreateUnicodeAtom("run");
public final static Descriptor runDesc = Descriptor.findOrCreateUTF8(Language.JAVA, "()Ljava/lang/Object;");