/** * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. * This file is licensed under the terms of the Modified BSD License. */ package deadlock.analyser.detection; import java.util.HashMap; import abs.frontend.ast.ASTNode; import abs.frontend.ast.AwaitStmt; import abs.frontend.ast.CompilationUnit; import abs.frontend.ast.DataTypeUse; import abs.frontend.ast.FieldDecl; import abs.frontend.ast.GetExp; import abs.frontend.ast.InterfaceTypeUse; import abs.frontend.ast.Model; import abs.frontend.ast.VarUse; import deadlock.analyser.AnalyserLog; /** * A class to pre-process the program in order to evaluate whether the program * requires a deadlock analysis. * @author groman * */ public class DeadlockPreanalysis { /** * The model of the program */ private Model model; /** * Log object */ private AnalyserLog log; /** * Get expressions found and their await statement (if exists) */ private HashMap<GetExp,AwaitStmt> getExpressions; /** * DataType Field declarations found in the program and if they might have a future value */ private HashMap<FieldDecl,Boolean> dataFieldDecls; /** * Stores the model * @param model The model of the program */ public DeadlockPreanalysis(Model model) { this.model = model; log = new AnalyserLog(); getExpressions = new HashMap<GetExp,AwaitStmt> (); dataFieldDecls = new HashMap<FieldDecl,Boolean>(); } /** * Applies the deadlock preanalysis */ public void analyzeModel () { try { //CompilationUnit cu = model.getCompilationUnits().getChild(0); for (CompilationUnit cu : model.getCompilationUnits()) { computeInstructions(cu,0); if (cu.hasMainBlock()) { System.out.println("Processing main block" + cu.getName()); computeInstructions(cu.getMainBlock(),0); } } System.out.println(getExpressions); System.out.println(this); } catch (Exception e) { e.printStackTrace(); } } /** * Computes all instructions (recursively) searching get statements and field declarations. * Relates get statements to previous "await" statements on the same variable. * Process all fields evaluating their types and detecting if they can contain a future variable. * @param node Node to be evaluated * @param level Level in the AST */ private void computeInstructions(ASTNode<?> node, int level) { // We save all get instructions if (node instanceof GetExp && !getExpressions.containsKey(node)) { getExpressions.put((GetExp)node, null); } // We evaluate all field declarations if (node instanceof FieldDecl) { processFieldDecl ((FieldDecl)node); } // Search recursively for(int i = 0; i < node.getNumChild(); i++) { ASTNode<?> child = node.getChild(i); // If we find an await we search for its get if (node.getChild(i) instanceof AwaitStmt && node.getNumChild() > i) { //processAwait((AwaitStmt)node.getChild(i), node.getChild(i+1)); processAwait((AwaitStmt)node.getChild(i), i, node); } computeInstructions(child, level + 1); } } private void processAwait (AwaitStmt await, int position, ASTNode<?> node) { String varAwait = null; if (await.getGuard().getChild(0) instanceof VarUse) { varAwait = ((VarUse)await.getGuard().getChild(0)).getName(); } int getPos = position + 1; GetExp getInst = null; if (varAwait != null) { while (getPos < node.getNumChild() && getInst == null) { getInst = lookforGetOperation(await,node.getChild(getPos),varAwait); if (getInst == null) { getPos ++; } } } // System.out.println("PROCESANDO " + position + " " + getPos); boolean used = false; for (int i = position+1; i < getPos && !used; i ++) { used = isVarUsed(node.getChild(i),varAwait); } if (used && getInst != null) { getExpressions.put((GetExp)getInst, null); } } private boolean isVarUsed (ASTNode<?> node, String var) { if (node instanceof VarUse) { VarUse vUse = (VarUse) node; if (var.equals(vUse.getName())) { return true; } } boolean used = false; for (int i = 0; i < node.getNumChild() && !used ; i++) { used = isVarUsed (node.getChild(i), var); } return used; } // private void processAwait (AwaitStmt await, ASTNode<?> next) { // if (await.getGuard().getChild(0) instanceof VarUse) { // String varAwait = ((VarUse)await.getGuard().getChild(0)).getName(); // lookforGetOperation(await,next,varAwait); // } // } private GetExp lookforGetOperation (AwaitStmt await, ASTNode<?> node, String varName) { GetExp result = null; if (node instanceof GetExp) { GetExp get = (GetExp)node; if (varName.equals(((VarUse)get.getChild(0)).getName())) { result = (GetExp)node; getExpressions.put((GetExp)node, await); } } for (int i = 0; i < node.getNumChild() && result == null; i ++) { result = lookforGetOperation(await, node.getChild(i), varName); } return result; } private void processFieldDecl (FieldDecl field) { System.out.println("Processing Field Declaration: " + field.getName()); if (field.getChild(0) instanceof DataTypeUse) { DataTypeUse type = (DataTypeUse)field.getChild(0); dataFieldDecls.put(field,hasFutureVariables(type)); } } private boolean hasFutureVariables (ASTNode<?> node) { boolean result = false; result = (node instanceof DataTypeUse && "Fut".equals(((DataTypeUse)node).getName())); for (int i = 0; i < node.getNumChild() && !result; i ++) { result = result || hasFutureVariables(node.getChild(i)); } return result; } public boolean isDeadlockFree () { boolean result = true; for (GetExp get: getExpressions.keySet()) { result = result && (getExpressions.get(get) != null); } for (Boolean value: dataFieldDecls.values()) { result = result && !value; } return result; } public String toString () { StringBuffer buffer = new StringBuffer (); buffer.append("***** Deadlock Preanalysis Results: *****\n"); buffer.append("----- GET Expressions evaluation --------\n"); for(GetExp get: getExpressions.keySet() ) { buffer.append(get.toString()); buffer.append("["); int line = get.getStartLine(); buffer.append(get.getCompilationUnit().getName() + ":" + (line != 0? + line:"_")); buffer.append("]"); buffer.append(":" + (getExpressions.get(get) != null? true:false)+ "\n"); } buffer.append("----- Field Types -----------------------\n"); for (FieldDecl field: dataFieldDecls.keySet()) { buffer.append(field.getContextDecl().getName() + "." + field.getName() + " [" + field.getCompilationUnit().getName() + ":" + field.getStartLine() + "]"); buffer.append(" might contain a future value?: " + dataFieldDecls.get(field) + "\n"); } buffer.append("*****************************************"); return buffer.toString(); } private String printTab(int n) { StringBuffer buffer = new StringBuffer (); for (int i = 0; i < n; i++) { buffer.append(" "); } return buffer.toString(); } }