00001 package ca.mcgill.sable.soot.jimple;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 import ca.mcgill.sable.soot.*;
00100 import ca.mcgill.sable.soot.jimple.*;
00101 import ca.mcgill.sable.util.*;
00102 import java.util.Enumeration;
00103 import java.util.Vector;
00104 import java.util.BitSet;
00105 import java.util.Hashtable;
00106
00107
00108
00109
00110 class TypeResolver
00111 {
00112 private static final boolean DEBUG = false;
00113
00114
00115 ClassHierarchy classHierarchy;
00116
00117
00118 SootMethod currentMethod;
00119
00120 static String lastClass;
00121
00122 Vector typeVariableInstances = new Vector();
00123
00124
00125 private Hashtable typeVariableHashtable = new Hashtable();
00126
00127
00128 private Hashtable typeVariableStringHashtable = new Hashtable();
00129
00130
00131 private ConstraintCollector constraintCollector = new ConstraintCollector();
00132
00133
00134 IntSet unresolvedTypeVariables = new IntSet();
00135
00136
00137 boolean new_relation;
00138
00139 private JimpleBody stmtBody;
00140
00141
00142 class TypeVariable
00143 {
00144
00145 private int id;
00146
00147 IntSet parents = new IntSet();
00148 IntSet children = new IntSet();
00149
00150 private ClassHierarchy.TypeNode typeNode;
00151
00152 private boolean cannotBeInt;
00153 private boolean cannotBeLong;
00154 private boolean cannotBeFloat;
00155 private boolean cannotBeDouble;
00156 private boolean cannotBeAddress;
00157 private boolean cannotBeRef;
00158
00159 TypeVariable isArrayOf;
00160 IntSet isElementOf = new IntSet();
00161 int arrayDepth;
00162 TypeVariable base;
00163 int count;
00164
00165 private TypeVariable rep = this;
00166 private int rank = 0;
00167
00168 private BitSet ancestors = new BitSet();
00169
00170 TypeVariable()
00171 {
00172 id = typeVariableInstances.size();
00173 typeVariableInstances.addElement(this);
00174 unresolvedTypeVariables.set(id);
00175 }
00176
00177 TypeVariable(Local local)
00178 {
00179 this();
00180 typeVariableHashtable.put(local, this);
00181 typeVariableStringHashtable.put(this, local.toString());
00182 }
00183
00184 TypeVariable(ClassHierarchy.TypeNode typeNode)
00185 {
00186 this();
00187 typeVariableHashtable.put(typeNode, this);
00188 typeVariableStringHashtable.put(this, typeNode.toString());
00189 this.typeNode = typeNode;
00190 unresolvedTypeVariables.clear(id);
00191
00192 if(typeNode.getType() instanceof ArrayType)
00193 {
00194 ArrayType type = (ArrayType) typeNode.getType();
00195
00196 if(type.numDimensions > 1)
00197 {
00198 new_relation = true;
00199 getTypeVariable(
00200 ArrayType.v(type.baseType,
00201 type.numDimensions - 1)).ecrUnion(
00202 getEcrIsArrayOf());
00203 }
00204 else
00205 {
00206 new_relation = true;
00207 getTypeVariable(type.baseType).ecrUnion(
00208 getEcrIsArrayOf());
00209 }
00210 }
00211 }
00212
00213 TypeVariable ecr()
00214 {
00215 if(rep != this)
00216 {
00217 rep = rep.ecr();
00218 }
00219
00220 return rep;
00221 }
00222
00223 TypeVariable ecrUnion(TypeVariable var)
00224 {
00225 new_relation = true;
00226
00227 TypeVariable x = ecr();
00228 TypeVariable y = var.ecr();
00229
00230 if(x == y)
00231 {
00232 return x;
00233 }
00234
00235 if(x.rank > y.rank)
00236 {
00237 x.merge(y);
00238
00239 y.rep = x;
00240 return x;
00241 }
00242
00243 y.merge(x);
00244
00245 x.rep = y;
00246
00247 if(y.rank == x.rank)
00248 {
00249 y.rank++;
00250 }
00251
00252 return y;
00253 }
00254
00255 private void merge(TypeVariable var)
00256 {
00257 new_relation = true;
00258
00259 if(typeNode == null)
00260 {
00261 typeNode = var.typeNode;
00262 }
00263 else if(var.typeNode != null)
00264 {
00265 var.typeNode = typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00266 error("Type Error(1): Attempt to merge incompatible types.");
00267 }
00268
00269 unresolvedTypeVariables.clear(var.id);
00270 if(typeNode != null)
00271 {
00272 unresolvedTypeVariables.clear(id);
00273 }
00274
00275
00276 cannotBeInt |= var.cannotBeInt;
00277 cannotBeLong |= var.cannotBeLong;
00278 cannotBeFloat |= var.cannotBeFloat;
00279 cannotBeDouble |= var.cannotBeDouble;
00280 cannotBeAddress |= var.cannotBeAddress;
00281 cannotBeRef |= var.cannotBeRef;
00282
00283
00284 isElementOf.or(var.isElementOf);
00285
00286 if(isArrayOf == null)
00287 {
00288 if(var.isArrayOf != null)
00289 {
00290 isArrayOf = var.isArrayOf.ecr();
00291 isArrayOf.isElementOf.clear(var.id);
00292 isArrayOf.isElementOf.set(id);
00293 }
00294 }
00295 else if(var.isArrayOf != null)
00296 {
00297 new_relation = true;
00298 isArrayOf.ecrUnion(var.isArrayOf);
00299 isArrayOf = isArrayOf.ecr();
00300 isArrayOf.isElementOf.clear(var.id);
00301 isArrayOf.isElementOf.set(id);
00302 }
00303
00304
00305 parents.or(var.parents);
00306 int[] elements = var.parents.elements();
00307 for(int i = 0; i < elements.length; i++)
00308 {
00309 TypeVariable parent =
00310 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00311 parent.children.clear(var.id);
00312 parent.children.set(id);
00313 }
00314
00315
00316 children.or(var.children);
00317 elements = var.children.elements();
00318 for(int i = 0; i < elements.length; i++)
00319 {
00320 TypeVariable child =
00321 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00322 child.parents.clear(var.id);
00323 child.parents.set(id);
00324 }
00325 parents.clear(id);
00326 children.clear(id);
00327 parents.clear(var.id);
00328 children.clear(var.id);
00329
00330
00331 if(typeNode != null)
00332 {
00333 if(cannotBeInt && (typeNode.getType() instanceof IntType))
00334 {
00335 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00336 error("Type Error(2): Should not be an IntType.");
00337 }
00338
00339 if(cannotBeLong && (typeNode.getType() instanceof LongType))
00340 {
00341 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00342 error("Type Error(3): Should not be a LongType.");
00343 }
00344
00345 if(cannotBeFloat && (typeNode.getType() instanceof FloatType))
00346 {
00347 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00348 error("Type Error(4): Should not be a FloatType.");
00349 }
00350
00351 if(cannotBeDouble && (typeNode.getType() instanceof DoubleType))
00352 {
00353 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00354 error("Type Error(5): Should not be a DoubleType.");
00355 }
00356
00357 if(cannotBeAddress && (typeNode.getType() instanceof StmtAddressType))
00358 {
00359 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00360 error("Type Error(6): Should not be a StmtAddressType.");
00361 }
00362
00363 if(cannotBeRef &&
00364 ((typeNode.getType() instanceof RefType) ||
00365 (typeNode.getType() instanceof ArrayType)))
00366 {
00367 typeNode = classHierarchy.getTypeNode(ErroneousType.v());
00368 error("Type Error(7): Should not be a RefType nor an ArrayType.");
00369 }
00370
00371 elements = parents.elements();
00372 for(int i = 0; i < elements.length; i++)
00373 {
00374 TypeVariable parent =
00375 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00376 if(parent.typeNode != null)
00377 {
00378 if(!typeNode.hasAncestor(parent.typeNode))
00379 {
00380 parent.typeNode = typeNode =
00381 classHierarchy.getTypeNode(ErroneousType.v());
00382 error("Type Error(8): Parent type is not a valid ancestor.");
00383 }
00384 }
00385 }
00386
00387 elements = children.elements();
00388 for(int i = 0; i < elements.length; i++)
00389 {
00390 TypeVariable child =
00391 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00392 if(child.typeNode != null)
00393 {
00394 if(!typeNode.hasDescendant(child.typeNode))
00395 {
00396 child.typeNode = typeNode =
00397 classHierarchy.getTypeNode(ErroneousType.v());
00398 error("Type Error(9): Child type is not a valid descendant.");
00399 }
00400 }
00401 }
00402 }
00403
00404 var.parents = new IntSet();
00405 var.children = new IntSet();
00406 var.isElementOf = new IntSet();
00407 var.isArrayOf = null;
00408 }
00409
00410 void removeEcrIndirectRelations()
00411 {
00412 TypeVariable x = ecr();
00413 x.ancestors = new BitSet();
00414
00415 TypeVariable[] parents = getEcrParents();
00416 for(int i = 0; i < parents.length; i++)
00417 {
00418 x.ancestors.or(parents[i].ancestors);
00419 }
00420 for(int i = 0; i < parents.length; i++)
00421 {
00422 if(x.ancestors.get(parents[i].id))
00423 {
00424 x.parents.clear(parents[i].id);
00425 parents[i].children.clear(x.id);
00426 }
00427 else
00428 {
00429 x.ancestors.set(parents[i].id);
00430 }
00431 }
00432 }
00433
00434 void ecrAddParent(TypeVariable variable)
00435 {
00436 if(ecr() != variable.ecr())
00437 {
00438 if(DEBUG)
00439 {
00440 System.out.println(typeVariableStringHashtable.get(variable.ecr()) + " < " +
00441 typeVariableStringHashtable.get(ecr()));
00442 }
00443
00444 ecr().parents.set(variable.ecr().id);
00445 variable.ecr().children.set(ecr().id);
00446 }
00447 }
00448
00449 void ecrAddChild(TypeVariable variable)
00450 {
00451 if(ecr() != variable.ecr())
00452 {
00453 if(DEBUG)
00454 {
00455 System.out.println(typeVariableStringHashtable.get(ecr()) + " < " +
00456 typeVariableStringHashtable.get(variable.ecr()));
00457 }
00458
00459 ecr().children.set(variable.ecr().id);
00460 variable.ecr().parents.set(ecr().id);
00461 }
00462 }
00463
00464 void ecrCannotBeInt()
00465 {
00466 ecr().cannotBeInt = true;
00467 }
00468
00469 void ecrCannotBeLong()
00470 {
00471 ecr().cannotBeLong = true;
00472 }
00473
00474 void ecrCannotBeFloat()
00475 {
00476 ecr().cannotBeFloat = true;
00477 }
00478
00479 void ecrCannotBeDouble()
00480 {
00481 ecr().cannotBeDouble = true;
00482 }
00483
00484 void ecrCannotBeAddress()
00485 {
00486 ecr().cannotBeAddress = true;
00487 }
00488
00489 void ecrCannotBeRef()
00490 {
00491 ecr().cannotBeRef = true;
00492 }
00493
00494 int getEcrId()
00495 {
00496 return ecr().id;
00497 }
00498
00499 boolean isEcrArray()
00500 {
00501 return ecr().isArrayOf != null;
00502 }
00503
00504 int ecrArrayDepth()
00505 {
00506 return ecr().arrayDepth;
00507 }
00508
00509 TypeVariable getEcrIsArrayOf()
00510 {
00511 TypeVariable x = ecr();
00512
00513 if(x.isArrayOf == null)
00514 {
00515 x.isArrayOf = new TypeVariable();
00516 x.isArrayOf.isElementOf.set(x.id);
00517 }
00518
00519 return x.isArrayOf;
00520 }
00521
00522 IntSet getEcrParentIds()
00523 {
00524 return (IntSet) ecr().parents.clone();
00525 }
00526
00527 TypeVariable[] getEcrParents()
00528 {
00529 TypeVariable x = ecr();
00530 int[] elements = x.parents.elements();
00531 TypeVariable[] result = new TypeVariable[elements.length];
00532
00533 for(int i = 0; i < elements.length; i++)
00534 {
00535 result[i] = (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00536 }
00537
00538 return result;
00539 }
00540
00541 TypeVariable[] getEcrChildren()
00542 {
00543 TypeVariable x = ecr();
00544 int[] elements = x.children.elements();
00545 TypeVariable[] result = new TypeVariable[elements.length];
00546
00547 for(int i = 0; i < elements.length; i++)
00548 {
00549 result[i] = (TypeVariable) typeVariableInstances.elementAt(elements[i]);
00550 }
00551
00552 return result;
00553 }
00554
00555 ClassHierarchy.TypeNode getEcrTypeNode()
00556 {
00557 return ecr().typeNode;
00558 }
00559
00560 boolean setEcrTypeNode(ClassHierarchy.TypeNode typeNode)
00561 {
00562 TypeVariable[] elements = getEcrParents();
00563 for(int i = 0; i < elements.length; i++)
00564 {
00565 if(elements[i].typeNode != null)
00566 {
00567 if((!typeNode.hasAncestor(elements[i].typeNode)) &&
00568 (typeNode != elements[i].typeNode))
00569 {
00570 return false;
00571 }
00572 }
00573 }
00574
00575 elements = getEcrChildren();
00576 for(int i = 0; i < elements.length; i++)
00577 {
00578 if(elements[i].typeNode != null)
00579 {
00580 if((!typeNode.hasDescendant(elements[i].typeNode)) &&
00581 (typeNode != elements[i].typeNode))
00582 {
00583 return false;
00584 }
00585 }
00586 }
00587
00588 if(isEcrArray())
00589 {
00590 if(!(typeNode.getType() instanceof ArrayType))
00591 {
00592 return false;
00593 }
00594 else
00595 {
00596 ArrayType at = (ArrayType) typeNode.getType();
00597 ClassHierarchy.TypeNode tn = (at.numDimensions > 1) ?
00598 classHierarchy.getTypeNode(
00599 ArrayType.v(at.baseType, at.numDimensions - 1)) :
00600 classHierarchy.getTypeNode(at.baseType);
00601
00602 if(!tn.hasDescendant(getEcrIsArrayOf().getEcrTypeNode()))
00603 {
00604 return false;
00605 }
00606 }
00607 }
00608
00609 ecr().typeNode = typeNode;
00610 return true;
00611 }
00612
00613 void unsetEcrTypeNode()
00614 {
00615 ecr().typeNode = null;
00616 }
00617 }
00618
00619 private class ConstraintCollector extends AbstractStmtSwitch
00620 {
00621 private void handleInvokeExpr(InvokeExpr ie)
00622 {
00623 if(ie instanceof InterfaceInvokeExpr)
00624 {
00625 InterfaceInvokeExpr invoke = (InterfaceInvokeExpr) ie;
00626
00627 SootMethod method = invoke.getMethod();
00628 Value base = invoke.getBase();
00629
00630 if(base instanceof Local)
00631 {
00632 Local local = (Local) base;
00633
00634 TypeVariable localType = getTypeVariable(local);
00635
00636 localType.ecrAddParent(getTypeVariable(method.getDeclaringClass()));
00637 }
00638
00639 int count = invoke.getArgCount();
00640
00641 for(int i = 0; i < count; i++)
00642 {
00643 if(invoke.getArg(i) instanceof Local)
00644 {
00645 Local local = (Local) invoke.getArg(i);
00646
00647 TypeVariable localType = getTypeVariable(local);
00648
00649 localType.ecrAddParent(getTypeVariable(method.getParameterType(i)));
00650 }
00651 }
00652 }
00653 else if(ie instanceof SpecialInvokeExpr)
00654 {
00655 SpecialInvokeExpr invoke = (SpecialInvokeExpr) ie;
00656
00657 SootMethod method = invoke.getMethod();
00658 Value base = invoke.getBase();
00659
00660 if(base instanceof Local)
00661 {
00662 Local local = (Local) base;
00663
00664 TypeVariable localType = getTypeVariable(local);
00665
00666 localType.ecrAddParent(getTypeVariable(method.getDeclaringClass()));
00667 }
00668
00669 int count = invoke.getArgCount();
00670
00671 for(int i = 0; i < count; i++)
00672 {
00673 if(invoke.getArg(i) instanceof Local)
00674 {
00675 Local local = (Local) invoke.getArg(i);
00676
00677 TypeVariable localType = getTypeVariable(local);
00678
00679 localType.ecrAddParent(getTypeVariable(method.getParameterType(i)));
00680 }
00681 }
00682 }
00683 else if(ie instanceof VirtualInvokeExpr)
00684 {
00685 VirtualInvokeExpr invoke = (VirtualInvokeExpr) ie;
00686
00687 SootMethod method = invoke.getMethod();
00688 Value base = invoke.getBase();
00689
00690 if(base instanceof Local)
00691 {
00692 Local local = (Local) base;
00693
00694 TypeVariable localType = getTypeVariable(local);
00695
00696 localType.ecrAddParent(getTypeVariable(method.getDeclaringClass()));
00697 }
00698
00699 int count = invoke.getArgCount();
00700
00701 for(int i = 0; i < count; i++)
00702 {
00703 if(invoke.getArg(i) instanceof Local)
00704 {
00705 Local local = (Local) invoke.getArg(i);
00706
00707 TypeVariable localType = getTypeVariable(local);
00708
00709 localType.ecrAddParent(getTypeVariable(method.getParameterType(i)));
00710 }
00711 }
00712 }
00713 else if(ie instanceof StaticInvokeExpr)
00714 {
00715 StaticInvokeExpr invoke = (StaticInvokeExpr) ie;
00716
00717 SootMethod method = invoke.getMethod();
00718
00719 int count = invoke.getArgCount();
00720
00721 for(int i = 0; i < count; i++)
00722 {
00723 if(invoke.getArg(i) instanceof Local)
00724 {
00725 Local local = (Local) invoke.getArg(i);
00726
00727 TypeVariable localType = getTypeVariable(local);
00728
00729 localType.ecrAddParent(getTypeVariable(method.getParameterType(i)));
00730 }
00731 }
00732 }
00733 else
00734 {
00735 throw new RuntimeException("Unhandled invoke expression type: " + ie.getClass());
00736 }
00737 }
00738
00739 public void caseBreakpointStmt(BreakpointStmt stmt)
00740 {
00741
00742 }
00743
00744 public void caseInvokeStmt(InvokeStmt stmt)
00745 {
00746 handleInvokeExpr((InvokeExpr) stmt.getInvokeExpr());
00747 }
00748
00749 public void caseAssignStmt(AssignStmt stmt)
00750 {
00751 Value l = stmt.getLeftOp();
00752 Value r = stmt.getRightOp();
00753
00754
00755
00756 TypeVariable left = null;
00757 TypeVariable right = null;
00758
00759 if(l instanceof ArrayRef)
00760 {
00761 ArrayRef ref = (ArrayRef) l;
00762 Value base = ref.getBase();
00763 Value index = ref.getIndex();
00764
00765 TypeVariable baseType = getTypeVariable((Local) base);
00766 left = baseType.getEcrIsArrayOf();
00767
00768 if(index instanceof Local)
00769 {
00770 getTypeVariable((Local) index).ecrCannotBeLong();
00771 getTypeVariable((Local) index).ecrCannotBeFloat();
00772 getTypeVariable((Local) index).ecrCannotBeDouble();
00773 getTypeVariable((Local) index).ecrCannotBeAddress();
00774 getTypeVariable((Local) index).ecrCannotBeRef();
00775 }
00776 }
00777 else if(l instanceof Local)
00778 {
00779 left = getTypeVariable((Local) l);
00780 }
00781 else if(l instanceof InstanceFieldRef)
00782 {
00783 InstanceFieldRef ref = (InstanceFieldRef) l;
00784
00785 TypeVariable baseType = getTypeVariable((Local) ref.getBase());
00786 baseType.ecrAddParent(getTypeVariable(ref.getField().getDeclaringClass()));
00787 left = getTypeVariable(ref.getField().getType());
00788 }
00789 else if(l instanceof StaticFieldRef)
00790 {
00791 StaticFieldRef ref = (StaticFieldRef) l;
00792
00793 left = getTypeVariable(ref.getField().getType());
00794 }
00795 else
00796 {
00797 throw new RuntimeException("Unhandled variable type: " + l.getClass());
00798 }
00799
00800 if(r instanceof ArrayRef)
00801 {
00802 ArrayRef ref = (ArrayRef) r;
00803 Value base = ref.getBase();
00804 Value index = ref.getIndex();
00805
00806 TypeVariable baseType = getTypeVariable((Local) base);
00807 right = baseType.getEcrIsArrayOf();
00808
00809 if(index instanceof Local)
00810 {
00811 getTypeVariable((Local) index).ecrCannotBeLong();
00812 getTypeVariable((Local) index).ecrCannotBeFloat();
00813 getTypeVariable((Local) index).ecrCannotBeDouble();
00814 getTypeVariable((Local) index).ecrCannotBeAddress();
00815 getTypeVariable((Local) index).ecrCannotBeRef();
00816 }
00817 }
00818 else if(r instanceof DoubleConstant)
00819 {
00820 right = getTypeVariable(DoubleType.v());
00821 }
00822 else if(r instanceof FloatConstant)
00823 {
00824 right = getTypeVariable(FloatType.v());
00825 }
00826 else if(r instanceof IntConstant)
00827 {
00828 right = getTypeVariable(IntType.v());
00829 }
00830 else if(r instanceof LongConstant)
00831 {
00832 right = getTypeVariable(LongType.v());
00833 }
00834 else if(r instanceof NullConstant)
00835 {
00836 right = null;
00837 }
00838 else if(r instanceof StringConstant)
00839 {
00840 right = getTypeVariable(RefType.v("java.lang.String"));
00841 }
00842 else if(r instanceof BinopExpr)
00843 {
00844 BinopExpr be = (BinopExpr) r;
00845
00846 if(be.getOp1() instanceof Local)
00847 {
00848 TypeVariable var = getTypeVariable((Local) be.getOp1());
00849
00850 if((r instanceof AddExpr) ||
00851 (r instanceof SubExpr) ||
00852 (r instanceof MulExpr) ||
00853 (r instanceof DivExpr) ||
00854 (r instanceof RemExpr))
00855 {
00856 var.ecrCannotBeAddress();
00857 var.ecrCannotBeRef();
00858 var.ecrAddParent(left);
00859 }
00860 else if((r instanceof AndExpr) ||
00861 (r instanceof OrExpr) ||
00862 (r instanceof XorExpr) ||
00863 (r instanceof ShlExpr) ||
00864 (r instanceof ShrExpr) ||
00865 (r instanceof UshrExpr))
00866 {
00867 var.ecrCannotBeFloat();
00868 var.ecrCannotBeDouble();
00869 var.ecrCannotBeAddress();
00870 var.ecrCannotBeRef();
00871 var.ecrAddParent(left);
00872 right = var;
00873 }
00874 else if(r instanceof CmpExpr)
00875 {
00876 var.ecrCannotBeInt();
00877 var.ecrCannotBeFloat();
00878 var.ecrCannotBeDouble();
00879 var.ecrCannotBeAddress();
00880 var.ecrCannotBeRef();
00881 }
00882 else if((r instanceof CmpgExpr) ||
00883 (r instanceof CmplExpr))
00884 {
00885 var.ecrCannotBeInt();
00886 var.ecrCannotBeLong();
00887 var.ecrCannotBeAddress();
00888 var.ecrCannotBeRef();
00889 }
00890 else if((r instanceof EqExpr) ||
00891 (r instanceof NeExpr))
00892 {
00893 var.ecrCannotBeLong();
00894 var.ecrCannotBeFloat();
00895 var.ecrCannotBeDouble();
00896 var.ecrCannotBeAddress();
00897 }
00898 else if((r instanceof GeExpr) ||
00899 (r instanceof GtExpr) ||
00900 (r instanceof LeExpr) ||
00901 (r instanceof LtExpr))
00902 {
00903 var.ecrCannotBeLong();
00904 var.ecrCannotBeFloat();
00905 var.ecrCannotBeDouble();
00906 var.ecrCannotBeAddress();
00907 var.ecrCannotBeRef();
00908 }
00909 }
00910 else if(be.getOp1() instanceof DoubleConstant)
00911 {
00912 if((r instanceof AddExpr) ||
00913 (r instanceof SubExpr) ||
00914 (r instanceof MulExpr) ||
00915 (r instanceof DivExpr) ||
00916 (r instanceof RemExpr) ||
00917 (r instanceof AndExpr) ||
00918 (r instanceof OrExpr) ||
00919 (r instanceof XorExpr) ||
00920 (r instanceof ShlExpr) ||
00921 (r instanceof ShrExpr) ||
00922 (r instanceof UshrExpr))
00923 {
00924 getTypeVariable(DoubleType.v()).ecrAddParent(left);
00925 right = getTypeVariable(DoubleType.v());
00926 }
00927 }
00928 else if(be.getOp1() instanceof FloatConstant)
00929 {
00930 if((r instanceof AddExpr) ||
00931 (r instanceof SubExpr) ||
00932 (r instanceof MulExpr) ||
00933 (r instanceof DivExpr) ||
00934 (r instanceof RemExpr) ||
00935 (r instanceof AndExpr) ||
00936 (r instanceof OrExpr) ||
00937 (r instanceof XorExpr) ||
00938 (r instanceof ShlExpr) ||
00939 (r instanceof ShrExpr) ||
00940 (r instanceof UshrExpr))
00941 {
00942 getTypeVariable(FloatType.v()).ecrAddParent(left);
00943 right = getTypeVariable(FloatType.v());
00944 }
00945 }
00946 else if(be.getOp1() instanceof IntConstant)
00947 {
00948 if((r instanceof AddExpr) ||
00949 (r instanceof SubExpr) ||
00950 (r instanceof MulExpr) ||
00951 (r instanceof DivExpr) ||
00952 (r instanceof RemExpr) ||
00953 (r instanceof AndExpr) ||
00954 (r instanceof OrExpr) ||
00955 (r instanceof XorExpr) ||
00956 (r instanceof ShlExpr) ||
00957 (r instanceof ShrExpr) ||
00958 (r instanceof UshrExpr))
00959 {
00960 getTypeVariable(IntType.v()).ecrAddParent(left);
00961 right = getTypeVariable(IntType.v());
00962 }
00963 }
00964 else if(be.getOp1() instanceof LongConstant)
00965 {
00966 if((r instanceof AddExpr) ||
00967 (r instanceof SubExpr) ||
00968 (r instanceof MulExpr) ||
00969 (r instanceof DivExpr) ||
00970 (r instanceof RemExpr) ||
00971 (r instanceof AndExpr) ||
00972 (r instanceof OrExpr) ||
00973 (r instanceof XorExpr) ||
00974 (r instanceof ShlExpr) ||
00975 (r instanceof ShrExpr) ||
00976 (r instanceof UshrExpr))
00977 {
00978 getTypeVariable(LongType.v()).ecrAddParent(left);
00979 right = getTypeVariable(LongType.v());
00980 }
00981 }
00982 else if(be.getOp1() instanceof NullConstant)
00983 {
00984 if((r instanceof AddExpr) ||
00985 (r instanceof SubExpr) ||
00986 (r instanceof MulExpr) ||
00987 (r instanceof DivExpr) ||
00988 (r instanceof RemExpr) ||
00989 (r instanceof AndExpr) ||
00990 (r instanceof OrExpr) ||
00991 (r instanceof XorExpr) ||
00992 (r instanceof ShlExpr) ||
00993 (r instanceof ShrExpr) ||
00994 (r instanceof UshrExpr))
00995 {
00996
00997 right = null;
00998 }
00999 }
01000 else if(be.getOp1() instanceof StringConstant)
01001 {
01002 if((r instanceof AddExpr) ||
01003 (r instanceof SubExpr) ||
01004 (r instanceof MulExpr) ||
01005 (r instanceof DivExpr) ||
01006 (r instanceof RemExpr) ||
01007 (r instanceof AndExpr) ||
01008 (r instanceof OrExpr) ||
01009 (r instanceof XorExpr) ||
01010 (r instanceof ShlExpr) ||
01011 (r instanceof ShrExpr) ||
01012 (r instanceof UshrExpr))
01013 {
01014 getTypeVariable(RefType.v("java.lang.String")).ecrAddParent(left);
01015 right = getTypeVariable(RefType.v("java.lang.String"));
01016 }
01017 }
01018
01019 if(be.getOp2() instanceof Local)
01020 {
01021 TypeVariable var = getTypeVariable((Local) be.getOp2());
01022
01023 if((r instanceof AddExpr) ||
01024 (r instanceof SubExpr) ||
01025 (r instanceof MulExpr) ||
01026 (r instanceof DivExpr) ||
01027 (r instanceof RemExpr))
01028 {
01029 var.ecrCannotBeAddress();
01030 var.ecrCannotBeRef();
01031 right = var;
01032 }
01033 else if((r instanceof AndExpr) ||
01034 (r instanceof OrExpr) ||
01035 (r instanceof XorExpr))
01036 {
01037 var.ecrCannotBeFloat();
01038 var.ecrCannotBeDouble();
01039 var.ecrCannotBeAddress();
01040 var.ecrCannotBeRef();
01041 right = var;
01042 }
01043 else if((r instanceof ShlExpr) ||
01044 (r instanceof ShrExpr) ||
01045 (r instanceof UshrExpr))
01046 {
01047 var.ecrCannotBeLong();
01048 var.ecrCannotBeFloat();
01049 var.ecrCannotBeDouble();
01050 var.ecrCannotBeAddress();
01051 var.ecrCannotBeRef();
01052 }
01053 else if(r instanceof CmpExpr)
01054 {
01055 var.ecrCannotBeInt();
01056 var.ecrCannotBeFloat();
01057 var.ecrCannotBeDouble();
01058 var.ecrCannotBeAddress();
01059 var.ecrCannotBeRef();
01060 right = getTypeVariable(IntType.v());
01061 }
01062 else if((r instanceof CmpgExpr) ||
01063 (r instanceof CmplExpr))
01064 {
01065 var.ecrCannotBeInt();
01066 var.ecrCannotBeLong();
01067 var.ecrCannotBeAddress();
01068 var.ecrCannotBeRef();
01069 right = getTypeVariable(IntType.v());
01070 }
01071 else if((r instanceof EqExpr) ||
01072 (r instanceof NeExpr))
01073 {
01074 var.ecrCannotBeLong();
01075 var.ecrCannotBeFloat();
01076 var.ecrCannotBeDouble();
01077 var.ecrCannotBeAddress();
01078 right = getTypeVariable(IntType.v());
01079 }
01080 else if((r instanceof GeExpr) ||
01081 (r instanceof GtExpr) ||
01082 (r instanceof LeExpr) ||
01083 (r instanceof LtExpr))
01084 {
01085 var.ecrCannotBeLong();
01086 var.ecrCannotBeFloat();
01087 var.ecrCannotBeDouble();
01088 var.ecrCannotBeAddress();
01089 var.ecrCannotBeRef();
01090 right = getTypeVariable(IntType.v());
01091 }
01092 }
01093 else if(be.getOp2() instanceof DoubleConstant)
01094 {
01095 if((r instanceof AddExpr) ||
01096 (r instanceof SubExpr) ||
01097 (r instanceof MulExpr) ||
01098 (r instanceof DivExpr) ||
01099 (r instanceof RemExpr) ||
01100 (r instanceof AndExpr) ||
01101 (r instanceof OrExpr) ||
01102 (r instanceof XorExpr))
01103 {
01104 right = getTypeVariable(DoubleType.v());
01105 }
01106 else
01107 {
01108 right = getTypeVariable(IntType.v());
01109 }
01110 }
01111 else if(be.getOp2() instanceof FloatConstant)
01112 {
01113 if((r instanceof AddExpr) ||
01114 (r instanceof SubExpr) ||
01115 (r instanceof MulExpr) ||
01116 (r instanceof DivExpr) ||
01117 (r instanceof RemExpr) ||
01118 (r instanceof AndExpr) ||
01119 (r instanceof OrExpr) ||
01120 (r instanceof XorExpr))
01121 {
01122 right = getTypeVariable(FloatType.v());
01123 }
01124 else
01125 {
01126 right = getTypeVariable(IntType.v());
01127 }
01128 }
01129 else if(be.getOp2() instanceof IntConstant)
01130 {
01131 if((r instanceof AddExpr) ||
01132 (r instanceof SubExpr) ||
01133 (r instanceof MulExpr) ||
01134 (r instanceof DivExpr) ||
01135 (r instanceof RemExpr) ||
01136 (r instanceof AndExpr) ||
01137 (r instanceof OrExpr) ||
01138 (r instanceof XorExpr))
01139 {
01140 right = getTypeVariable(IntType.v());
01141 }
01142 else if(!((r instanceof ShlExpr) ||
01143 (r instanceof UshrExpr) ||
01144 (r instanceof ShrExpr)))
01145 {
01146 right = getTypeVariable(IntType.v());
01147 }
01148 }
01149 else if(be.getOp2() instanceof LongConstant)
01150 {
01151 if((r instanceof AddExpr) ||
01152 (r instanceof SubExpr) ||
01153 (r instanceof MulExpr) ||
01154 (r instanceof DivExpr) ||
01155 (r instanceof RemExpr) ||
01156 (r instanceof AndExpr) ||
01157 (r instanceof OrExpr) ||
01158 (r instanceof XorExpr))
01159 {
01160 right = getTypeVariable(LongType.v());
01161 }
01162 else
01163 {
01164 right = getTypeVariable(IntType.v());
01165 }
01166 }
01167 else if(be.getOp2() instanceof NullConstant)
01168 {
01169 if((r instanceof AddExpr) ||
01170 (r instanceof SubExpr) ||
01171 (r instanceof MulExpr) ||
01172 (r instanceof DivExpr) ||
01173 (r instanceof RemExpr) ||
01174 (r instanceof AndExpr) ||
01175 (r instanceof OrExpr) ||
01176 (r instanceof XorExpr))
01177 {
01178 right = null;
01179 }
01180 else
01181 {
01182 right = getTypeVariable(IntType.v());
01183 }
01184 }
01185 else if(be.getOp2() instanceof StringConstant)
01186 {
01187 if((r instanceof AddExpr) ||
01188 (r instanceof SubExpr) ||
01189 (r instanceof MulExpr) ||
01190 (r instanceof DivExpr) ||
01191 (r instanceof RemExpr) ||
01192 (r instanceof AndExpr) ||
01193 (r instanceof OrExpr) ||
01194 (r instanceof XorExpr))
01195 {
01196 right = getTypeVariable(RefType.v("java.lang.String"));
01197 }
01198 else
01199 {
01200 right = getTypeVariable(IntType.v());
01201 }
01202 }
01203 }
01204 else if(r instanceof CastExpr)
01205 {
01206 CastExpr ce = (CastExpr) r;
01207
01208 right = getTypeVariable(ce.getCastType());
01209 }
01210 else if(r instanceof InstanceOfExpr)
01211 {
01212 InstanceOfExpr ioe = (InstanceOfExpr) r;
01213
01214 TypeVariable var = getTypeVariable((Local) ioe.getOp());
01215
01216 var.ecrCannotBeInt();
01217 var.ecrCannotBeLong();
01218 var.ecrCannotBeFloat();
01219 var.ecrCannotBeDouble();
01220 var.ecrCannotBeAddress();
01221
01222 right = getTypeVariable(IntType.v());
01223 }
01224 else if(r instanceof InvokeExpr)
01225 {
01226 InvokeExpr ie = (InvokeExpr) r;
01227
01228 handleInvokeExpr(ie);
01229
01230 right = getTypeVariable(ie.getMethod().getReturnType());
01231 }
01232 else if(r instanceof NewArrayExpr)
01233 {
01234 NewArrayExpr nae = (NewArrayExpr) r;
01235
01236 Type baseType = nae.getBaseType();
01237
01238 if(baseType instanceof ArrayType)
01239 {
01240 right = getTypeVariable(ArrayType.v(((ArrayType) baseType).
01241 baseType, ((ArrayType) baseType).numDimensions + 1));
01242 }
01243 else
01244 right = getTypeVariable(ArrayType.v((BaseType) baseType, 1));
01245
01246 Value size = nae.getSize();
01247 if(size instanceof Local)
01248 {
01249 TypeVariable var = getTypeVariable((Local) size);
01250 var.ecrCannotBeLong();
01251 var.ecrCannotBeFloat();
01252 var.ecrCannotBeDouble();
01253 var.ecrCannotBeAddress();
01254 var.ecrCannotBeRef();
01255 }
01256 }
01257 else if(r instanceof NewExpr)
01258 {
01259 NewExpr na = (NewExpr) r;
01260
01261 right = getTypeVariable(na.getBaseType());
01262 }
01263 else if(r instanceof NewMultiArrayExpr)
01264 {
01265 NewMultiArrayExpr nmae = (NewMultiArrayExpr) r;
01266
01267 right = getTypeVariable(nmae.getBaseType());
01268
01269 for(int i = 0; i < nmae.getSizeCount(); i++)
01270 {
01271 Value size = nmae.getSize(i);
01272 if(size instanceof Local)
01273 {
01274 TypeVariable var = getTypeVariable((Local) size);
01275 var.ecrCannotBeLong();
01276 var.ecrCannotBeFloat();
01277 var.ecrCannotBeDouble();
01278 var.ecrCannotBeAddress();
01279 var.ecrCannotBeRef();
01280 }
01281 }
01282 }
01283 else if(r instanceof LengthExpr)
01284 {
01285 LengthExpr le = (LengthExpr) r;
01286
01287 if(le.getOp() instanceof Local)
01288 {
01289 getTypeVariable((Local) le.getOp()).getEcrIsArrayOf();
01290 }
01291
01292 right = getTypeVariable(IntType.v());
01293 }
01294 else if(r instanceof NegExpr)
01295 {
01296 NegExpr ne = (NegExpr) r;
01297
01298 if(ne.getOp() instanceof Local)
01299 {
01300 right = getTypeVariable((Local) ne.getOp());
01301
01302 right.ecrCannotBeAddress();
01303 right.ecrCannotBeRef();
01304 }
01305 else if(ne.getOp() instanceof DoubleConstant)
01306 {
01307 right = getTypeVariable(DoubleType.v());
01308 }
01309 else if(ne.getOp() instanceof FloatConstant)
01310 {
01311 right = getTypeVariable(FloatType.v());
01312 }
01313 else if(ne.getOp() instanceof IntConstant)
01314 {
01315 right = getTypeVariable(IntType.v());
01316 }
01317 else if(ne.getOp() instanceof LongConstant)
01318 {
01319 right = getTypeVariable(LongType.v());
01320 }
01321 }
01322 else if(r instanceof Local)
01323 {
01324 right = getTypeVariable((Local) r);
01325 }
01326 else if(r instanceof InstanceFieldRef)
01327 {
01328 InstanceFieldRef ref = (InstanceFieldRef) r;
01329
01330 TypeVariable baseType = getTypeVariable((Local) ref.getBase());
01331 baseType.ecrAddParent(getTypeVariable(ref.getField().getDeclaringClass()));
01332 right = getTypeVariable(ref.getField().getType());
01333 }
01334 else if(r instanceof StaticFieldRef)
01335 {
01336 StaticFieldRef ref = (StaticFieldRef) r;
01337
01338 right = getTypeVariable(ref.getField().getType());
01339 }
01340 else if(r instanceof NextNextStmtRef)
01341 {
01342 right = getTypeVariable(StmtAddressType.v());
01343 }
01344 else
01345 {
01346 throw new RuntimeException("Unhandled variable type: " + r.getClass());
01347 }
01348
01349 if(right != null)
01350 {
01351 right.ecrAddParent(left);
01352 }
01353 }
01354
01355 public void caseIdentityStmt(IdentityStmt stmt)
01356 {
01357 Value l = stmt.getLeftOp();
01358 Value r = stmt.getRightOp();
01359
01360 if(l instanceof Local)
01361 {
01362 TypeVariable left = getTypeVariable((Local) l);
01363
01364 if(!(r instanceof CaughtExceptionRef))
01365 {
01366 TypeVariable right = getTypeVariable(r.getType());
01367 right.ecrAddParent(left);
01368 }
01369 else
01370 {
01371 List exceptionTypes = ((CaughtExceptionRef) r).getExceptionTypes();
01372 Iterator typeIt = exceptionTypes.iterator();
01373
01374 while(typeIt.hasNext())
01375 {
01376 Type t = (Type) typeIt.next();
01377
01378 left.ecrAddChild(getTypeVariable(t));
01379 }
01380
01381 left.ecrAddParent(getTypeVariable(RefType.v("java.lang.Throwable")));
01382 }
01383 }
01384 }
01385
01386 public void caseEnterMonitorStmt(EnterMonitorStmt stmt)
01387 {
01388 if(stmt.getOp() instanceof Local)
01389 {
01390 TypeVariable op = getTypeVariable((Local) stmt.getOp());
01391
01392 op.ecrAddParent(getTypeVariable(RefType.v("java.lang.Object")));
01393 }
01394 }
01395
01396 public void caseExitMonitorStmt(ExitMonitorStmt stmt)
01397 {
01398 if(stmt.getOp() instanceof Local)
01399 {
01400 TypeVariable op = getTypeVariable((Local) stmt.getOp());
01401
01402 op.ecrAddParent(getTypeVariable(RefType.v("java.lang.Object")));
01403 }
01404 }
01405
01406 public void caseGotoStmt(GotoStmt stmt)
01407 {
01408 }
01409
01410 public void caseIfStmt(IfStmt stmt)
01411 {
01412 ConditionExpr cond = (ConditionExpr) stmt.getCondition();
01413
01414 BinopExpr expr = (BinopExpr) cond;
01415 Value l = expr.getOp1();
01416 Value r = expr.getOp2();
01417
01418 if(l instanceof Local)
01419 {
01420 TypeVariable var = getTypeVariable((Local) l);
01421
01422 if((cond instanceof EqExpr) ||
01423 (cond instanceof NeExpr))
01424 {
01425 var.ecrCannotBeLong();
01426 var.ecrCannotBeFloat();
01427 var.ecrCannotBeDouble();
01428 var.ecrCannotBeAddress();
01429 }
01430 else if((cond instanceof GeExpr) ||
01431 (cond instanceof GtExpr) ||
01432 (cond instanceof LeExpr) ||
01433 (cond instanceof LtExpr))
01434 {
01435 var.ecrCannotBeLong();
01436 var.ecrCannotBeFloat();
01437 var.ecrCannotBeDouble();
01438 var.ecrCannotBeAddress();
01439 var.ecrCannotBeRef();
01440 }
01441 }
01442
01443 if(r instanceof Local)
01444 {
01445 TypeVariable var = getTypeVariable((Local) r);
01446
01447 if((cond instanceof EqExpr) ||
01448 (cond instanceof NeExpr))
01449 {
01450 var.ecrCannotBeLong();
01451 var.ecrCannotBeFloat();
01452 var.ecrCannotBeDouble();
01453 var.ecrCannotBeAddress();
01454 }
01455 else if((cond instanceof GeExpr) ||
01456 (cond instanceof GtExpr) ||
01457 (cond instanceof LeExpr) ||
01458 (cond instanceof LtExpr))
01459 {
01460 var.ecrCannotBeLong();
01461 var.ecrCannotBeFloat();
01462 var.ecrCannotBeDouble();
01463 var.ecrCannotBeAddress();
01464 var.ecrCannotBeRef();
01465 }
01466 }
01467 }
01468
01469 public void caseLookupSwitchStmt(LookupSwitchStmt stmt)
01470 {
01471 Value key = stmt.getKey();
01472
01473 if(key instanceof Local)
01474 {
01475 getTypeVariable((Local) key).ecrCannotBeLong();
01476 getTypeVariable((Local) key).ecrCannotBeFloat();
01477 getTypeVariable((Local) key).ecrCannotBeDouble();
01478 getTypeVariable((Local) key).ecrCannotBeAddress();
01479 getTypeVariable((Local) key).ecrCannotBeRef();
01480 }
01481 }
01482
01483 public void caseNopStmt(NopStmt stmt)
01484 {
01485 }
01486
01487 public void caseRetStmt(RetStmt stmt)
01488 {
01489 getTypeVariable((Local) stmt.getStmtAddress()).
01490 ecrAddParent(getTypeVariable(StmtAddressType.v()));
01491 }
01492
01493 public void caseReturnStmt(ReturnStmt stmt)
01494 {
01495 if(stmt.getReturnValue() instanceof Local)
01496 {
01497 getTypeVariable((Local) stmt.getReturnValue()).ecrAddParent(
01498 getTypeVariable(currentMethod.getReturnType()));
01499 }
01500 }
01501
01502 public void caseReturnVoidStmt(ReturnVoidStmt stmt)
01503 {
01504 }
01505
01506 public void caseTableSwitchStmt(TableSwitchStmt stmt)
01507 {
01508 Value key = stmt.getKey();
01509
01510 if(key instanceof Local)
01511 {
01512 getTypeVariable((Local) key).ecrCannotBeLong();
01513 getTypeVariable((Local) key).ecrCannotBeFloat();
01514 getTypeVariable((Local) key).ecrCannotBeDouble();
01515 getTypeVariable((Local) key).ecrCannotBeAddress();
01516 getTypeVariable((Local) key).ecrCannotBeRef();
01517 }
01518 }
01519
01520 public void caseThrowStmt(ThrowStmt stmt)
01521 {
01522 if(stmt.getOp() instanceof Local)
01523 {
01524 TypeVariable op = getTypeVariable((Local) stmt.getOp());
01525
01526 op.ecrAddParent(getTypeVariable(RefType.v("java.lang.Throwable")));
01527 }
01528 }
01529
01530 public void defaultCase(Stmt stmt)
01531 {
01532 throw new RuntimeException("Unhandled statement type: " + stmt.getClass());
01533 }
01534 }
01535
01536 private static class SCC
01537 {
01538 TypeVariable[] variables;
01539 boolean[] black;
01540 TypeVariable[] finished;
01541 int time;
01542
01543 LinkedList forest = new LinkedList();
01544 LinkedList current_tree;
01545
01546 SCC(Vector typeVariableInstances)
01547 {
01548 variables = new TypeVariable[typeVariableInstances.size()];
01549
01550 int counter = 0;
01551 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
01552 {
01553 variables[counter++] = (TypeVariable) e.nextElement();
01554 }
01555
01556 black = new boolean[variables.length];
01557 finished = new TypeVariable[variables.length];
01558
01559 for(int i = 0; i < variables.length; i++)
01560 {
01561 if((variables[i] == variables[i].ecr()) &&
01562 (variables[i].arrayDepth == 0))
01563 {
01564 if(!black[variables[i].id])
01565 {
01566 black[variables[i].id] = true;
01567 dfsg_visit(variables[i]);
01568 }
01569 }
01570 }
01571
01572 black = new boolean[variables.length];
01573
01574 for(int i = variables.length - 1; i >= 0; i--)
01575 {
01576 if(finished[i] == null)
01577 {
01578 continue;
01579 }
01580
01581 if((finished[i] == finished[i].ecr()) &&
01582 (finished[i].arrayDepth == 0))
01583 {
01584 if(!black[finished[i].id])
01585 {
01586 current_tree = new LinkedList();
01587 forest.add(current_tree);
01588
01589 black[finished[i].id] = true;
01590 dfsgt_visit(finished[i]);
01591 }
01592 }
01593 }
01594
01595 for(Iterator i = forest.iterator(); i.hasNext();)
01596 {
01597 LinkedList list = (LinkedList) i.next();
01598 TypeVariable previous = null;
01599
01600 for(Iterator j = list.iterator(); j.hasNext();)
01601 {
01602 TypeVariable current = (TypeVariable) j.next();
01603
01604 if(previous == null)
01605 {
01606 previous = current;
01607 }
01608 else
01609 {
01610 previous.ecrUnion(current);
01611 }
01612 }
01613 }
01614 }
01615
01616 void dfsg_visit(TypeVariable var)
01617 {
01618 TypeVariable[] parents = var.getEcrParents();
01619
01620 for(int i = 0; i < parents.length; i++)
01621 {
01622 if(!black[parents[i].id])
01623 {
01624 black[parents[i].id] = true;
01625 dfsg_visit(parents[i]);
01626 }
01627 }
01628
01629 finished[time++] = var;
01630 }
01631
01632 void dfsgt_visit(TypeVariable var)
01633 {
01634 current_tree.add(var);
01635
01636 TypeVariable[] children = var.getEcrChildren();
01637
01638 for(int i = 0; i < children.length; i++)
01639 {
01640 if(!black[children[i].id])
01641 {
01642 if(children[i].arrayDepth == 0)
01643 {
01644 black[children[i].id] = true;
01645 dfsgt_visit(children[i]);
01646 }
01647 }
01648 }
01649 }
01650 }
01651
01652 private static class TypeException extends RuntimeException
01653 {
01654 }
01655
01656
01657
01658 private TypeResolver(JimpleBody stmtBody)
01659 {
01660 try {
01661
01662 this.stmtBody = stmtBody;
01663
01664 currentMethod = stmtBody.getMethod();
01665 if(!currentMethod.getDeclaringClass().getName().equals(lastClass))
01666 {
01667
01668 lastClass = currentMethod.getDeclaringClass().getName();
01669 }
01670
01671 classHierarchy = ClassHierarchy.getClassHierarchy(
01672 currentMethod.getDeclaringClass().getManager());
01673
01674 if(DEBUG)
01675 {
01676 System.out.println();
01677 System.out.println("****" + currentMethod.getName());
01678 }
01679
01680
01681
01682
01683
01684 for(Iterator i = stmtBody.getStmtList().iterator(); i.hasNext();)
01685 {
01686 Stmt stmt = (Stmt) i.next();
01687 if(DEBUG)
01688 {
01689 System.out.println("** " + stmt);
01690 }
01691 stmt.apply(constraintCollector);
01692 }
01693
01694 getTypeVariable(RefType.v("java.lang.Object"));
01695 getTypeVariable(RefType.v("java.lang.Cloneable"));
01696 getTypeVariable(NullType.v());
01697
01698
01699
01700
01701
01702
01703
01704
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726 mergeAll(getTypeVariable(IntType.v()));
01727 mergeAll(getTypeVariable(LongType.v()));
01728 mergeAll(getTypeVariable(FloatType.v()));
01729 mergeAll(getTypeVariable(DoubleType.v()));
01730 mergeAll(getTypeVariable(StmtAddressType.v()));
01731
01732
01733
01734
01735 do
01736 {
01737 new_relation = false;
01738 collapseStronglyConnectedComponents();
01739 }
01740 while(new_relation == true);
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750
01751
01752
01753
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764 propagateArrayConstraints();
01765
01766
01767
01768 addRelationsBetweenHardNodes();
01769
01770
01771
01772
01773
01774 mergeAll(getTypeVariable(IntType.v()));
01775 mergeAll(getTypeVariable(LongType.v()));
01776 mergeAll(getTypeVariable(FloatType.v()));
01777 mergeAll(getTypeVariable(DoubleType.v()));
01778 mergeAll(getTypeVariable(StmtAddressType.v()));
01779
01780
01781
01782
01783 collapseStronglyConnectedComponents();
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813
01814 if(unresolvedTypeVariables.size() != 0)
01815 {
01816 resolveSingleRelations();
01817
01818 }
01819
01820
01821
01822 boolean modified = true;
01823 while((unresolvedTypeVariables.size() != 0) && modified)
01824 {
01825 removeIndirectRelations();
01826 modified = resolveSingleRelations();
01827
01828 }
01829
01830
01831
01832
01833
01834
01835 if(unresolvedTypeVariables.size() != 0)
01836 {
01837
01838
01839 resolveComplexRelations();
01840 if(unresolvedTypeVariables.size() != 0)
01841 {
01842
01843 }
01844 else
01845 {
01846
01847 }
01848 }
01849 else
01850 {
01851
01852 }
01853
01854
01855
01856
01857
01858 } catch(TypeException e)
01859 {
01860
01861 }
01862
01863
01864
01865 for(Iterator i = stmtBody.getLocals().iterator(); i.hasNext(); )
01866 {
01867 Local local = (Local) i.next();
01868
01869 TypeVariable var = getTypeVariable(local).ecr();
01870 if(var == null)
01871 {
01872 local.setType(UnknownType.v());
01873 }
01874 else if (var.arrayDepth == 0)
01875 {
01876 if(var.getEcrTypeNode() == null)
01877 {
01878 local.setType(UnknownType.v());
01879 }
01880 else
01881 {
01882 local.setType(var.getEcrTypeNode().getType());
01883 }
01884 }
01885 else
01886 {
01887 if(var.getEcrTypeNode() != null)
01888
01889 {
01890 local.setType(var.getEcrTypeNode().getType());
01891 }
01892 else if(var.base.getEcrTypeNode() == null)
01893 {
01894 local.setType(UnknownType.v());
01895 }
01896 else if(var.base.getEcrTypeNode().getType() instanceof ErroneousType)
01897 {
01898 local.setType(ErroneousType.v());
01899 }
01900 else
01901 {
01902 local.setType(ArrayType.v(
01903 (BaseType) var.base.getEcrTypeNode().getType(),
01904 var.arrayDepth));
01905 }
01906 }
01907 }
01908 }
01909 private void addRelationsBetweenHardNodes()
01910 {
01911 LinkedList workList = new LinkedList();
01912
01913 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
01914 {
01915 TypeVariable var = (TypeVariable) e.nextElement();
01916
01917 if((var == var.ecr()) &&
01918 (var.getEcrTypeNode() != null) &&
01919 (!(var.getEcrTypeNode().getType() instanceof ArrayType)))
01920 {
01921 workList.add(var);
01922 }
01923 }
01924
01925 while(workList.size() > 0)
01926 {
01927 TypeVariable var = (TypeVariable) workList.removeFirst();
01928
01929 TypeVariable[] elements = new TypeVariable[workList.size()];
01930 workList.toArray(elements);
01931
01932 for(int i = 0; i < elements.length; i++)
01933 {
01934 TypeVariable other = elements[i];
01935
01936 if(var.getEcrTypeNode().hasAncestor(other.getEcrTypeNode()))
01937 {
01938 var.ecrAddParent(other);
01939 }
01940 else if(var.getEcrTypeNode().hasDescendant(other.getEcrTypeNode()))
01941 {
01942 var.ecrAddChild(other);
01943 }
01944 }
01945
01946 }
01947 }
01948
01949 public static void assignTypesToLocals(JimpleBody stmtBody)
01950 {
01951 new TypeResolver(stmtBody);
01952 }
01953
01954
01955 private void collapseStronglyConnectedComponents()
01956 {
01957 new SCC(typeVariableInstances);
01958 }
01959 private void computeArrayDepths()
01960 {
01961 LinkedList workList = new LinkedList();
01962 LinkedList workList2 = new LinkedList();
01963
01964 int counter = 0;
01965
01966 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
01967 {
01968 TypeVariable var = (TypeVariable) e.nextElement();
01969
01970 if(var == var.ecr())
01971 {
01972 counter++;
01973 var.count = var.parents.elementCount();
01974
01975 if((var.isArrayOf != null) &&
01976 (!var.parents.get(var.isArrayOf.getEcrId())))
01977 {
01978 var.count++;
01979 }
01980
01981 if(var.count == 0)
01982 {
01983 var.arrayDepth = 0;
01984 workList.add(var);
01985 }
01986 }
01987 }
01988
01989 while(workList.size() > 0)
01990 {
01991 TypeVariable var = (TypeVariable) workList.removeFirst();
01992
01993 int[] elements = var.children.elements();
01994 for(int i = 0; i < elements.length; i++)
01995 {
01996 TypeVariable child =
01997 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
01998 child.arrayDepth = Math.max(child.arrayDepth, var.arrayDepth);
01999 if(--child.count == 0)
02000 {
02001 workList.add(child);
02002 }
02003 }
02004
02005 elements = var.isElementOf.elements();
02006 for(int i = 0; i < elements.length; i++)
02007 {
02008 TypeVariable array =
02009 ((TypeVariable) typeVariableInstances.
02010 elementAt(elements[i])).ecr();
02011
02012 array.arrayDepth = Math.max(array.arrayDepth, var.arrayDepth + 1);
02013 if(--array.count == 0)
02014 {
02015 workList.add(array);
02016 }
02017 }
02018
02019 workList2.add(var);
02020 }
02021
02022 if(counter != workList2.size())
02023 {
02024
02025 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02026 {
02027 TypeVariable var = (TypeVariable) e.nextElement();
02028
02029 if(var == var.ecr())
02030 {
02031
02032
02033
02034
02035
02036
02037
02038
02039 }
02040 }
02041 }
02042
02043 while(workList2.size() > 0)
02044 {
02045 TypeVariable var = (TypeVariable) workList2.removeFirst();
02046 var.count = 0;
02047
02048 if((var.isArrayOf != null) &&
02049 (var.arrayDepth < var.isArrayOf.ecr().arrayDepth + 1))
02050 {
02051 var.arrayDepth = var.isArrayOf.ecr().arrayDepth + 1;
02052 }
02053
02054 int[] elements = var.isElementOf.elements();
02055 for(int i = 0; i < elements.length; i++)
02056 {
02057 TypeVariable array =
02058 ((TypeVariable) typeVariableInstances.elementAt(elements[i])).ecr();
02059
02060 if(var.arrayDepth < array.arrayDepth - 1)
02061 {
02062 var.arrayDepth = array.arrayDepth - 1;
02063 }
02064 }
02065
02066 elements = var.parents.elements();
02067 for(int i = 0; i < elements.length; i++)
02068 {
02069 TypeVariable parent =
02070 ((TypeVariable) typeVariableInstances.elementAt(elements[i])).ecr();
02071
02072 if(var.arrayDepth < parent.arrayDepth)
02073 {
02074 var.arrayDepth = parent.arrayDepth;
02075 }
02076 }
02077
02078 if((var.isArrayOf != null) &&
02079 (var.arrayDepth > var.isArrayOf.ecr().arrayDepth + 1))
02080 {
02081 var.isArrayOf.ecr().arrayDepth = var.arrayDepth - 1;
02082
02083 if(var.isArrayOf.ecr().count++ == 0)
02084 {
02085 workList2.add(var.isArrayOf.ecr());
02086 }
02087 }
02088
02089 elements = var.isElementOf.elements();
02090 for(int i = 0; i < elements.length; i++)
02091 {
02092 TypeVariable array =
02093 ((TypeVariable) typeVariableInstances.elementAt(elements[i])).ecr();
02094
02095 if(var.arrayDepth > array.arrayDepth - 1)
02096 {
02097 array.arrayDepth = var.arrayDepth + 1;
02098
02099 if(array.count++ == 0)
02100 {
02101 workList2.add(array);
02102 }
02103 }
02104 }
02105
02106 elements = var.children.elements();
02107 for(int i = 0; i < elements.length; i++)
02108 {
02109 TypeVariable child =
02110 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
02111
02112 if(var.arrayDepth > child.arrayDepth)
02113 {
02114 child.arrayDepth = var.arrayDepth;
02115
02116 if(child.count++ == 0)
02117 {
02118 workList2.add(child);
02119 }
02120 }
02121 }
02122 }
02123 }
02124 private void debug()
02125 {
02126 System.out.println("*** DEBUG ***");
02127 debug_locals();
02128 int size = typeVariableInstances.size();
02129 for(int i = 0; i < size; i++)
02130 {
02131 TypeVariable a = (TypeVariable) typeVariableInstances.elementAt(i);
02132
02133 if(a == a.ecr())
02134 {
02135 System.out.print(i + ":");
02136
02137 ClassHierarchy.TypeNode node = a.getEcrTypeNode();
02138 if(node != null)
02139 {
02140 System.out.print(" " + node.getType());
02141 }
02142 System.out.println();
02143
02144 TypeVariable[] parents = a.getEcrParents();
02145 if(parents.length != 0)
02146 {
02147 System.out.print(" Parents:");
02148
02149 for(int j = 0; j < parents.length; j++)
02150 {
02151 System.out.print(" " + parents[j].getEcrId());
02152 }
02153
02154 System.out.println();
02155 }
02156
02157 TypeVariable[] children = a.getEcrChildren();
02158 if(children.length != 0)
02159 {
02160 System.out.print(" Children:");
02161
02162 for(int j = 0; j < children.length; j++)
02163 {
02164 System.out.print(" " + children[j].getEcrId());
02165 }
02166
02167 System.out.println();
02168 }
02169
02170 if(a.isArrayOf != null)
02171 {
02172 System.out.println(" Array of: " + a.isArrayOf.getEcrId());
02173 }
02174
02175 System.out.println(" Array depth: " + a.arrayDepth);
02176 }
02177 }
02178 }
02179 private void debug_locals()
02180 {
02181 for(Iterator i = stmtBody.getLocals().iterator(); i.hasNext(); )
02182 {
02183 Local local = (Local) i.next();
02184
02185 System.out.print(local + ": ");
02186
02187 TypeVariable var = getTypeVariable(local).ecr();
02188 if(var == null)
02189 {
02190 System.out.println("null");
02191 }
02192 else
02193 {
02194 System.out.println(var.getEcrId());
02195 }
02196 }
02197 }
02198 private static void error(String message)
02199 {
02200 if(DEBUG)
02201 {
02202 System.out.println(message);
02203 }
02204
02205 throw new TypeException();
02206 }
02207
02208 TypeVariable getTypeVariable(ClassHierarchy.TypeNode typeNode)
02209 {
02210 TypeVariable result = (TypeVariable) typeVariableHashtable.get(typeNode);
02211
02212 if(result == null)
02213 {
02214 result = new TypeVariable(typeNode);
02215 }
02216
02217 return result;
02218 }
02219
02220 TypeVariable getTypeVariable(Local local)
02221 {
02222 TypeVariable result = (TypeVariable) typeVariableHashtable.get(local);
02223
02224 if(result == null)
02225 {
02226 result = new TypeVariable(local);
02227
02228 }
02229
02230 return result;
02231 }
02232
02233 TypeVariable getTypeVariable(SootClass sClass)
02234 {
02235 return getTypeVariable(classHierarchy.getTypeNode(RefType.v(sClass.getName())));
02236 }
02237
02238 TypeVariable getTypeVariable(Type type)
02239 {
02240 return getTypeVariable(classHierarchy.getTypeNode(type));
02241 }
02242
02243 private boolean mergeAll(TypeVariable var)
02244 {
02245 TypeVariable[] parents = var.getEcrParents();
02246 TypeVariable[] children = var.getEcrChildren();
02247 boolean changed = true;
02248 boolean modif = false;
02249
02250 while(changed)
02251 {
02252 changed = false;
02253
02254 for(int i = 0; i < parents.length; i++)
02255 {
02256 if(parents[i].ecr().arrayDepth == var.ecr().arrayDepth)
02257 {
02258 modif = true;
02259 changed = true;
02260 var.ecrUnion(parents[i]);
02261 }
02262 }
02263
02264 for(int i = 0; i < children.length; i++)
02265 {
02266 if(children[i].ecr().arrayDepth == var.ecr().arrayDepth)
02267 {
02268 modif = true;
02269 changed = true;
02270 var.ecrUnion(children[i]);
02271 }
02272 }
02273
02274 parents = var.getEcrParents();
02275 children = var.getEcrChildren();
02276 }
02277
02278 return modif;
02279 }
02280 private void mergeBaseTypeArrays()
02281 {
02282 boolean changed;
02283
02284 do
02285 {
02286 changed = false;
02287
02288 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02289 {
02290 TypeVariable var = (TypeVariable) e.nextElement();
02291
02292 if((var == var.ecr()) &&
02293 (var.getEcrTypeNode() != null) &&
02294 (var.getEcrTypeNode().getType() instanceof ArrayType))
02295 {
02296 ArrayType type = (ArrayType) var.getEcrTypeNode().getType();
02297
02298 if(!(type.baseType instanceof RefType))
02299 {
02300 if(mergeAll(var))
02301 {
02302 changed = true;
02303 }
02304 }
02305 }
02306 }
02307 } while(changed);
02308 }
02309
02310
02311 private void propagateArrayConstraints()
02312 {
02313 computeArrayDepths();
02314
02315 propagateConstrains();
02316
02317 mergeBaseTypeArrays();
02318 }
02319 private void propagateConstrains()
02320 {
02321 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02322 {
02323 TypeVariable var = (TypeVariable) e.nextElement();
02324
02325 if(var == var.ecr())
02326 {
02327 if(var.isArrayOf == null)
02328 {
02329 if(var.arrayDepth == 0)
02330 {
02331 var.base = var;
02332 }
02333 else
02334 {
02335 var.base = new TypeVariable();
02336 var.base.base = var.base;
02337 }
02338
02339 LinkedList workList = new LinkedList();
02340 workList.add(var);
02341
02342 while(workList.size() > 0)
02343 {
02344 TypeVariable tv = (TypeVariable) workList.removeFirst();
02345
02346 int[] elements = tv.isElementOf.elements();
02347 for(int i = 0; i < elements.length; i++)
02348 {
02349 TypeVariable array =
02350 ((TypeVariable) typeVariableInstances.
02351 elementAt(elements[i])).ecr();
02352 array.base = var.base;
02353 workList.add(array);
02354 }
02355 }
02356 }
02357 }
02358 }
02359
02360 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02361 {
02362 TypeVariable var = (TypeVariable) e.nextElement();
02363
02364 if(var == var.ecr())
02365 {
02366 int[] elements = var.parents.elements();
02367 for(int i = 0; i < elements.length; i++)
02368 {
02369 TypeVariable parent =
02370 (TypeVariable) typeVariableInstances.elementAt(elements[i]);
02371
02372 if(parent.arrayDepth == var.arrayDepth)
02373 {
02374 var.base.ecrAddParent(parent.base);
02375 }
02376 else
02377 {
02378 parent.base.ecrAddChild(getTypeVariable(
02379 RefType.v("java.lang.Cloneable")));
02380 }
02381 }
02382
02383 if(var.arrayDepth != 0)
02384 {
02385 unresolvedTypeVariables.clear(var.id);
02386 }
02387 }
02388 }
02389 }
02390
02391 private void removeIndirectRelations()
02392 {
02393 LinkedList workList = new LinkedList();
02394 workList.addLast(getTypeVariable(RefType.v("java.lang.Object")));
02395 IntSet processed = new IntSet();
02396
02397 while(workList.size() != 0)
02398 {
02399 TypeVariable var = (TypeVariable) workList.removeFirst();
02400
02401 var.removeEcrIndirectRelations();
02402 processed.set(var.getEcrId());
02403
02404 TypeVariable[] children = var.getEcrChildren();
02405 for(int i = 0; i < children.length; i++)
02406 {
02407 IntSet temp = children[i].getEcrParentIds();
02408 temp.and(processed);
02409 if(temp.equals(children[i].getEcrParentIds()))
02410 {
02411 workList.addLast(children[i]);
02412 }
02413 }
02414 }
02415 }
02416 private void removeRelationsBetweenNonEcrs()
02417 {
02418 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02419 {
02420 TypeVariable var = (TypeVariable) e.nextElement();
02421
02422 if((var != var.ecr()) ||
02423 (var.arrayDepth != 0))
02424 {
02425 var.parents = new IntSet();
02426 var.children = new IntSet();
02427 }
02428 }
02429 }
02430
02431 private boolean resolveComplexRelations()
02432 {
02433 if(unresolvedTypeVariables.size() == 0)
02434 {
02435 return true;
02436 }
02437
02438 final TypeVariable[] ecrInstances;
02439 {
02440 Vector ecrs = new Vector();
02441 TypeVariable nullVar = null;
02442 for(Enumeration e = typeVariableInstances.elements(); e.hasMoreElements();)
02443 {
02444 TypeVariable var = (TypeVariable) e.nextElement();
02445 if((var.ecr() == var) && (var.getEcrTypeNode() != null))
02446 {
02447 if(var.getEcrTypeNode().getType().equals(NullType.v()))
02448 {
02449 nullVar = var;
02450 }
02451 else
02452 {
02453 ecrs.addElement(var);
02454 }
02455 }
02456 }
02457
02458
02459 if(nullVar != null)
02460 {
02461 ecrs.addElement(nullVar);
02462 }
02463
02464 ecrInstances = new TypeVariable[ecrs.size()];
02465 int index = 0;
02466 for(Enumeration e = ecrs.elements(); e.hasMoreElements();)
02467 {
02468 TypeVariable var = (TypeVariable) e.nextElement();
02469 ecrInstances[index++] = var;
02470 }
02471 }
02472
02473 final int[] elements;
02474 {
02475 IntSet processed = new IntSet();
02476 LinkedList processedList = new LinkedList();
02477
02478 while(!processed.equals(unresolvedTypeVariables))
02479 {
02480 IntSet unprocessed = (IntSet) unresolvedTypeVariables.clone();
02481 unprocessed.xor(processed);
02482 int[] unprocessedElements = unprocessed.elements();
02483
02484 for(int i = 0; i < unprocessedElements.length; i++)
02485 {
02486 TypeVariable var =
02487 (TypeVariable) typeVariableInstances.elementAt(unprocessedElements[i]);
02488
02489 if((!var.isEcrArray()) ||
02490 processed.get(var.getEcrIsArrayOf().getEcrId()) ||
02491 (!unresolvedTypeVariables.get(var.getEcrIsArrayOf().getEcrId())))
02492 {
02493 processed.set(var.getEcrId());
02494 processedList.add(var);
02495 }
02496 }
02497 }
02498
02499 elements = new int[processedList.size()];
02500 int index = 0;
02501 for(Iterator i = processedList.iterator(); i.hasNext();)
02502 {
02503 elements[index++] = ((TypeVariable) i.next()).getEcrId();
02504 }
02505 }
02506
02507 class RecursiveFunction
02508 {
02509 int index = 0;
02510
02511 public boolean resolve()
02512 {
02513 if(index == elements.length)
02514 {
02515 return true;
02516 }
02517
02518 TypeVariable var =
02519 (TypeVariable) typeVariableInstances.elementAt(elements[index++]);
02520
02521 for(int i = 0; i < ecrInstances.length; i++)
02522 {
02523 if(var.setEcrTypeNode(ecrInstances[i].getEcrTypeNode()))
02524 {
02525 if(resolve())
02526 {
02527 return true;
02528 }
02529 var.unsetEcrTypeNode();
02530 }
02531 }
02532 index--;
02533
02534 return false;
02535 }
02536 }
02537
02538 return new RecursiveFunction().resolve();
02539 }
02540
02541
02542
02543
02544
02545
02546 private boolean resolveSingleRelations()
02547 {
02548 boolean modified = false;
02549
02550 int[] elements = unresolvedTypeVariables.elements();
02551 for(int i = 0; i < elements.length; i++)
02552 {
02553 TypeVariable var = (TypeVariable) typeVariableInstances.elementAt(elements[i]);
02554
02555 if(var.getEcrTypeNode() == null)
02556 {
02557 TypeVariable[] parents = var.getEcrParents();
02558 TypeVariable[] children = var.getEcrChildren();
02559
02560 if(children.length == 1 && children[0] != getTypeVariable(NullType.v()))
02561 {
02562 modified = true;
02563 var.ecrUnion(children[0]);
02564 }
02565 else if(parents.length == 1)
02566 {
02567 modified = true;
02568 var.ecrUnion(parents[0]);
02569 }
02570 else if(parents.length == 0)
02571 {
02572 TypeVariable var2 = getTypeVariable(RefType.v("java.lang.Object"));
02573 modified = true;
02574 var.ecrUnion(var2);
02575 }
02576 else if(children.length == 0)
02577 {
02578 TypeVariable var2 = getTypeVariable(NullType.v());
02579 modified = true;
02580 var.ecrUnion(var2);
02581 }
02582 else if(children.length == 1)
02583 {
02584 modified = true;
02585 var.ecrUnion(children[0]);
02586 }
02587 }
02588 }
02589
02590 return modified;
02591 }
02592 }