changes: fixes the case that a shared location appears in the middle of a composite...
[IRC.git] / Robust / src / Analysis / SSJava / LinearTypeCheck.java
index 4ba5d38bd43ee883483ef8325be0e33f8c0ebcbd..77b7de65ac7fce791395279587d2f816ee0a2272 100644 (file)
@@ -1,15 +1,19 @@
 package Analysis.SSJava;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Set;
 import java.util.Vector;
 
 import Analysis.Liveness;
 import IR.AnnotationDescriptor;
 import IR.ClassDescriptor;
-import IR.Descriptor;
+import IR.FieldDescriptor;
 import IR.MethodDescriptor;
 import IR.Operation;
 import IR.State;
@@ -52,7 +56,7 @@ public class LinearTypeCheck {
   State state;
   SSJavaAnalysis ssjava;
   String needToNullify = null;
-  AssignmentNode prevAssignNode;
+  TreeNode prevAssignNode;
 
   Set<TreeNode> linearTypeCheckSet;
 
@@ -62,6 +66,8 @@ public class LinearTypeCheck {
 
   Liveness liveness;
 
+  boolean deterministic = true;
+
   public LinearTypeCheck(SSJavaAnalysis ssjava, State state) {
     this.ssjava = ssjava;
     this.state = state;
@@ -84,12 +90,49 @@ public class LinearTypeCheck {
     }
 
     // second, check the linear type
-    it = state.getClassSymbolTable().getDescriptorsIterator();
-    while (it.hasNext()) {
-      ClassDescriptor cd = (ClassDescriptor) it.next();
-      for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
-        MethodDescriptor md = (MethodDescriptor) method_it.next();
-        checkMethodBody(cd, md);
+    if (deterministic) {
+
+      SymbolTable classtable = state.getClassSymbolTable();
+
+      List<ClassDescriptor> toanalyzeList = new ArrayList<ClassDescriptor>();
+      List<MethodDescriptor> toanalyzeMethodList = new ArrayList<MethodDescriptor>();
+
+      toanalyzeList.addAll(classtable.getValueSet());
+      Collections.sort(toanalyzeList, new Comparator<ClassDescriptor>() {
+        public int compare(ClassDescriptor o1, ClassDescriptor o2) {
+          return o1.getClassName().compareTo(o2.getClassName());
+        }
+      });
+
+      for (int i = 0; i < toanalyzeList.size(); i++) {
+        ClassDescriptor cd = toanalyzeList.get(i);
+
+        SymbolTable methodtable = cd.getMethodTable();
+        toanalyzeMethodList.clear();
+        toanalyzeMethodList.addAll(methodtable.getValueSet());
+        Collections.sort(toanalyzeMethodList, new Comparator<MethodDescriptor>() {
+          public int compare(MethodDescriptor o1, MethodDescriptor o2) {
+            return o1.getSymbol().compareTo(o2.getSymbol());
+          }
+        });
+
+        for (int mdIdx = 0; mdIdx < toanalyzeMethodList.size(); mdIdx++) {
+          MethodDescriptor md = toanalyzeMethodList.get(mdIdx);
+          if (ssjava.needToCheckLinearType(md)) {
+            checkMethodBody(cd, md);
+          }
+        }
+
+      }
+
+    } else {
+      it = state.getClassSymbolTable().getDescriptorsIterator();
+      while (it.hasNext()) {
+        ClassDescriptor cd = (ClassDescriptor) it.next();
+        for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
+          MethodDescriptor md = (MethodDescriptor) method_it.next();
+          checkMethodBody(cd, md);
+        }
       }
     }
 
@@ -159,6 +202,9 @@ public class LinearTypeCheck {
   }
 
   private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
+    if (state.SSJAVADEBUG) {
+      System.out.println("SSJAVA: Linear Type Checking: " + md);
+    }
     BlockNode bn = state.getMethodBody(md);
     checkBlockNode(md, md.getParameterTable(), bn);
   }
@@ -324,9 +370,10 @@ public class LinearTypeCheck {
     }
   }
 
-  private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) {
-    // TODO Auto-generated method stub
-
+  private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode tn) {
+    checkExpressionNode(md, nametable, tn.getCond());
+    checkExpressionNode(md, nametable, tn.getTrueExpr());
+    checkExpressionNode(md, nametable, tn.getFalseExpr());
   }
 
   private void checkOffsetNode(MethodDescriptor md, SymbolTable nametable, OffsetNode en) {
@@ -383,7 +430,7 @@ public class LinearTypeCheck {
 
       TypeDescriptor paramType = calleeMethodDesc.getParamType(i);
 
-      if (isReference(argNode.getType())) {
+      if (isReference(argNode.getType()) && !argNode.getType().isNull()) {
 
         boolean isParamOwnedByCallee = false;
         if (paramType.getExtension() != null) {
@@ -395,6 +442,12 @@ public class LinearTypeCheck {
 
         if (isParamOwnedByCallee) {
 
+          // cannot pass field reference through ownership transition
+          if (isField(argNode)) {
+            throw new Error("Caller cannot transfer its ownership of the field reference at "
+                + md.getClassDesc() + "::" + min.getNumLine());
+          }
+
           // method expects that argument is owned by caller
           SSJavaType locationType = (SSJavaType) argType.getExtension();
 
@@ -402,6 +455,10 @@ public class LinearTypeCheck {
             throw new Error("Caller passes an argument not owned by itself at " + md.getClassDesc()
                 + "::" + min.getNumLine());
           }
+
+          // delegated arg is no longer to be available from here
+          linearTypeCheckSet.add(argNode);
+          mapTreeNode2FlatMethod.put(argNode, state.getMethodFlat(md));
         }
 
       }
@@ -456,15 +513,19 @@ public class LinearTypeCheck {
       if (en.kind() == Kind.AssignmentNode) {
         AssignmentNode an = (AssignmentNode) en;
 
-        String destName = an.getDest().printNode(0);
-        if (destName.startsWith("this.")) {
-          destName = destName.substring(5);
-        }
+        boolean postinc = isPostIncAssignment(an);
 
-        if (an.getSrc().getType().isNull() && destName.equals(needToNullify)) {
-          needToNullify = null;
-          return true;
+        if (!postinc) {
+          String destName = an.getDest().printNode(0);
+          if (destName.startsWith("this.")) {
+            destName = destName.substring(5);
+          }
+          if (an.getSrc().getType().isNull() && destName.equals(needToNullify)) {
+            needToNullify = null;
+            return true;
+          }
         }
+
       }
     }
 
@@ -490,86 +551,45 @@ public class LinearTypeCheck {
     }
   }
 
-  private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an) {
-
-    boolean postinc = true;
+  public boolean isPostIncAssignment(AssignmentNode an) {
     if (an.getOperation().getBaseOp() == null
         || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
-            .getBaseOp().getOp() != Operation.POSTDEC))
-      postinc = false;
+            .getBaseOp().getOp() != Operation.POSTDEC)) {
+      return false;
+    } else {
+      return true;
+    }
+  }
 
-    if (!postinc) {
+  private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an) {
 
-      checkExpressionNode(md, nametable, an.getSrc());
+    boolean postinc = isPostIncAssignment(an);
 
+    if (!postinc) {
+      checkExpressionNode(md, nametable, an.getSrc());
       if (isReference(an.getSrc().getType()) && isReference(an.getDest().getType())) {
-        if (an.getSrc().kind() == Kind.NameNode) {
-
-          NameNode nn = (NameNode) an.getSrc();
-
-          if (nn.getField() != null) {
-            needToNullify = nn.getField().getSymbol();
-            prevAssignNode = an;
-          } else if (nn.getExpression() != null) {
-            if (nn.getExpression() instanceof FieldAccessNode) {
-              FieldAccessNode fan = (FieldAccessNode) nn.getExpression();
-              needToNullify = fan.printNode(0);
-              prevAssignNode = an;
-
-            }
-
-          } else {
-            // local variable case
-            linearTypeCheckSet.add(an.getSrc());
-            mapTreeNode2FlatMethod.put(an.getSrc(), state.getMethodFlat(md));
-          }
-        } else if (an.getSrc().kind() == Kind.FieldAccessNode) {
-          FieldAccessNode fan = (FieldAccessNode) an.getSrc();
-          needToNullify = fan.printNode(0);
-          if (needToNullify.startsWith("this.")) {
-            needToNullify = needToNullify.substring(5);
-          }
-          prevAssignNode = an;
-        } else if (an.getSrc().kind() == Kind.ArrayAccessNode) {
-          throw new Error(
-              "Not allowed to create an alias to the middle of the multidimensional array at "
-                  + md.getClassDesc() + "::" + an.getNumLine());
-        }
-
-        if (!an.getSrc().getType().isNull()) {
-
-          TypeDescriptor srcType = getTypeDescriptor(an.getSrc());
-          boolean isSourceOwned = false;
+        checkAlias(md, an, an.getSrc());
+      }
 
-          if (srcType.getExtension() != null) {
-            SSJavaType srcLocationType = (SSJavaType) srcType.getExtension();
-            isSourceOwned = srcLocationType.isOwned();
-          }
+    }
 
-          if (!isField(an.getDest()) && isSourceOwned) {
-            // here, transfer ownership from LHS to RHS when it creates alias
-            TypeDescriptor destType = getTypeDescriptor(an.getDest());
-            destType.setExtension(new SSJavaType(isSourceOwned));
-          } else {
-            // if instance is not owned by the method, not able to store
-            // instance into field
-            if (!isSourceOwned) {
-              throw new Error(
-                  "Method is not allowed to store an instance not owned by itself into a field at "
-                      + md.getClassDesc() + "::" + an.getNumLine());
-            }
-          }
+  }
 
-        }
+  private boolean isFieldOfClass(ClassDescriptor classDesc, String varName) {
+    return classDesc.getFieldTable().contains(varName);
+  }
 
-      }
+  private boolean isCreatingAlias(ExpressionNode en) {
 
+    int kind = en.kind();
+    if (kind == Kind.NameNode || kind == Kind.ArrayAccessNode || kind == Kind.FieldAccessNode) {
+      return true;
     }
+    return false;
 
   }
 
   private TypeDescriptor getTypeDescriptor(ExpressionNode en) {
-
     if (en.kind() == Kind.NameNode) {
       NameNode nn = (NameNode) en;
       if (nn.getField() != null) {
@@ -585,6 +605,29 @@ public class LinearTypeCheck {
     } else if (en.kind() == Kind.CreateObjectNode) {
       CreateObjectNode con = (CreateObjectNode) en;
       return con.getType();
+    } else if (en.kind() == Kind.ArrayAccessNode) {
+      ArrayAccessNode aan = (ArrayAccessNode) en;
+      return aan.getExpression().getType();
+    }
+
+    return null;
+  }
+
+  private FieldDescriptor getFieldDescriptorFromExpressionNode(ExpressionNode en) {
+
+    if (en.kind() == Kind.NameNode) {
+      NameNode nn = (NameNode) en;
+      if (nn.getField() != null) {
+        return nn.getField();
+      }
+
+      if (nn.getName() != null && nn.getName().getBase() != null) {
+        return getFieldDescriptorFromExpressionNode(nn.getExpression());
+      }
+
+    } else if (en.kind() == Kind.FieldAccessNode) {
+      FieldAccessNode fan = (FieldAccessNode) en;
+      return fan.getField();
     }
 
     return null;
@@ -608,19 +651,109 @@ public class LinearTypeCheck {
     return false;
   }
 
-  private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
-    if (dn.getExpression() != null) {
-      checkExpressionNode(md, nametable, dn.getExpression());
-      if (dn.getExpression().kind() == Kind.CreateObjectNode) {
+  private void checkAlias(MethodDescriptor md, TreeNode node, ExpressionNode src) {
+
+    if (src.kind() == Kind.NameNode) {
+
+      NameNode nn = (NameNode) src;
+
+      if (nn.getField() != null) {
+        needToNullify = nn.getField().getSymbol();
+        prevAssignNode = node;
+      } else if (nn.getExpression() != null) {
+        if (nn.getExpression() instanceof FieldAccessNode) {
+          FieldAccessNode fan = (FieldAccessNode) nn.getExpression();
+          needToNullify = fan.printNode(0);
+          prevAssignNode = node;
+        }
+      } else {
+        // local variable case
+        linearTypeCheckSet.add(src);
+        mapTreeNode2FlatMethod.put(src, state.getMethodFlat(md));
+      }
+    } else if (src.kind() == Kind.FieldAccessNode) {
+      FieldAccessNode fan = (FieldAccessNode) src;
+      needToNullify = fan.printNode(0);
+      if (needToNullify.startsWith("this.")) {
+        needToNullify = needToNullify.substring(5);
+      }
+      prevAssignNode = node;
+    } else if (src.kind() == Kind.ArrayAccessNode) {
+      ArrayAccessNode aan = (ArrayAccessNode) src;
+      TypeDescriptor srcType = src.getType();
+      if (srcType.isPtr() && srcType.getArrayCount() > 0) {
+        throw new Error(
+            "Not allowed to create an alias to the middle of the multidimensional array at "
+                + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
+      } else {
+        needToNullify = aan.printNode(0);
+        prevAssignNode = node;
+      }
+    } else if (src.kind() == Kind.CreateObjectNode || src.kind() == Kind.MethodInvokeNode
+        || src.kind() == Kind.ArrayInitializerNode || src.kind() == Kind.LiteralNode) {
+      if (node.kind() == Kind.DeclarationNode) {
+        DeclarationNode dn = (DeclarationNode) node;
         dn.getVarDescriptor().getType().setExtension(new SSJavaType(true));
       }
+    } else {
+      throw new Error("Not allowed this type of assignment at "
+          + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
+    }
+
+    if (isCreatingAlias(src)) {
+
+      TypeDescriptor srcType = getTypeDescriptor(src);
+      boolean isSourceOwned = false;
+
+      if (srcType.getExtension() != null) {
+        SSJavaType srcLocationType = (SSJavaType) srcType.getExtension();
+        isSourceOwned = srcLocationType.isOwned();
+
+        if (isSourceOwned) {
+          if (isField(src)) {
+            ssjava.setFieldOnwership(md, getFieldDescriptorFromExpressionNode(src));
+          }
+        }
+
+      } else if (md.isConstructor() && isFieldOfClass(md.getClassDesc(), src.printNode(0))) {
+        isSourceOwned = true;
+        ssjava.setFieldOnwership(md, getFieldDescriptorFromExpressionNode(src));
+      }
+
+      if (node.kind() == Kind.AssignmentNode) {
+        AssignmentNode an = (AssignmentNode) node;
+        if (isField(an.getDest())) {
+          // if instance is not owned by the method, not able to store
+          // instance into field
+          if (!isSourceOwned) {
+            throw new Error(
+                "Method is not allowed to store an instance not owned by itself into a field at "
+                    + md.getClassDesc().getSourceFileName() + "::" + node.getNumLine());
+          }
+        } else {
+          if (isSourceOwned) {
+            // here, transfer ownership from LHS to RHS when it creates alias
+            TypeDescriptor destType = getTypeDescriptor(an.getDest());
+            destType.setExtension(new SSJavaType(isSourceOwned));
+          }
+        }
+      }
 
     }
 
   }
 
+  private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
+    if (dn.getExpression() != null) {
+      ExpressionNode src = dn.getExpression();
+      if (isReference(src.getType())) {
+        checkAlias(md, dn, src);
+      }
+    }
+  }
+
   private boolean isReference(TypeDescriptor td) {
-    if (td.isPtr()) {
+    if (td.isPtr() && (!td.isString())) {
       return true;
     }
     return false;