fix bugs and changes on method checking
[IRC.git] / Robust / src / Analysis / SSJava / FlowDownCheck.java
1 package Analysis.SSJava;
2
3 import java.util.ArrayList;
4 import java.util.HashSet;
5 import java.util.Hashtable;
6 import java.util.Iterator;
7 import java.util.List;
8 import java.util.Set;
9 import java.util.StringTokenizer;
10 import java.util.Vector;
11
12 import Analysis.SSJava.FlowDownCheck.ComparisonResult;
13 import Analysis.SSJava.FlowDownCheck.CompositeLattice;
14 import IR.AnnotationDescriptor;
15 import IR.ClassDescriptor;
16 import IR.Descriptor;
17 import IR.FieldDescriptor;
18 import IR.MethodDescriptor;
19 import IR.NameDescriptor;
20 import IR.Operation;
21 import IR.State;
22 import IR.SymbolTable;
23 import IR.TypeDescriptor;
24 import IR.VarDescriptor;
25 import IR.Tree.ArrayAccessNode;
26 import IR.Tree.AssignmentNode;
27 import IR.Tree.BlockExpressionNode;
28 import IR.Tree.BlockNode;
29 import IR.Tree.BlockStatementNode;
30 import IR.Tree.CastNode;
31 import IR.Tree.CreateObjectNode;
32 import IR.Tree.DeclarationNode;
33 import IR.Tree.ExpressionNode;
34 import IR.Tree.FieldAccessNode;
35 import IR.Tree.IfStatementNode;
36 import IR.Tree.Kind;
37 import IR.Tree.LiteralNode;
38 import IR.Tree.LoopNode;
39 import IR.Tree.MethodInvokeNode;
40 import IR.Tree.NameNode;
41 import IR.Tree.OpNode;
42 import IR.Tree.ReturnNode;
43 import IR.Tree.SubBlockNode;
44 import IR.Tree.TertiaryNode;
45 import IR.Tree.TreeNode;
46 import Util.Pair;
47
48 public class FlowDownCheck {
49
50   State state;
51   static SSJavaAnalysis ssjava;
52
53   HashSet toanalyze;
54
55   // mapping from 'descriptor' to 'composite location'
56   Hashtable<Descriptor, CompositeLocation> d2loc;
57
58   Hashtable<MethodDescriptor, CompositeLocation> md2ReturnLoc;
59   Hashtable<MethodDescriptor, ReturnLocGenerator> md2ReturnLocGen;
60
61   // mapping from 'locID' to 'class descriptor'
62   Hashtable<String, ClassDescriptor> fieldLocName2cd;
63
64   public FlowDownCheck(SSJavaAnalysis ssjava, State state) {
65     this.ssjava = ssjava;
66     this.state = state;
67     this.toanalyze = new HashSet();
68     this.d2loc = new Hashtable<Descriptor, CompositeLocation>();
69     this.fieldLocName2cd = new Hashtable<String, ClassDescriptor>();
70     this.md2ReturnLoc = new Hashtable<MethodDescriptor, CompositeLocation>();
71     this.md2ReturnLocGen = new Hashtable<MethodDescriptor, ReturnLocGenerator>();
72   }
73
74   public void init() {
75
76     // construct mapping from the location name to the class descriptor
77     // assume that the location name is unique through the whole program
78
79     Set<ClassDescriptor> cdSet = ssjava.getCd2lattice().keySet();
80     for (Iterator iterator = cdSet.iterator(); iterator.hasNext();) {
81       ClassDescriptor cd = (ClassDescriptor) iterator.next();
82       SSJavaLattice<String> lattice = ssjava.getCd2lattice().get(cd);
83       Set<String> fieldLocNameSet = lattice.getKeySet();
84
85       for (Iterator iterator2 = fieldLocNameSet.iterator(); iterator2.hasNext();) {
86         String fieldLocName = (String) iterator2.next();
87         fieldLocName2cd.put(fieldLocName, cd);
88       }
89
90     }
91
92   }
93
94   public void flowDownCheck() {
95     SymbolTable classtable = state.getClassSymbolTable();
96
97     // phase 1 : checking declaration node and creating mapping of 'type
98     // desciptor' & 'location'
99     toanalyze.addAll(classtable.getValueSet());
100     toanalyze.addAll(state.getTaskSymbolTable().getValueSet());
101     while (!toanalyze.isEmpty()) {
102       Object obj = toanalyze.iterator().next();
103       ClassDescriptor cd = (ClassDescriptor) obj;
104       toanalyze.remove(cd);
105
106       if (!cd.isInterface()) {
107
108         ClassDescriptor superDesc = cd.getSuperDesc();
109         if (superDesc != null && (!superDesc.isInterface())
110             && (!superDesc.getSymbol().equals("Object"))) {
111           checkOrderingInheritance(superDesc, cd);
112         }
113
114         checkDeclarationInClass(cd);
115         for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
116           MethodDescriptor md = (MethodDescriptor) method_it.next();
117           if (ssjava.hasAnnotation(md)) {
118             checkDeclarationInMethodBody(cd, md);
119           }
120         }
121       }
122
123     }
124
125     // phase2 : checking assignments
126     toanalyze.addAll(classtable.getValueSet());
127     toanalyze.addAll(state.getTaskSymbolTable().getValueSet());
128     while (!toanalyze.isEmpty()) {
129       Object obj = toanalyze.iterator().next();
130       ClassDescriptor cd = (ClassDescriptor) obj;
131       toanalyze.remove(cd);
132
133       checkClass(cd);
134       for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
135         MethodDescriptor md = (MethodDescriptor) method_it.next();
136         if (ssjava.hasAnnotation(md)) {
137           checkMethodBody(cd, md);
138         }
139       }
140     }
141
142   }
143
144   private void checkOrderingInheritance(ClassDescriptor superCd, ClassDescriptor cd) {
145     // here, we're going to check that sub class keeps same relative orderings
146     // in respect to super class
147
148     SSJavaLattice<String> superLattice = ssjava.getClassLattice(superCd);
149     SSJavaLattice<String> subLattice = ssjava.getClassLattice(cd);
150
151     if (superLattice != null && subLattice == null) {
152       throw new Error("If a parent class '" + superCd + "' has a ordering lattice, its subclass '"
153           + cd + "' should have one.");
154     }
155
156     Set<Pair<String, String>> superPairSet = superLattice.getOrderingPairSet();
157     Set<Pair<String, String>> subPairSet = subLattice.getOrderingPairSet();
158
159     for (Iterator iterator = superPairSet.iterator(); iterator.hasNext();) {
160       Pair<String, String> pair = (Pair<String, String>) iterator.next();
161
162       if (!subPairSet.contains(pair)) {
163         throw new Error("Subclass '" + cd + "' does not have the relative ordering '"
164             + pair.getSecond() + " < " + pair.getFirst() + "' that is defined by its superclass '"
165             + superCd + "'.");
166       }
167     }
168
169   }
170
171   public Hashtable getMap() {
172     return d2loc;
173   }
174
175   private void checkDeclarationInMethodBody(ClassDescriptor cd, MethodDescriptor md) {
176     BlockNode bn = state.getMethodBody(md);
177
178     // parsing returnloc annotation
179     if (ssjava.hasAnnotation(md)) {
180       Vector<AnnotationDescriptor> methodAnnotations = md.getModifiers().getAnnotations();
181       if (methodAnnotations != null) {
182         for (int i = 0; i < methodAnnotations.size(); i++) {
183           AnnotationDescriptor an = methodAnnotations.elementAt(i);
184           if (an.getMarker().equals(ssjava.RETURNLOC)) {
185             // developer explicitly defines method lattice
186             String returnLocDeclaration = an.getValue();
187             CompositeLocation returnLocComp =
188                 parseLocationDeclaration(md, null, returnLocDeclaration);
189             md2ReturnLoc.put(md, returnLocComp);
190           }
191         }
192
193         if (!md.getReturnType().isVoid() && !md2ReturnLoc.containsKey(md)) {
194           throw new Error("Return location is not specified for the method " + md + " at "
195               + cd.getSourceFileName());
196         }
197
198       }
199     }
200
201     List<CompositeLocation> paramList = new ArrayList<CompositeLocation>();
202
203     boolean hasReturnValue = (!md.getReturnType().isVoid());
204     if (hasReturnValue) {
205       MethodLattice<String> methodLattice = ssjava.getMethodLattice(md);
206       String thisLocId = methodLattice.getThisLoc();
207       CompositeLocation thisLoc = new CompositeLocation(new Location(md, thisLocId));
208       paramList.add(thisLoc);
209     }
210
211     for (int i = 0; i < md.numParameters(); i++) {
212       // process annotations on method parameters
213       VarDescriptor vd = (VarDescriptor) md.getParameter(i);
214       assignLocationOfVarDescriptor(vd, md, md.getParameterTable(), bn);
215       if (hasReturnValue) {
216         paramList.add(d2loc.get(vd));
217       }
218     }
219
220     if (hasReturnValue) {
221       md2ReturnLocGen.put(md, new ReturnLocGenerator(md2ReturnLoc.get(md), paramList));
222     }
223
224     checkDeclarationInBlockNode(md, md.getParameterTable(), bn);
225   }
226
227   private void checkDeclarationInBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
228     bn.getVarTable().setParent(nametable);
229     for (int i = 0; i < bn.size(); i++) {
230       BlockStatementNode bsn = bn.get(i);
231       checkDeclarationInBlockStatementNode(md, bn.getVarTable(), bsn);
232     }
233   }
234
235   private void checkDeclarationInBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
236       BlockStatementNode bsn) {
237
238     switch (bsn.kind()) {
239     case Kind.SubBlockNode:
240       checkDeclarationInSubBlockNode(md, nametable, (SubBlockNode) bsn);
241       return;
242
243     case Kind.DeclarationNode:
244       checkDeclarationNode(md, nametable, (DeclarationNode) bsn);
245       break;
246
247     case Kind.LoopNode:
248       checkDeclarationInLoopNode(md, nametable, (LoopNode) bsn);
249       break;
250     }
251   }
252
253   private void checkDeclarationInLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
254
255     if (ln.getType() == LoopNode.FORLOOP) {
256       // check for loop case
257       ClassDescriptor cd = md.getClassDesc();
258       BlockNode bn = ln.getInitializer();
259       for (int i = 0; i < bn.size(); i++) {
260         BlockStatementNode bsn = bn.get(i);
261         checkDeclarationInBlockStatementNode(md, nametable, bsn);
262       }
263     }
264
265     // check loop body
266     checkDeclarationInBlockNode(md, nametable, ln.getBody());
267   }
268
269   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
270     BlockNode bn = state.getMethodBody(md);
271     checkLocationFromBlockNode(md, md.getParameterTable(), bn);
272   }
273
274   private CompositeLocation checkLocationFromBlockNode(MethodDescriptor md, SymbolTable nametable,
275       BlockNode bn) {
276
277     bn.getVarTable().setParent(nametable);
278     // it will return the lowest location in the block node
279     CompositeLocation lowestLoc = null;
280
281     for (int i = 0; i < bn.size(); i++) {
282       BlockStatementNode bsn = bn.get(i);
283       CompositeLocation bLoc = checkLocationFromBlockStatementNode(md, bn.getVarTable(), bsn);
284       if (!bLoc.isEmpty()) {
285         if (lowestLoc == null) {
286           lowestLoc = bLoc;
287         } else {
288           if (CompositeLattice.isGreaterThan(lowestLoc, bLoc)) {
289             lowestLoc = bLoc;
290           }
291         }
292       }
293
294     }
295     return lowestLoc;
296   }
297
298   private CompositeLocation checkLocationFromBlockStatementNode(MethodDescriptor md,
299       SymbolTable nametable, BlockStatementNode bsn) {
300
301     CompositeLocation compLoc = null;
302     switch (bsn.kind()) {
303     case Kind.BlockExpressionNode:
304       compLoc = checkLocationFromBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
305       break;
306
307     case Kind.DeclarationNode:
308       compLoc = checkLocationFromDeclarationNode(md, nametable, (DeclarationNode) bsn);
309       break;
310
311     case Kind.IfStatementNode:
312       compLoc = checkLocationFromIfStatementNode(md, nametable, (IfStatementNode) bsn);
313       break;
314
315     case Kind.LoopNode:
316       compLoc = checkLocationFromLoopNode(md, nametable, (LoopNode) bsn);
317       break;
318
319     case Kind.ReturnNode:
320       compLoc = checkLocationFromReturnNode(md, nametable, (ReturnNode) bsn);
321       break;
322
323     case Kind.SubBlockNode:
324       compLoc = checkLocationFromSubBlockNode(md, nametable, (SubBlockNode) bsn);
325       break;
326
327     // case Kind.ContinueBreakNode:
328     // checkLocationFromContinueBreakNode(md, nametable,(ContinueBreakNode)
329     // bsn);
330     // return null;
331     }
332     return compLoc;
333   }
334
335   private CompositeLocation checkLocationFromReturnNode(MethodDescriptor md, SymbolTable nametable,
336       ReturnNode rn) {
337
338     ExpressionNode returnExp = rn.getReturnExpression();
339
340     CompositeLocation expLoc =
341         checkLocationFromExpressionNode(md, nametable, returnExp, new CompositeLocation());
342
343     // by default, return node has "bottom" location
344     CompositeLocation loc = new CompositeLocation();
345     loc.addLocation(Location.createBottomLocation(md));
346     return loc;
347   }
348
349   private boolean hasOnlyLiteralValue(ExpressionNode en) {
350     if (en.kind() == Kind.LiteralNode) {
351       return true;
352     } else {
353       return false;
354     }
355   }
356
357   private CompositeLocation checkLocationFromLoopNode(MethodDescriptor md, SymbolTable nametable,
358       LoopNode ln) {
359
360     ClassDescriptor cd = md.getClassDesc();
361     if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
362
363       CompositeLocation condLoc =
364           checkLocationFromExpressionNode(md, nametable, ln.getCondition(), new CompositeLocation());
365       addTypeLocation(ln.getCondition().getType(), (condLoc));
366
367       CompositeLocation bodyLoc = checkLocationFromBlockNode(md, nametable, ln.getBody());
368
369       if (!CompositeLattice.isGreaterThan(condLoc, bodyLoc)) {
370         // loop condition should be higher than loop body
371         throw new Error(
372             "The location of the while-condition statement is lower than the loop body at "
373                 + cd.getSourceFileName() + ":" + ln.getCondition().getNumLine());
374       }
375
376       return bodyLoc;
377
378     } else {
379       // check for loop case
380       BlockNode bn = ln.getInitializer();
381       bn.getVarTable().setParent(nametable);
382
383       // calculate glb location of condition and update statements
384       CompositeLocation condLoc =
385           checkLocationFromExpressionNode(md, bn.getVarTable(), ln.getCondition(),
386               new CompositeLocation());
387       addTypeLocation(ln.getCondition().getType(), condLoc);
388
389       CompositeLocation updateLoc =
390           checkLocationFromBlockNode(md, bn.getVarTable(), ln.getUpdate());
391
392       Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
393       glbInputSet.add(condLoc);
394       glbInputSet.add(updateLoc);
395
396       CompositeLocation glbLocOfForLoopCond = CompositeLattice.calculateGLB(glbInputSet);
397
398       // check location of 'forloop' body
399       CompositeLocation blockLoc = checkLocationFromBlockNode(md, bn.getVarTable(), ln.getBody());
400
401       if (blockLoc == null) {
402         // when there is no statement in the loop body
403         return glbLocOfForLoopCond;
404       }
405
406       if (!CompositeLattice.isGreaterThan(glbLocOfForLoopCond, blockLoc)) {
407         throw new Error(
408             "The location of the for-condition statement is lower than the for-loop body at "
409                 + cd.getSourceFileName() + ":" + ln.getCondition().getNumLine());
410       }
411       return blockLoc;
412     }
413
414   }
415
416   private CompositeLocation checkLocationFromSubBlockNode(MethodDescriptor md,
417       SymbolTable nametable, SubBlockNode sbn) {
418     CompositeLocation compLoc = checkLocationFromBlockNode(md, nametable, sbn.getBlockNode());
419     return compLoc;
420   }
421
422   private CompositeLocation checkLocationFromIfStatementNode(MethodDescriptor md,
423       SymbolTable nametable, IfStatementNode isn) {
424
425     ClassDescriptor localCD = md.getClassDesc();
426     Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
427
428     CompositeLocation condLoc =
429         checkLocationFromExpressionNode(md, nametable, isn.getCondition(), new CompositeLocation());
430
431     addTypeLocation(isn.getCondition().getType(), condLoc);
432     glbInputSet.add(condLoc);
433
434     CompositeLocation locTrueBlock = checkLocationFromBlockNode(md, nametable, isn.getTrueBlock());
435     if (locTrueBlock != null) {
436       glbInputSet.add(locTrueBlock);
437       // here, the location of conditional block should be higher than the
438       // location of true/false blocks
439       if (locTrueBlock != null && !CompositeLattice.isGreaterThan(condLoc, locTrueBlock)) {
440         // error
441         throw new Error(
442             "The location of the if-condition statement is lower than the conditional block at "
443                 + localCD.getSourceFileName() + ":" + isn.getCondition().getNumLine());
444       }
445     }
446
447     if (isn.getFalseBlock() != null) {
448       CompositeLocation locFalseBlock =
449           checkLocationFromBlockNode(md, nametable, isn.getFalseBlock());
450
451       if (locFalseBlock != null) {
452         glbInputSet.add(locFalseBlock);
453
454         if (!CompositeLattice.isGreaterThan(condLoc, locFalseBlock)) {
455           // error
456           throw new Error(
457               "The location of the if-condition statement is lower than the conditional block at "
458                   + localCD.getSourceFileName() + ":" + isn.getCondition().getNumLine());
459         }
460       }
461
462     }
463
464     // return GLB location of condition, true, and false block
465     CompositeLocation glbLoc = CompositeLattice.calculateGLB(glbInputSet);
466
467     return glbLoc;
468   }
469
470   private CompositeLocation checkLocationFromDeclarationNode(MethodDescriptor md,
471       SymbolTable nametable, DeclarationNode dn) {
472
473     VarDescriptor vd = dn.getVarDescriptor();
474
475     CompositeLocation destLoc = d2loc.get(vd);
476
477     if (dn.getExpression() != null) {
478       CompositeLocation expressionLoc =
479           checkLocationFromExpressionNode(md, nametable, dn.getExpression(),
480               new CompositeLocation());
481       // addTypeLocation(dn.getExpression().getType(), expressionLoc);
482
483       if (expressionLoc != null) {
484         // checking location order
485         if (!CompositeLattice.isGreaterThan(expressionLoc, destLoc)) {
486           throw new Error("The value flow from " + expressionLoc + " to " + destLoc
487               + " does not respect location hierarchy on the assignment " + dn.printNode(0)
488               + " at " + md.getClassDesc().getSourceFileName() + "::" + dn.getNumLine());
489         }
490       }
491       return expressionLoc;
492
493     } else {
494
495       return new CompositeLocation();
496
497     }
498
499   }
500
501   private void checkDeclarationInSubBlockNode(MethodDescriptor md, SymbolTable nametable,
502       SubBlockNode sbn) {
503     checkDeclarationInBlockNode(md, nametable.getParent(), sbn.getBlockNode());
504   }
505
506   private CompositeLocation checkLocationFromBlockExpressionNode(MethodDescriptor md,
507       SymbolTable nametable, BlockExpressionNode ben) {
508     CompositeLocation compLoc =
509         checkLocationFromExpressionNode(md, nametable, ben.getExpression(), null);
510     // addTypeLocation(ben.getExpression().getType(), compLoc);
511     return compLoc;
512   }
513
514   private CompositeLocation checkLocationFromExpressionNode(MethodDescriptor md,
515       SymbolTable nametable, ExpressionNode en, CompositeLocation loc) {
516
517     CompositeLocation compLoc = null;
518     switch (en.kind()) {
519
520     case Kind.AssignmentNode:
521       compLoc = checkLocationFromAssignmentNode(md, nametable, (AssignmentNode) en, loc);
522       break;
523
524     case Kind.FieldAccessNode:
525       compLoc = checkLocationFromFieldAccessNode(md, nametable, (FieldAccessNode) en, loc);
526       break;
527
528     case Kind.NameNode:
529       compLoc = checkLocationFromNameNode(md, nametable, (NameNode) en, loc);
530       break;
531
532     case Kind.OpNode:
533       compLoc = checkLocationFromOpNode(md, nametable, (OpNode) en);
534       break;
535
536     case Kind.CreateObjectNode:
537       compLoc = checkLocationFromCreateObjectNode(md, nametable, (CreateObjectNode) en);
538       break;
539
540     case Kind.ArrayAccessNode:
541       compLoc = checkLocationFromArrayAccessNode(md, nametable, (ArrayAccessNode) en);
542       break;
543
544     case Kind.LiteralNode:
545       compLoc = checkLocationFromLiteralNode(md, nametable, (LiteralNode) en, loc);
546       break;
547
548     case Kind.MethodInvokeNode:
549       compLoc = checkLocationFromMethodInvokeNode(md, nametable, (MethodInvokeNode) en, loc);
550       break;
551
552     case Kind.TertiaryNode:
553       compLoc = checkLocationFromTertiaryNode(md, nametable, (TertiaryNode) en);
554       break;
555
556     case Kind.CastNode:
557       compLoc = checkLocationFromCastNode(md, nametable, (CastNode) en);
558       break;
559
560     // case Kind.InstanceOfNode:
561     // checkInstanceOfNode(md, nametable, (InstanceOfNode) en, td);
562     // return null;
563
564     // case Kind.ArrayInitializerNode:
565     // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en,
566     // td);
567     // return null;
568
569     // case Kind.ClassTypeNode:
570     // checkClassTypeNode(md, nametable, (ClassTypeNode) en, td);
571     // return null;
572
573     // case Kind.OffsetNode:
574     // checkOffsetNode(md, nametable, (OffsetNode)en, td);
575     // return null;
576
577     default:
578       return null;
579
580     }
581     // addTypeLocation(en.getType(), compLoc);
582     return compLoc;
583
584   }
585
586   private CompositeLocation checkLocationFromCastNode(MethodDescriptor md, SymbolTable nametable,
587       CastNode cn) {
588
589     ExpressionNode en = cn.getExpression();
590     return checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation());
591
592   }
593
594   private CompositeLocation checkLocationFromTertiaryNode(MethodDescriptor md,
595       SymbolTable nametable, TertiaryNode tn) {
596     ClassDescriptor cd = md.getClassDesc();
597
598     CompositeLocation condLoc =
599         checkLocationFromExpressionNode(md, nametable, tn.getCond(), new CompositeLocation());
600     addTypeLocation(tn.getCond().getType(), condLoc);
601     CompositeLocation trueLoc =
602         checkLocationFromExpressionNode(md, nametable, tn.getTrueExpr(), new CompositeLocation());
603     addTypeLocation(tn.getTrueExpr().getType(), trueLoc);
604     CompositeLocation falseLoc =
605         checkLocationFromExpressionNode(md, nametable, tn.getFalseExpr(), new CompositeLocation());
606     addTypeLocation(tn.getFalseExpr().getType(), falseLoc);
607
608     // check if condLoc is higher than trueLoc & falseLoc
609     if (!CompositeLattice.isGreaterThan(condLoc, trueLoc)) {
610       throw new Error(
611           "The location of the condition expression is lower than the true expression at "
612               + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
613     }
614
615     if (!CompositeLattice.isGreaterThan(condLoc, falseLoc)) {
616       throw new Error(
617           "The location of the condition expression is lower than the true expression at "
618               + cd.getSourceFileName() + ":" + tn.getCond().getNumLine());
619     }
620
621     // then, return glb of trueLoc & falseLoc
622     Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
623     glbInputSet.add(trueLoc);
624     glbInputSet.add(falseLoc);
625
626     return CompositeLattice.calculateGLB(glbInputSet);
627   }
628
629   private CompositeLocation checkLocationFromMethodInvokeNode(MethodDescriptor md,
630       SymbolTable nametable, MethodInvokeNode min, CompositeLocation loc) {
631
632     checkCalleeConstraints(md, nametable, min);
633     if (!min.getMethod().getReturnType().isVoid()) {
634       CompositeLocation ceilingLoc = computeCeilingLocationForCaller(md, nametable, min);
635       return ceilingLoc;
636     }
637
638     return new CompositeLocation();
639
640   }
641
642   private CompositeLocation computeCeilingLocationForCaller(MethodDescriptor md,
643       SymbolTable nametable, MethodInvokeNode min) {
644
645     List<CompositeLocation> argList = new ArrayList<CompositeLocation>();
646
647     String thisLocId = ssjava.getMethodLattice(md).getThisLoc();
648     CompositeLocation thisLoc = new CompositeLocation(new Location(md, thisLocId));
649     argList.add(thisLoc);
650
651     for (int i = 0; i < min.numArgs(); i++) {
652       ExpressionNode en = min.getArg(i);
653       CompositeLocation callerArg =
654           checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation());
655       argList.add(callerArg);
656     }
657
658     return md2ReturnLocGen.get(min.getMethod()).computeReturnLocation(argList);
659
660   }
661
662   private void checkCalleeConstraints(MethodDescriptor md, SymbolTable nametable,
663       MethodInvokeNode min) {
664
665     if (min.numArgs() > 1) {
666       // caller needs to guarantee that it passes arguments in regarding to
667       // callee's hierarchy
668       for (int i = 0; i < min.numArgs(); i++) {
669         ExpressionNode en = min.getArg(i);
670         CompositeLocation callerArg1 =
671             checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation());
672
673         ClassDescriptor calleecd = min.getMethod().getClassDesc();
674         VarDescriptor calleevd = (VarDescriptor) min.getMethod().getParameter(i);
675         CompositeLocation calleeLoc1 = d2loc.get(calleevd);
676
677         if (!callerArg1.get(0).isTop()) {
678           // here, check if ordering relations among caller's args respect
679           // ordering relations in-between callee's args
680           for (int currentIdx = 0; currentIdx < min.numArgs(); currentIdx++) {
681             if (currentIdx != i) { // skip itself
682               ExpressionNode argExp = min.getArg(currentIdx);
683
684               CompositeLocation callerArg2 =
685                   checkLocationFromExpressionNode(md, nametable, argExp, new CompositeLocation());
686
687               VarDescriptor calleevd2 = (VarDescriptor) min.getMethod().getParameter(currentIdx);
688               CompositeLocation calleeLoc2 = d2loc.get(calleevd2);
689
690               boolean callerResult = CompositeLattice.isGreaterThan(callerArg1, callerArg2);
691               boolean calleeResult = CompositeLattice.isGreaterThan(calleeLoc1, calleeLoc2);
692
693               if (calleeResult && !callerResult) {
694                 // If calleeLoc1 is higher than calleeLoc2
695                 // then, caller should have same ordering relation in-bet
696                 // callerLoc1 & callerLoc2
697
698                 throw new Error("Caller doesn't respect ordering relations among method arguments:"
699                     + md.getClassDesc().getSourceFileName() + ":" + min.getNumLine());
700               }
701
702             }
703           }
704         }
705
706       }
707
708     }
709
710   }
711
712   private CompositeLocation checkLocationFromArrayAccessNode(MethodDescriptor md,
713       SymbolTable nametable, ArrayAccessNode aan) {
714
715     // return glb location of array itself and index
716
717     ClassDescriptor cd = md.getClassDesc();
718
719     Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
720
721     CompositeLocation arrayLoc =
722         checkLocationFromExpressionNode(md, nametable, aan.getExpression(), new CompositeLocation());
723     // addTypeLocation(aan.getExpression().getType(), arrayLoc);
724     glbInputSet.add(arrayLoc);
725     CompositeLocation indexLoc =
726         checkLocationFromExpressionNode(md, nametable, aan.getIndex(), new CompositeLocation());
727     glbInputSet.add(indexLoc);
728     // addTypeLocation(aan.getIndex().getType(), indexLoc);
729
730     CompositeLocation glbLoc = CompositeLattice.calculateGLB(glbInputSet);
731     return glbLoc;
732   }
733
734   private CompositeLocation checkLocationFromCreateObjectNode(MethodDescriptor md,
735       SymbolTable nametable, CreateObjectNode con) {
736
737     ClassDescriptor cd = md.getClassDesc();
738
739     // check arguments
740     Set<CompositeLocation> glbInputSet = new HashSet<CompositeLocation>();
741     for (int i = 0; i < con.numArgs(); i++) {
742       ExpressionNode en = con.getArg(i);
743       CompositeLocation argLoc =
744           checkLocationFromExpressionNode(md, nametable, en, new CompositeLocation());
745       glbInputSet.add(argLoc);
746       addTypeLocation(en.getType(), argLoc);
747     }
748
749     // check array initializers
750     // if ((con.getArrayInitializer() != null)) {
751     // checkLocationFromArrayInitializerNode(md, nametable,
752     // con.getArrayInitializer());
753     // }
754
755     if (glbInputSet.size() > 0) {
756       return CompositeLattice.calculateGLB(glbInputSet);
757     }
758
759     CompositeLocation compLoc = new CompositeLocation();
760     compLoc.addLocation(Location.createTopLocation(md));
761     return compLoc;
762
763   }
764
765   private CompositeLocation checkLocationFromOpNode(MethodDescriptor md, SymbolTable nametable,
766       OpNode on) {
767
768     ClassDescriptor cd = md.getClassDesc();
769     CompositeLocation leftLoc = new CompositeLocation();
770     leftLoc = checkLocationFromExpressionNode(md, nametable, on.getLeft(), leftLoc);
771     // addTypeLocation(on.getLeft().getType(), leftLoc);
772
773     CompositeLocation rightLoc = new CompositeLocation();
774     if (on.getRight() != null) {
775       rightLoc = checkLocationFromExpressionNode(md, nametable, on.getRight(), rightLoc);
776       // addTypeLocation(on.getRight().getType(), rightLoc);
777     }
778
779     // System.out.println("checking op node=" + on.printNode(0));
780     // System.out.println("left loc=" + leftLoc + " from " +
781     // on.getLeft().getClass());
782     // System.out.println("right loc=" + rightLoc + " from " +
783     // on.getRight().getClass());
784
785     Operation op = on.getOp();
786
787     switch (op.getOp()) {
788
789     case Operation.UNARYPLUS:
790     case Operation.UNARYMINUS:
791     case Operation.LOGIC_NOT:
792       // single operand
793       return leftLoc;
794
795     case Operation.LOGIC_OR:
796     case Operation.LOGIC_AND:
797     case Operation.COMP:
798     case Operation.BIT_OR:
799     case Operation.BIT_XOR:
800     case Operation.BIT_AND:
801     case Operation.ISAVAILABLE:
802     case Operation.EQUAL:
803     case Operation.NOTEQUAL:
804     case Operation.LT:
805     case Operation.GT:
806     case Operation.LTE:
807     case Operation.GTE:
808     case Operation.ADD:
809     case Operation.SUB:
810     case Operation.MULT:
811     case Operation.DIV:
812     case Operation.MOD:
813     case Operation.LEFTSHIFT:
814     case Operation.RIGHTSHIFT:
815     case Operation.URIGHTSHIFT:
816
817       Set<CompositeLocation> inputSet = new HashSet<CompositeLocation>();
818       inputSet.add(leftLoc);
819       inputSet.add(rightLoc);
820       CompositeLocation glbCompLoc = CompositeLattice.calculateGLB(inputSet);
821       return glbCompLoc;
822
823     default:
824       throw new Error(op.toString());
825     }
826
827   }
828
829   private CompositeLocation checkLocationFromLiteralNode(MethodDescriptor md,
830       SymbolTable nametable, LiteralNode en, CompositeLocation loc) {
831
832     // literal value has the top location so that value can be flowed into any
833     // location
834     Location literalLoc = Location.createTopLocation(md);
835     loc.addLocation(literalLoc);
836     return loc;
837
838   }
839
840   private CompositeLocation checkLocationFromNameNode(MethodDescriptor md, SymbolTable nametable,
841       NameNode nn, CompositeLocation loc) {
842
843     NameDescriptor nd = nn.getName();
844     if (nd.getBase() != null) {
845
846       loc = checkLocationFromExpressionNode(md, nametable, nn.getExpression(), loc);
847       // addTypeLocation(nn.getExpression().getType(), loc);
848     } else {
849       String varname = nd.toString();
850
851       if (varname.equals("this")) {
852         // 'this' itself!
853         MethodLattice<String> methodLattice = ssjava.getMethodLattice(md);
854         String thisLocId = methodLattice.getThisLoc();
855         if (thisLocId == null) {
856           throw new Error("The location for 'this' is not defined at "
857               + md.getClassDesc().getSourceFileName() + "::" + nn.getNumLine());
858         }
859         Location locElement = new Location(md, thisLocId);
860         loc.addLocation(locElement);
861         return loc;
862       }
863       Descriptor d = (Descriptor) nametable.get(varname);
864
865       // CompositeLocation localLoc = null;
866       if (d instanceof VarDescriptor) {
867         VarDescriptor vd = (VarDescriptor) d;
868         // localLoc = d2loc.get(vd);
869         // the type of var descriptor has a composite location!
870         loc = ((CompositeLocation) vd.getType().getExtension()).clone();
871       } else if (d instanceof FieldDescriptor) {
872         // the type of field descriptor has a location!
873         FieldDescriptor fd = (FieldDescriptor) d;
874
875         if (fd.isStatic()) {
876           if (fd.isFinal()) {
877             // if it is 'static final', the location has TOP since no one can
878             // change its value
879             loc.addLocation(Location.createTopLocation(md));
880           } else {
881             // if 'static', the location has pre-assigned global loc
882             MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
883             String globalLocId = localLattice.getGlobalLoc();
884             if (globalLocId == null) {
885               throw new Error("Global location element is not defined in the method " + md);
886             }
887             Location globalLoc = new Location(md, globalLocId);
888
889             loc.addLocation(globalLoc);
890           }
891         } else {
892           // the location of field access starts from this, followed by field
893           // location
894           MethodLattice<String> localLattice = ssjava.getMethodLattice(md);
895           Location thisLoc = new Location(md, localLattice.getThisLoc());
896           loc.addLocation(thisLoc);
897         }
898
899         Location fieldLoc = (Location) fd.getType().getExtension();
900         loc.addLocation(fieldLoc);
901       }
902     }
903     return loc;
904   }
905
906   private CompositeLocation checkLocationFromFieldAccessNode(MethodDescriptor md,
907       SymbolTable nametable, FieldAccessNode fan, CompositeLocation loc) {
908
909     ExpressionNode left = fan.getExpression();
910     loc = checkLocationFromExpressionNode(md, nametable, left, loc);
911     // addTypeLocation(left.getType(), loc);
912
913     if (!left.getType().isPrimitive()) {
914       FieldDescriptor fd = fan.getField();
915       Location fieldLoc = (Location) fd.getType().getExtension();
916       loc.addLocation(fieldLoc);
917     }
918
919     return loc;
920   }
921
922   private CompositeLocation checkLocationFromAssignmentNode(MethodDescriptor md,
923       SymbolTable nametable, AssignmentNode an, CompositeLocation loc) {
924
925     ClassDescriptor cd = md.getClassDesc();
926
927     boolean postinc = true;
928     if (an.getOperation().getBaseOp() == null
929         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
930             .getBaseOp().getOp() != Operation.POSTDEC))
931       postinc = false;
932
933     CompositeLocation destLocation =
934         checkLocationFromExpressionNode(md, nametable, an.getDest(), new CompositeLocation());
935
936     CompositeLocation srcLocation = new CompositeLocation();
937
938     if (!postinc) {
939       if (hasOnlyLiteralValue(an.getSrc())) {
940         // if source is literal value, src location is TOP. so do not need to
941         // compare!
942         return destLocation;
943       }
944       srcLocation = new CompositeLocation();
945       srcLocation = checkLocationFromExpressionNode(md, nametable, an.getSrc(), srcLocation);
946       // System.out.println(" an= " + an.printNode(0) + " an.getSrc()=" +
947       // an.getSrc().getClass()
948       // + " at " + cd.getSourceFileName() + "::" + an.getNumLine());
949       // System.out.println("srcLocation=" + srcLocation);
950       // System.out.println("dstLocation=" + destLocation);
951       if (!CompositeLattice.isGreaterThan(srcLocation, destLocation)) {
952         throw new Error("The value flow from " + srcLocation + " to " + destLocation
953             + " does not respect location hierarchy on the assignment " + an.printNode(0) + " at "
954             + cd.getSourceFileName() + "::" + an.getNumLine());
955       }
956     } else {
957       destLocation =
958           srcLocation = checkLocationFromExpressionNode(md, nametable, an.getDest(), srcLocation);
959
960       if (!CompositeLattice.isGreaterThan(srcLocation, destLocation)) {
961         throw new Error("Location " + destLocation
962             + " is not allowed to have the value flow that moves within the same location at "
963             + cd.getSourceFileName() + "::" + an.getNumLine());
964       }
965
966     }
967
968     return destLocation;
969   }
970
971   private void assignLocationOfVarDescriptor(VarDescriptor vd, MethodDescriptor md,
972       SymbolTable nametable, TreeNode n) {
973
974     ClassDescriptor cd = md.getClassDesc();
975     Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
976
977     // currently enforce every variable to have corresponding location
978     if (annotationVec.size() == 0) {
979       throw new Error("Location is not assigned to variable " + vd.getSymbol() + " in the method "
980           + md.getSymbol() + " of the class " + cd.getSymbol());
981     }
982
983     if (annotationVec.size() > 1) { // variable can have at most one location
984       throw new Error(vd.getSymbol() + " has more than one location.");
985     }
986
987     AnnotationDescriptor ad = annotationVec.elementAt(0);
988
989     if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
990
991       if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
992         String locDec = ad.getValue(); // check if location is defined
993
994         if (locDec.startsWith(SSJavaAnalysis.DELTA)) {
995           DeltaLocation deltaLoc = parseDeltaDeclaration(md, n, locDec);
996           d2loc.put(vd, deltaLoc);
997           addTypeLocation(vd.getType(), deltaLoc);
998         } else {
999           CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
1000           d2loc.put(vd, compLoc);
1001           addTypeLocation(vd.getType(), compLoc);
1002         }
1003
1004       }
1005     }
1006
1007   }
1008
1009   private DeltaLocation parseDeltaDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
1010
1011     int deltaCount = 0;
1012     int dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
1013     while (dIdx >= 0) {
1014       deltaCount++;
1015       int beginIdx = dIdx + 6;
1016       locDec = locDec.substring(beginIdx, locDec.length() - 1);
1017       dIdx = locDec.indexOf(SSJavaAnalysis.DELTA);
1018     }
1019
1020     CompositeLocation compLoc = parseLocationDeclaration(md, n, locDec);
1021     DeltaLocation deltaLoc = new DeltaLocation(compLoc, deltaCount);
1022
1023     return deltaLoc;
1024   }
1025
1026   private Location parseFieldLocDeclaraton(String decl) {
1027
1028     int idx = decl.indexOf(".");
1029     String className = decl.substring(0, idx);
1030     String fieldName = decl.substring(idx + 1);
1031
1032     Descriptor d = state.getClassSymbolTable().get(className);
1033
1034     assert (d instanceof ClassDescriptor);
1035     SSJavaLattice<String> lattice = ssjava.getClassLattice((ClassDescriptor) d);
1036     if (!lattice.containsKey(fieldName)) {
1037       throw new Error("The location " + fieldName + " is not defined in the field lattice of '"
1038           + className + "'.");
1039     }
1040
1041     return new Location(d, fieldName);
1042   }
1043
1044   private CompositeLocation parseLocationDeclaration(MethodDescriptor md, TreeNode n, String locDec) {
1045
1046     CompositeLocation compLoc = new CompositeLocation();
1047
1048     StringTokenizer tokenizer = new StringTokenizer(locDec, ",");
1049     List<String> locIdList = new ArrayList<String>();
1050     while (tokenizer.hasMoreTokens()) {
1051       String locId = tokenizer.nextToken();
1052       locIdList.add(locId);
1053     }
1054
1055     // at least,one location element needs to be here!
1056     assert (locIdList.size() > 0);
1057
1058     // assume that loc with idx 0 comes from the local lattice
1059     // loc with idx 1 comes from the field lattice
1060
1061     String localLocId = locIdList.get(0);
1062     SSJavaLattice<String> localLattice = CompositeLattice.getLatticeByDescriptor(md);
1063     Location localLoc = new Location(md, localLocId);
1064     if (localLattice == null || (!localLattice.containsKey(localLocId))) {
1065       throw new Error("Location " + localLocId
1066           + " is not defined in the local variable lattice at "
1067           + md.getClassDesc().getSourceFileName() + "::" + (n != null ? n.getNumLine() : "") + ".");
1068     }
1069     compLoc.addLocation(localLoc);
1070
1071     for (int i = 1; i < locIdList.size(); i++) {
1072       String locName = locIdList.get(i);
1073
1074       Location fieldLoc = parseFieldLocDeclaraton(locName);
1075       // ClassDescriptor cd = fieldLocName2cd.get(locName);
1076       // SSJavaLattice<String> fieldLattice =
1077       // CompositeLattice.getLatticeByDescriptor(cd);
1078       //
1079       // if (fieldLattice == null || (!fieldLattice.containsKey(locName))) {
1080       // throw new Error("Location " + locName +
1081       // " is not defined in the field lattice at "
1082       // + cd.getSourceFileName() + ".");
1083       // }
1084       // Location fieldLoc = new Location(cd, locName);
1085       compLoc.addLocation(fieldLoc);
1086     }
1087
1088     return compLoc;
1089
1090   }
1091
1092   private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
1093     VarDescriptor vd = dn.getVarDescriptor();
1094     assignLocationOfVarDescriptor(vd, md, nametable, dn);
1095   }
1096
1097   private void checkClass(ClassDescriptor cd) {
1098     // Check to see that methods respects ss property
1099     for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
1100       MethodDescriptor md = (MethodDescriptor) method_it.next();
1101       checkMethodDeclaration(cd, md);
1102     }
1103   }
1104
1105   private void checkDeclarationInClass(ClassDescriptor cd) {
1106     // Check to see that fields are okay
1107     for (Iterator field_it = cd.getFields(); field_it.hasNext();) {
1108       FieldDescriptor fd = (FieldDescriptor) field_it.next();
1109       checkFieldDeclaration(cd, fd);
1110     }
1111   }
1112
1113   private void checkMethodDeclaration(ClassDescriptor cd, MethodDescriptor md) {
1114     // TODO
1115   }
1116
1117   private void checkFieldDeclaration(ClassDescriptor cd, FieldDescriptor fd) {
1118
1119     Vector<AnnotationDescriptor> annotationVec = fd.getType().getAnnotationMarkers();
1120
1121     // currently enforce every field to have corresponding location
1122     if (annotationVec.size() == 0) {
1123       throw new Error("Location is not assigned to the field " + fd.getSymbol() + " of the class "
1124           + cd.getSymbol());
1125     }
1126
1127     if (annotationVec.size() > 1) {
1128       // variable can have at most one location
1129       throw new Error("Field " + fd.getSymbol() + " of class " + cd
1130           + " has more than one location.");
1131     }
1132
1133     AnnotationDescriptor ad = annotationVec.elementAt(0);
1134
1135     if (ad.getType() == AnnotationDescriptor.SINGLE_ANNOTATION) {
1136
1137       if (ad.getMarker().equals(SSJavaAnalysis.LOC)) {
1138         String locationID = ad.getValue();
1139         // check if location is defined
1140         SSJavaLattice<String> lattice = ssjava.getClassLattice(cd);
1141         if (lattice == null || (!lattice.containsKey(locationID))) {
1142           throw new Error("Location " + locationID
1143               + " is not defined in the field lattice of class " + cd.getSymbol() + " at"
1144               + cd.getSourceFileName() + ".");
1145         }
1146         Location loc = new Location(cd, locationID);
1147         // d2loc.put(fd, loc);
1148         addTypeLocation(fd.getType(), loc);
1149
1150       }
1151     }
1152
1153   }
1154
1155   private void addTypeLocation(TypeDescriptor type, CompositeLocation loc) {
1156     if (type != null) {
1157       type.setExtension(loc);
1158     }
1159   }
1160
1161   private void addTypeLocation(TypeDescriptor type, Location loc) {
1162     if (type != null) {
1163       type.setExtension(loc);
1164     }
1165   }
1166
1167   static class CompositeLattice {
1168
1169     public static boolean isGreaterThan(CompositeLocation loc1, CompositeLocation loc2) {
1170
1171       // System.out.println("isGreaterThan= " + loc1 + " " + loc2);
1172
1173       int baseCompareResult = compareBaseLocationSet(loc1, loc2);
1174       if (baseCompareResult == ComparisonResult.EQUAL) {
1175         if (compareDelta(loc1, loc2) == ComparisonResult.GREATER) {
1176           return true;
1177         } else {
1178           return false;
1179         }
1180       } else if (baseCompareResult == ComparisonResult.GREATER) {
1181         return true;
1182       } else {
1183         return false;
1184       }
1185
1186     }
1187
1188     public static int compare(CompositeLocation loc1, CompositeLocation loc2) {
1189
1190 //      System.out.println("compare=" + loc1 + " " + loc2);
1191       int baseCompareResult = compareBaseLocationSet(loc1, loc2);
1192
1193       if (baseCompareResult == ComparisonResult.EQUAL) {
1194         return compareDelta(loc1, loc2);
1195       } else {
1196         return baseCompareResult;
1197       }
1198
1199     }
1200
1201     private static int compareDelta(CompositeLocation dLoc1, CompositeLocation dLoc2) {
1202
1203       int deltaCount1 = 0;
1204       int deltaCount2 = 0;
1205       if (dLoc1 instanceof DeltaLocation) {
1206         deltaCount1 = ((DeltaLocation) dLoc1).getNumDelta();
1207       }
1208
1209       if (dLoc2 instanceof DeltaLocation) {
1210         deltaCount2 = ((DeltaLocation) dLoc2).getNumDelta();
1211       }
1212       if (deltaCount1 < deltaCount2) {
1213         return ComparisonResult.GREATER;
1214       } else if (deltaCount1 == deltaCount2) {
1215         return ComparisonResult.EQUAL;
1216       } else {
1217         return ComparisonResult.LESS;
1218       }
1219
1220     }
1221
1222     private static int compareBaseLocationSet(CompositeLocation compLoc1, CompositeLocation compLoc2) {
1223
1224       // if compLoc1 is greater than compLoc2, return true
1225       // else return false;
1226
1227       // compare one by one in according to the order of the tuple
1228       int numOfTie = 0;
1229       for (int i = 0; i < compLoc1.getSize(); i++) {
1230         Location loc1 = compLoc1.get(i);
1231         if (i >= compLoc2.getSize()) {
1232           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1233               + " because they are not comparable.");
1234         }
1235         Location loc2 = compLoc2.get(i);
1236
1237         if (!loc1.getDescriptor().equals(loc2.getDescriptor())) {
1238           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1239               + " because they are not comparable.");
1240         }
1241
1242         Descriptor d1 = loc1.getDescriptor();
1243         Descriptor d2 = loc2.getDescriptor();
1244
1245         SSJavaLattice<String> lattice1 = getLatticeByDescriptor(d1);
1246         SSJavaLattice<String> lattice2 = getLatticeByDescriptor(d2);
1247
1248         // check if the spin location is appeared only at the end of the
1249         // composite location
1250         if (lattice1.getSpinLocSet().contains(loc1.getLocIdentifier())) {
1251           if (i != (compLoc1.getSize() - 1)) {
1252             throw new Error("The spin location " + loc1.getLocIdentifier()
1253                 + " cannot be appeared in the middle of composite location.");
1254           }
1255         }
1256
1257         if (lattice2.getSpinLocSet().contains(loc2.getLocIdentifier())) {
1258           if (i != (compLoc2.getSize() - 1)) {
1259             throw new Error("The spin location " + loc2.getLocIdentifier()
1260                 + " cannot be appeared in the middle of composite location.");
1261           }
1262         }
1263
1264         if (!lattice1.equals(lattice2)) {
1265           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1266               + " because they are not comparable.");
1267         }
1268
1269         if (loc1.getLocIdentifier().equals(loc2.getLocIdentifier())) {
1270           numOfTie++;
1271           // check if the current location is the spinning location
1272           // note that the spinning location only can be appeared in the last
1273           // part of the composite location
1274           if (numOfTie == compLoc1.getSize()
1275               && lattice1.getSpinLocSet().contains(loc1.getLocIdentifier())) {
1276             return ComparisonResult.GREATER;
1277           }
1278           continue;
1279         } else if (lattice1.isGreaterThan(loc1.getLocIdentifier(), loc2.getLocIdentifier())) {
1280           return ComparisonResult.GREATER;
1281         } else {
1282           return ComparisonResult.LESS;
1283         }
1284
1285       }
1286
1287       if (numOfTie == compLoc1.getSize()) {
1288
1289         if (numOfTie != compLoc2.getSize()) {
1290           throw new Error("Failed to compare two locations of " + compLoc1 + " and " + compLoc2
1291               + " because they are not comparable.");
1292         }
1293
1294         return ComparisonResult.EQUAL;
1295       }
1296
1297       return ComparisonResult.LESS;
1298
1299     }
1300
1301     public static CompositeLocation calculateGLB(Set<CompositeLocation> inputSet) {
1302
1303       // System.out.println("Calculating GLB=" + inputSet);
1304       CompositeLocation glbCompLoc = new CompositeLocation();
1305
1306       // calculate GLB of the first(priority) element
1307       Set<String> priorityLocIdentifierSet = new HashSet<String>();
1308       Descriptor priorityDescriptor = null;
1309
1310       Hashtable<String, Set<CompositeLocation>> locId2CompLocSet =
1311           new Hashtable<String, Set<CompositeLocation>>();
1312       // mapping from the priority loc ID to its full representation by the
1313       // composite location
1314
1315       for (Iterator iterator = inputSet.iterator(); iterator.hasNext();) {
1316         CompositeLocation compLoc = (CompositeLocation) iterator.next();
1317         Location priorityLoc = compLoc.get(0);
1318         String priorityLocId = priorityLoc.getLocIdentifier();
1319         priorityLocIdentifierSet.add(priorityLocId);
1320
1321         if (locId2CompLocSet.containsKey(priorityLocId)) {
1322           locId2CompLocSet.get(priorityLocId).add(compLoc);
1323         } else {
1324           Set<CompositeLocation> newSet = new HashSet<CompositeLocation>();
1325           newSet.add(compLoc);
1326           locId2CompLocSet.put(priorityLocId, newSet);
1327         }
1328
1329         // check if priority location are coming from the same lattice
1330         if (priorityDescriptor == null) {
1331           priorityDescriptor = priorityLoc.getDescriptor();
1332         } else if (!priorityDescriptor.equals(priorityLoc.getDescriptor())) {
1333           throw new Error("Failed to calculate GLB of " + inputSet
1334               + " because they are from different lattices.");
1335         }
1336       }
1337
1338       SSJavaLattice<String> locOrder = getLatticeByDescriptor(priorityDescriptor);
1339       String glbOfPriorityLoc = locOrder.getGLB(priorityLocIdentifierSet);
1340
1341       glbCompLoc.addLocation(new Location(priorityDescriptor, glbOfPriorityLoc));
1342       Set<CompositeLocation> compSet = locId2CompLocSet.get(glbOfPriorityLoc);
1343
1344       if (compSet == null) {
1345         // when GLB(x1,x2)!=x1 and !=x2 : GLB case 4
1346         // mean that the result is already lower than <x1,y1> and <x2,y2>
1347         // assign TOP to the rest of the location elements
1348
1349         // in this case, do not take care about delta
1350         CompositeLocation inputComp = inputSet.iterator().next();
1351         for (int i = 1; i < inputComp.getSize(); i++) {
1352           glbCompLoc.addLocation(Location.createTopLocation(inputComp.get(i).getDescriptor()));
1353         }
1354       } else {
1355         if (compSet.size() == 1) {
1356
1357           // if GLB(x1,x2)==x1 or x2 : GLB case 2,3
1358           CompositeLocation comp = compSet.iterator().next();
1359           for (int i = 1; i < comp.getSize(); i++) {
1360             glbCompLoc.addLocation(comp.get(i));
1361           }
1362
1363           // if input location corresponding to glb is a delta, need to apply
1364           // delta to glb result
1365           if (comp instanceof DeltaLocation) {
1366             glbCompLoc = new DeltaLocation(glbCompLoc, 1);
1367           }
1368
1369         } else {
1370           // when GLB(x1,x2)==x1 and x2 : GLB case 1
1371           // if more than one location shares the same priority GLB
1372           // need to calculate the rest of GLB loc
1373
1374           int compositeLocSize = compSet.iterator().next().getSize();
1375
1376           Set<String> glbInputSet = new HashSet<String>();
1377           Descriptor currentD = null;
1378           for (int i = 1; i < compositeLocSize; i++) {
1379             for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
1380               CompositeLocation compositeLocation = (CompositeLocation) iterator.next();
1381               Location currentLoc = compositeLocation.get(i);
1382               currentD = currentLoc.getDescriptor();
1383               // making set of the current location sharing the same idx
1384               glbInputSet.add(currentLoc.getLocIdentifier());
1385             }
1386             // calculate glb for the current lattice
1387
1388             SSJavaLattice<String> currentLattice = getLatticeByDescriptor(currentD);
1389             String currentGLBLocId = currentLattice.getGLB(glbInputSet);
1390             glbCompLoc.addLocation(new Location(currentD, currentGLBLocId));
1391           }
1392
1393           // if input location corresponding to glb is a delta, need to apply
1394           // delta to glb result
1395
1396           for (Iterator iterator = compSet.iterator(); iterator.hasNext();) {
1397             CompositeLocation compLoc = (CompositeLocation) iterator.next();
1398             if (compLoc instanceof DeltaLocation) {
1399               if (glbCompLoc.equals(compLoc)) {
1400                 glbCompLoc = new DeltaLocation(glbCompLoc, 1);
1401                 break;
1402               }
1403             }
1404           }
1405
1406         }
1407       }
1408
1409       return glbCompLoc;
1410
1411     }
1412
1413     static SSJavaLattice<String> getLatticeByDescriptor(Descriptor d) {
1414
1415       SSJavaLattice<String> lattice = null;
1416
1417       if (d instanceof ClassDescriptor) {
1418         lattice = ssjava.getCd2lattice().get(d);
1419       } else if (d instanceof MethodDescriptor) {
1420         if (ssjava.getMd2lattice().containsKey(d)) {
1421           lattice = ssjava.getMd2lattice().get(d);
1422         } else {
1423           // use default lattice for the method
1424           lattice = ssjava.getCd2methodDefault().get(((MethodDescriptor) d).getClassDesc());
1425         }
1426       }
1427
1428       return lattice;
1429     }
1430
1431   }
1432
1433   class ComparisonResult {
1434
1435     public static final int GREATER = 0;
1436     public static final int EQUAL = 1;
1437     public static final int LESS = 2;
1438     public static final int INCOMPARABLE = 3;
1439     int result;
1440
1441   }
1442
1443 }
1444
1445 class ReturnLocGenerator {
1446
1447   public static final int PARAMISHIGHER = 0;
1448   public static final int PARAMISSAME = 1;
1449   public static final int IGNORE = 2;
1450
1451   Hashtable<Integer, Integer> paramIdx2paramType;
1452
1453   public ReturnLocGenerator(CompositeLocation returnLoc, List<CompositeLocation> params) {
1454     // creating mappings
1455
1456     paramIdx2paramType = new Hashtable<Integer, Integer>();
1457     for (int i = 0; i < params.size(); i++) {
1458       CompositeLocation param = params.get(i);
1459       int compareResult = CompositeLattice.compare(param, returnLoc);
1460
1461       int type;
1462       if (compareResult == ComparisonResult.GREATER) {
1463         type = 0;
1464       } else if (compareResult == ComparisonResult.EQUAL) {
1465         type = 1;
1466       } else {
1467         type = 2;
1468       }
1469       paramIdx2paramType.put(new Integer(i), new Integer(type));
1470     }
1471
1472   }
1473
1474   public CompositeLocation computeReturnLocation(List<CompositeLocation> args) {
1475
1476     // compute the highest possible location in caller's side
1477     assert paramIdx2paramType.keySet().size() == args.size();
1478
1479     Set<CompositeLocation> inputGLB = new HashSet<CompositeLocation>();
1480     for (int i = 0; i < args.size(); i++) {
1481       int type = (paramIdx2paramType.get(new Integer(i))).intValue();
1482       CompositeLocation argLoc = args.get(i);
1483       if (type == PARAMISHIGHER) {
1484         // return loc is lower than param
1485         System.out.println("argLoc=" + argLoc);
1486         DeltaLocation delta = new DeltaLocation(argLoc, 1);
1487         inputGLB.add(delta);
1488       } else if (type == PARAMISSAME) {
1489         // return loc is equal or lower than param
1490         inputGLB.add(argLoc);
1491       }
1492     }
1493
1494     // compute GLB of arguments subset that are same or higher than return
1495     // location
1496     CompositeLocation glb = CompositeLattice.calculateGLB(inputGLB);
1497     return glb;
1498   }
1499 }