1 package Analysis.SSJava;
3 import java.util.HashSet;
4 import java.util.Hashtable;
5 import java.util.Iterator;
7 import java.util.Vector;
9 import Analysis.Liveness;
10 import IR.AnnotationDescriptor;
11 import IR.ClassDescriptor;
13 import IR.MethodDescriptor;
16 import IR.SymbolTable;
17 import IR.TypeDescriptor;
18 import IR.VarDescriptor;
20 import IR.Flat.FlatMethod;
21 import IR.Flat.FlatNode;
22 import IR.Flat.FlatOpNode;
23 import IR.Flat.TempDescriptor;
24 import IR.Tree.ArrayAccessNode;
25 import IR.Tree.ArrayInitializerNode;
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;
37 import IR.Tree.LoopNode;
38 import IR.Tree.MethodInvokeNode;
39 import IR.Tree.NameNode;
40 import IR.Tree.OffsetNode;
41 import IR.Tree.OpNode;
42 import IR.Tree.ReturnNode;
43 import IR.Tree.SubBlockNode;
44 import IR.Tree.SwitchBlockNode;
45 import IR.Tree.SwitchStatementNode;
46 import IR.Tree.SynchronizedNode;
47 import IR.Tree.TertiaryNode;
48 import IR.Tree.TreeNode;
50 public class LinearTypeCheck {
53 SSJavaAnalysis ssjava;
54 String needToNullify = null;
55 AssignmentNode prevAssignNode;
57 Set<TreeNode> linearTypeCheckSet;
59 Hashtable<TreeNode, FlatMethod> mapTreeNode2FlatMethod;
61 Set<MethodDescriptor> delegateThisMethodSet;
65 public LinearTypeCheck(SSJavaAnalysis ssjava, State state) {
68 this.linearTypeCheckSet = new HashSet<TreeNode>();
69 this.mapTreeNode2FlatMethod = new Hashtable<TreeNode, FlatMethod>();
70 this.delegateThisMethodSet = new HashSet<MethodDescriptor>();
71 this.liveness = new Liveness();
74 public void linearTypeCheck() {
76 // first, parsing DELEGATE annotation from method declarations
77 Iterator it = state.getClassSymbolTable().getDescriptorsIterator();
78 while (it.hasNext()) {
79 ClassDescriptor cd = (ClassDescriptor) it.next();
80 for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
81 MethodDescriptor md = (MethodDescriptor) method_it.next();
86 // second, check the linear type
87 it = state.getClassSymbolTable().getDescriptorsIterator();
88 while (it.hasNext()) {
89 ClassDescriptor cd = (ClassDescriptor) it.next();
90 for (Iterator method_it = cd.getMethods(); method_it.hasNext();) {
91 MethodDescriptor md = (MethodDescriptor) method_it.next();
92 checkMethodBody(cd, md);
96 // third, check if original references are destroyed after creating new
99 for (Iterator<TreeNode> iterator = linearTypeCheckSet.iterator(); iterator.hasNext();) {
100 TreeNode tn = iterator.next();
101 Set<FlatNode> fnSet = ssjava.getBuildFlat().getFlatNodeSet(tn);
103 for (Iterator iterator2 = fnSet.iterator(); iterator2.hasNext();) {
104 FlatNode fn = (FlatNode) iterator2.next();
105 if (isLiveOut(tn, fn)) {
109 + "', which is read by a method, should be destroyed after introducing new alias at "
110 + mapTreeNode2FlatMethod.get(tn).getMethod().getClassDesc().getSourceFileName()
111 + "::" + tn.getNumLine());
121 private boolean isLiveOut(TreeNode tn, FlatNode fn) {
122 Set<TempDescriptor> liveOutTemp = liveness.getLiveOutTemps(mapTreeNode2FlatMethod.get(tn), fn);
123 if (fn.kind() == FKind.FlatOpNode) {
124 FlatOpNode fon = (FlatOpNode) fn;
125 return liveOutTemp.contains(fon.getLeft());
130 private void parseAnnotations(MethodDescriptor md) {
132 // method annotation parsing
133 Vector<AnnotationDescriptor> methodAnnotations = md.getModifiers().getAnnotations();
134 if (methodAnnotations != null) {
135 for (int i = 0; i < methodAnnotations.size(); i++) {
136 AnnotationDescriptor an = methodAnnotations.elementAt(i);
137 if (an.getMarker().equals(ssjava.DELEGATETHIS)) {
138 delegateThisMethodSet.add(md);
139 md.getThis().getType().setExtension(new SSJavaType(true));
144 // paramter annotation parsing
145 for (int i = 0; i < md.numParameters(); i++) {
146 // process annotations on method parameters
147 VarDescriptor vd = (VarDescriptor) md.getParameter(i);
149 Vector<AnnotationDescriptor> annotationVec = vd.getType().getAnnotationMarkers();
151 for (int anIdx = 0; anIdx < annotationVec.size(); anIdx++) {
152 AnnotationDescriptor ad = annotationVec.elementAt(anIdx);
153 if (ad.getMarker().equals(SSJavaAnalysis.DELEGATE)) {
154 SSJavaType locationType = new SSJavaType(true);
155 vd.getType().setExtension(locationType);
161 private void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
162 BlockNode bn = state.getMethodBody(md);
163 checkBlockNode(md, md.getParameterTable(), bn);
166 private void checkBlockNode(MethodDescriptor md, SymbolTable nametable, BlockNode bn) {
167 for (int i = 0; i < bn.size(); i++) {
168 BlockStatementNode bsn = bn.get(i);
169 checkBlockStatementNode(md, bn.getVarTable(), bsn);
173 private void checkBlockStatementNode(MethodDescriptor md, SymbolTable nametable,
174 BlockStatementNode bsn) {
176 if (needToNullify != null) {
177 if (!checkNullifying(bsn)) {
181 + "', which is read by a method, should be assigned to null before executing any following statement of the reference copy statement at "
182 + md.getClassDesc().getSourceFileName() + "::" + prevAssignNode.getNumLine());
186 switch (bsn.kind()) {
188 case Kind.BlockExpressionNode:
189 checkBlockExpressionNode(md, nametable, (BlockExpressionNode) bsn);
192 case Kind.DeclarationNode:
193 checkDeclarationNode(md, nametable, (DeclarationNode) bsn);
196 case Kind.IfStatementNode:
197 checkIfStatementNode(md, nametable, (IfStatementNode) bsn);
200 case Kind.SwitchStatementNode:
201 checkSwitchStatementNode(md, nametable, (SwitchStatementNode) bsn);
205 checkLoopNode(md, nametable, (LoopNode) bsn);
208 case Kind.ReturnNode:
209 checkReturnNode(md, nametable, (ReturnNode) bsn);
212 case Kind.SubBlockNode:
213 checkSubBlockNode(md, nametable, (SubBlockNode) bsn);
216 case Kind.SynchronizedNode:
217 checkSynchronizedNode(md, nametable, (SynchronizedNode) bsn);
223 private void checkSynchronizedNode(MethodDescriptor md, SymbolTable nametable,
224 SynchronizedNode sbn) {
225 checkBlockNode(md, nametable, sbn.getBlockNode());
226 // todo this could be Object
227 checkExpressionNode(md, nametable, sbn.getExpr());
230 private void checkReturnNode(MethodDescriptor md, SymbolTable nametable, ReturnNode rn) {
231 if (rn.getReturnExpression() != null) {
232 checkExpressionNode(md, nametable, rn.getReturnExpression());
236 private void checkSubBlockNode(MethodDescriptor md, SymbolTable nametable, SubBlockNode sbn) {
237 checkBlockNode(md, nametable, sbn.getBlockNode());
240 private void checkIfStatementNode(MethodDescriptor md, SymbolTable nametable, IfStatementNode isn) {
241 checkExpressionNode(md, nametable, isn.getCondition());
242 checkBlockNode(md, nametable, isn.getTrueBlock());
243 if (isn.getFalseBlock() != null)
244 checkBlockNode(md, nametable, isn.getFalseBlock());
247 private void checkSwitchStatementNode(MethodDescriptor md, SymbolTable nametable,
248 SwitchStatementNode ssn) {
250 checkExpressionNode(md, nametable, ssn.getCondition());
252 BlockNode sbn = ssn.getSwitchBody();
253 for (int i = 0; i < sbn.size(); i++) {
254 checkSwitchBlockNode(md, nametable, (SwitchBlockNode) sbn.get(i));
258 private void checkSwitchBlockNode(MethodDescriptor md, SymbolTable nametable, SwitchBlockNode sbn) {
259 checkBlockNode(md, nametable, sbn.getSwitchBlockStatement());
262 private void checkBlockExpressionNode(MethodDescriptor md, SymbolTable nametable,
263 BlockExpressionNode ben) {
264 checkExpressionNode(md, nametable, ben.getExpression());
267 private void checkExpressionNode(MethodDescriptor md, SymbolTable nametable, ExpressionNode en) {
269 case Kind.AssignmentNode:
270 checkAssignmentNode(md, nametable, (AssignmentNode) en);
274 checkCastNode(md, nametable, (CastNode) en);
277 case Kind.CreateObjectNode:
278 checkCreateObjectNode(md, nametable, (CreateObjectNode) en);
281 case Kind.FieldAccessNode:
282 checkFieldAccessNode(md, nametable, (FieldAccessNode) en);
285 case Kind.ArrayAccessNode:
286 checkArrayAccessNode(md, nametable, (ArrayAccessNode) en);
289 // case Kind.LiteralNode:
290 // checkLiteralNode(md, nametable, (LiteralNode) en);
293 case Kind.MethodInvokeNode:
294 checkMethodInvokeNode(md, nametable, (MethodInvokeNode) en);
298 checkNameNode(md, nametable, (NameNode) en);
302 checkOpNode(md, nametable, (OpNode) en);
305 case Kind.OffsetNode:
306 checkOffsetNode(md, nametable, (OffsetNode) en);
309 case Kind.TertiaryNode:
310 checkTertiaryNode(md, nametable, (TertiaryNode) en);
313 // case Kind.InstanceOfNode:
314 // checkInstanceOfNode(md, nametable, (InstanceOfNode) en);
317 // case Kind.ArrayInitializerNode:
318 // checkArrayInitializerNode(md, nametable, (ArrayInitializerNode) en);
321 // case Kind.ClassTypeNode:
322 // checkClassTypeNode(md, nametable, (ClassTypeNode) ens);
327 private void checkTertiaryNode(MethodDescriptor md, SymbolTable nametable, TertiaryNode en) {
328 // TODO Auto-generated method stub
332 private void checkOffsetNode(MethodDescriptor md, SymbolTable nametable, OffsetNode en) {
333 // TODO Auto-generated method stub
337 private void checkOpNode(MethodDescriptor md, SymbolTable nametable, OpNode en) {
338 // TODO Auto-generated method stub
342 private void checkNameNode(MethodDescriptor md, SymbolTable nametable, NameNode en) {
343 // TODO Auto-generated method stub
347 private boolean isOwned(VarDescriptor varDesc) {
348 if (varDesc.getType().getExtension() != null) {
349 SSJavaType locationType = (SSJavaType) varDesc.getType().getExtension();
350 return locationType.isOwned();
355 private void checkMethodInvokeNode(MethodDescriptor md, SymbolTable nametable,
356 MethodInvokeNode min) {
358 MethodDescriptor calleeMethodDesc = min.getMethod();
360 // check delegate_this annotation
361 // only method that owns itself 'THIS' can call method with delegate_this
364 if (delegateThisMethodSet.contains(calleeMethodDesc)) {
366 if (min.getBaseName() == null) {
367 if (!delegateThisMethodSet.contains(md)) {
368 throw new Error("Caller does not own the 'THIS' argument at " + md.getClassDesc() + "::"
372 VarDescriptor baseVar = (VarDescriptor) nametable.get(min.getBaseName().getIdentifier());
373 if (!isOwned(baseVar)) {
374 throw new Error("Caller does not own the 'THIS' argument at " + md.getClassDesc() + "::"
380 // check delegate parameter annotation
381 for (int i = 0; i < min.numArgs(); i++) {
382 ExpressionNode argNode = min.getArg(i);
384 TypeDescriptor paramType = calleeMethodDesc.getParamType(i);
386 if (isReference(argNode.getType())) {
388 boolean isParamOwnedByCallee = false;
389 if (paramType.getExtension() != null) {
390 SSJavaType locationType = (SSJavaType) paramType.getExtension();
391 isParamOwnedByCallee = locationType.isOwned();
394 TypeDescriptor argType = getTypeDescriptor(argNode);
396 if (isParamOwnedByCallee) {
398 // method expects that argument is owned by caller
399 SSJavaType locationType = (SSJavaType) argType.getExtension();
401 if (locationType == null || !locationType.isOwned()) {
402 throw new Error("Caller passes an argument not owned by itself at " + md.getClassDesc()
403 + "::" + min.getNumLine());
412 private void checkArrayAccessNode(MethodDescriptor md, SymbolTable nametable, ArrayAccessNode en) {
413 // TODO Auto-generated method stub
417 private void checkFieldAccessNode(MethodDescriptor md, SymbolTable nametable, FieldAccessNode fan) {
421 private void checkCreateObjectNode(MethodDescriptor md, SymbolTable nametable,
422 CreateObjectNode con) {
424 TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()];
425 for (int i = 0; i < con.numArgs(); i++) {
426 ExpressionNode en = con.getArg(i);
427 checkExpressionNode(md, nametable, en);
428 tdarray[i] = en.getType();
431 if ((con.getArrayInitializer() != null)) {
432 checkArrayInitializerNode(md, nametable, con.getArrayInitializer());
435 // the current method owns a instance that it makes inside
436 SSJavaType locationType = new SSJavaType(true);
437 con.getType().setExtension(locationType);
441 private void checkArrayInitializerNode(MethodDescriptor md, SymbolTable nametable,
442 ArrayInitializerNode arrayInitializer) {
443 // TODO Auto-generated method stub
447 private void checkCastNode(MethodDescriptor md, SymbolTable nametable, CastNode cn) {
448 ExpressionNode en = cn.getExpression();
449 checkExpressionNode(md, nametable, en);
452 private boolean checkNullifying(BlockStatementNode bsn) {
454 if (bsn.kind() == Kind.BlockExpressionNode) {
455 ExpressionNode en = ((BlockExpressionNode) bsn).getExpression();
456 if (en.kind() == Kind.AssignmentNode) {
457 AssignmentNode an = (AssignmentNode) en;
459 String destName = an.getDest().printNode(0);
460 if (destName.startsWith("this.")) {
461 destName = destName.substring(5);
464 if (an.getSrc().getType().isNull() && destName.equals(needToNullify)) {
465 needToNullify = null;
474 private void checkLoopNode(MethodDescriptor md, SymbolTable nametable, LoopNode ln) {
475 if (ln.getType() == LoopNode.WHILELOOP || ln.getType() == LoopNode.DOWHILELOOP) {
476 checkExpressionNode(md, nametable, ln.getCondition());
477 checkBlockNode(md, nametable, ln.getBody());
480 /* Link in the initializer naming environment */
481 BlockNode bn = ln.getInitializer();
482 for (int i = 0; i < bn.size(); i++) {
483 BlockStatementNode bsn = bn.get(i);
484 checkBlockStatementNode(md, bn.getVarTable(), bsn);
486 // check the condition
487 checkExpressionNode(md, bn.getVarTable(), ln.getCondition());
488 checkBlockNode(md, bn.getVarTable(), ln.getBody());
489 checkBlockNode(md, bn.getVarTable(), ln.getUpdate());
493 private void checkAssignmentNode(MethodDescriptor md, SymbolTable nametable, AssignmentNode an) {
495 boolean postinc = true;
496 if (an.getOperation().getBaseOp() == null
497 || (an.getOperation().getBaseOp().getOp() != Operation.POSTINC && an.getOperation()
498 .getBaseOp().getOp() != Operation.POSTDEC))
503 checkExpressionNode(md, nametable, an.getSrc());
505 if (isReference(an.getSrc().getType()) && isReference(an.getDest().getType())) {
506 if (an.getSrc().kind() == Kind.NameNode) {
508 NameNode nn = (NameNode) an.getSrc();
510 if (nn.getField() != null) {
511 needToNullify = nn.getField().getSymbol();
513 } else if (nn.getExpression() != null) {
514 if (nn.getExpression() instanceof FieldAccessNode) {
515 FieldAccessNode fan = (FieldAccessNode) nn.getExpression();
516 needToNullify = fan.printNode(0);
522 // local variable case
523 linearTypeCheckSet.add(an.getSrc());
524 mapTreeNode2FlatMethod.put(an.getSrc(), state.getMethodFlat(md));
526 } else if (an.getSrc().kind() == Kind.FieldAccessNode) {
527 FieldAccessNode fan = (FieldAccessNode) an.getSrc();
528 needToNullify = fan.printNode(0);
529 if (needToNullify.startsWith("this.")) {
530 needToNullify = needToNullify.substring(5);
533 } else if (an.getSrc().kind() == Kind.ArrayAccessNode) {
535 "Not allowed to create an alias to the middle of the multidimensional array at "
536 + md.getClassDesc() + "::" + an.getNumLine());
539 if (!an.getSrc().getType().isNull()) {
541 TypeDescriptor srcType = getTypeDescriptor(an.getSrc());
542 boolean isSourceOwned = false;
544 if (srcType.getExtension() != null) {
545 SSJavaType srcLocationType = (SSJavaType) srcType.getExtension();
546 isSourceOwned = srcLocationType.isOwned();
549 if (!isField(an.getDest()) && isSourceOwned) {
550 // here, transfer ownership from LHS to RHS when it creates alias
551 TypeDescriptor destType = getTypeDescriptor(an.getDest());
552 destType.setExtension(new SSJavaType(isSourceOwned));
554 // if instance is not owned by the method, not able to store
555 // instance into field
556 if (!isSourceOwned) {
558 "Method is not allowed to store an instance not owned by itself into a field at "
559 + md.getClassDesc() + "::" + an.getNumLine());
571 private TypeDescriptor getTypeDescriptor(ExpressionNode en) {
573 if (en.kind() == Kind.NameNode) {
574 NameNode nn = (NameNode) en;
575 if (nn.getField() != null) {
576 return nn.getVar().getType();
577 } else if (nn.getVar() != null) {
578 return nn.getVar().getType();
580 return getTypeDescriptor(nn.getExpression());
582 } else if (en.kind() == Kind.FieldAccessNode) {
583 FieldAccessNode fan = (FieldAccessNode) en;
584 return getTypeDescriptor(fan.getExpression());
585 } else if (en.kind() == Kind.CreateObjectNode) {
586 CreateObjectNode con = (CreateObjectNode) en;
587 return con.getType();
593 private boolean isField(ExpressionNode en) {
595 if (en.kind() == Kind.NameNode) {
596 NameNode nn = (NameNode) en;
597 if (nn.getField() != null) {
601 if (nn.getName() != null && nn.getName().getBase() != null) {
605 } else if (en.kind() == Kind.FieldAccessNode) {
611 private void checkDeclarationNode(MethodDescriptor md, SymbolTable nametable, DeclarationNode dn) {
612 if (dn.getExpression() != null) {
613 checkExpressionNode(md, nametable, dn.getExpression());
614 if (dn.getExpression().kind() == Kind.CreateObjectNode) {
615 dn.getVarDescriptor().getType().setExtension(new SSJavaType(true));
622 private boolean isReference(TypeDescriptor td) {