/******************************************************************************* * Copyright (c) 2014 Imperial College London * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Raul Castro Fernandez - initial API and implementation ******************************************************************************/ package uk.ac.imperial.lsds.java2sdg.flowanalysis; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import soot.SootClass; import soot.SootMethod; import soot.Unit; import soot.Value; import soot.ValueBox; import soot.jimple.FieldRef; import soot.jimple.InvokeExpr; import soot.tagkit.SourceLnPosTag; import soot.tagkit.StringTag; import soot.tagkit.Tag; import soot.toolkits.graph.UnitGraph; import uk.ac.imperial.lsds.java2sdg.Main; import uk.ac.imperial.lsds.java2sdg.bricks.InternalStateRepr; import uk.ac.imperial.lsds.java2sdg.bricks.SDGAnnotation; import uk.ac.imperial.lsds.java2sdg.bricks.TaskElementNature; import uk.ac.imperial.lsds.java2sdg.bricks.Variable; import uk.ac.imperial.lsds.java2sdg.bricks.InternalStateRepr.StateLabel; import uk.ac.imperial.lsds.java2sdg.bricks.TaskElement.TaskElementBuilder; import uk.ac.imperial.lsds.java2sdg.input.SourceCodeHandler; public class TEBoundaryAnalysis { private final static Logger log = LoggerFactory.getLogger(Main.class.getCanonicalName()); private StateAccessUtil util = new StateAccessUtil(); private UnitGraph cfg = null; private final Map<String, InternalStateRepr> stateElements; private Iterator<Unit> units = null; private LinkedList<PointOfInterest> stateAccesses = null; private SourceCodeHandler sch; private LiveVariableAnalysis lva; private Map<TaskElementBuilder, LinkedHashSet<Integer>> op_code = new LinkedHashMap<TaskElementBuilder, LinkedHashSet<Integer>>(); private TEBoundaryAnalysis(UnitGraph cfg, Map<String, InternalStateRepr> stateElements, SourceCodeHandler sch, LiveVariableAnalysis lva){ this.cfg = cfg; this.stateElements = stateElements; this.sch = sch; this.lva = lva; units = cfg.iterator(); stateAccesses = new LinkedList<PointOfInterest>(); } public static TEBoundaryAnalysis getBoundaryAnalyzer(UnitGraph cfg, Map<String, InternalStateRepr> stateElements, SourceCodeHandler sch, LiveVariableAnalysis lva){ return new TEBoundaryAnalysis(cfg, stateElements, sch, lva); } /** * Dataflow style analysis */ public List<TaskElementBuilder> performTEAnalysis(){ // Get sequential TE return getTeInSequence(); } public LinkedList<PointOfInterest> getStateAccessList(){ return stateAccesses; } public TaskElementBuilder getOperatorBlockBuilder(int opId){ for(TaskElementBuilder obb : op_code.keySet()){ if(obb.getId() == opId){ return obb; } } return null; } public LinkedHashSet<Integer> getCodeForOperator(int opId){ for(TaskElementBuilder obb : op_code.keySet()){ if(obb.getId() == opId){ return op_code.get(obb); } } return null; } public int getNumberOperators(){ return op_code.keySet().size(); } private int getLineNumber(Unit u){ int lineNumber = -1; SourceLnPosTag tag = (SourceLnPosTag)u.getTag("SourceLnPosTag"); if (tag != null){ lineNumber = tag.startLn(); // get line number } return lineNumber; } private Iterator<ValueBox> getValueBoxes(Unit u){ return u.getUseBoxes().iterator(); } private PointOfInterest analyzeLine(int originalLineNumber, List<Unit> groupOfJimpleLines){ PointOfInterest poi = new PointOfInterest(); poi.setSourceCodeLine(originalLineNumber); //Assign source code line // First check whether there is an important annotation and store it in ann SDGAnnotation ann = sch.getSDGAnnotationAtLine(originalLineNumber); poi.setAnnotation(ann); // Then check if there is state access for(Unit u : groupOfJimpleLines){ Iterator<ValueBox> iValueBox = getValueBoxes(u); while(iValueBox.hasNext()){ ValueBox valueBox = iValueBox.next(); Value v = valueBox.getValue(); if(v instanceof FieldRef){ FieldRef fRef = (FieldRef)v; String fieldName = fRef.getField().getName(); // stateName if(stateElements.containsKey(fieldName)){ int stateElementId = getStateElementId(fieldName); // stateElement id poi.setStateElementId(stateElementId); // the state this line refers to poi.setStateName(fieldName); // If there is a ref to partial state and no annotation, then it's local access InternalStateRepr isr = stateElements.get(fieldName); if(isr.getStateLabel().equals(StateLabel.PARTIAL) && ann == null){ poi.setAnnotation(SDGAnnotation.LOCAL); } } } else if(v instanceof InvokeExpr){ if(poi.getStateName() != null){ InvokeExpr m = (InvokeExpr)v; SootMethod method = m.getMethod(); String methodName = method.getName(); SootClass aux = m.getMethod().getDeclaringClass(); if(ann == null || !ann.equals(SDGAnnotation.GLOBAL_READ) || !ann.equals(SDGAnnotation.GLOBAL_WRITE)){ InternalStateRepr isr = stateElements.get(poi.getStateName()); StateLabel sl = isr.getStateLabel(); SootClass sc = isr.getStateClass(); if(aux.toString().equals(sc.toString())){ // If it's partitioned state then we get the key if(sl.equals(StateLabel.PARTITIONED)){ SootMethod originM = aux.getMethodByName(methodName); List<Tag> tags = originM.getTags(); int partitioningKeyPosition = util.getPartitioningKey(tags); Value partitioningKey = m.getArg(partitioningKeyPosition); poi.setPartitioningKey(partitioningKey.toString()); } } } } } } } return poi; } private boolean setsNewBound(PointOfInterest poi, int lastSAccess){ SDGAnnotation ann = poi.getAnnotation(); if(ann != null && (ann.equals(SDGAnnotation.GLOBAL_READ) || ann.equals(SDGAnnotation.GLOBAL_READ) || ann.equals(SDGAnnotation.COLLECTION))){ log.debug("ANN bound at line: "+poi.getSourceCodeLine()); return true; } if(poi.isStateAccess()){ if(lastSAccess != -1){ // first TE does not count (group more lines) if(!(poi.getStateElementId() == lastSAccess)){ log.debug("StateAccess bound at line: "+poi.getSourceCodeLine()); return true; } } } return false; } private TaskElementBuilder processPOI(PointOfInterest poi, TaskElementBuilder buildingTE){ SDGAnnotation ann = poi.getAnnotation(); if(ann != null && (ann.equals(SDGAnnotation.GLOBAL_READ) || ann.equals(SDGAnnotation.GLOBAL_WRITE))){ // Say it's global and check for state access buildingTE.ann(ann); } else if(ann != null && (ann.equals(SDGAnnotation.LOCAL))){ buildingTE.ann(ann); TaskElementNature ten = TaskElementNature.getStatefulTaskElement(poi.getStateElementId(), poi.getStateName(), poi.getPartitioningKey()); buildingTE.opType(ten); return buildingTE; } else if(ann != null && (ann.equals(SDGAnnotation.COLLECTION))){ // Say it's merge and return (we don't want these to be stateful) buildingTE.ann(ann); // ... so we make it stateless with a state reference to whatever it merges int stateId = poi.getStateElementId(); System.out.println("COLLECTION WITH STATE ID: "+stateId); TaskElementNature ten = TaskElementNature.getStatelessTaskElementWithStateReference(stateId); buildingTE.opType(ten); return buildingTE; } // If it's state access fill stateful info if(poi.isStateAccess()){ TaskElementNature ten = TaskElementNature.getStatefulTaskElement(poi.getStateElementId(), poi.getStateName(), poi.getPartitioningKey()); buildingTE.opType(ten); } else{ // Make sure we are initialising this state, because otherwise we just need to continue if(buildingTE.getOpType() == null){ TaskElementNature ten = TaskElementNature.getStatelessTaskElement(); buildingTE.opType(ten); } } return buildingTE; } private List<Variable> filterThis(List<Variable> vars){ Iterator<Variable> iv = vars.iterator(); while(iv.hasNext()){ Variable v = iv.next(); if(v.getName().equals("this")){ iv.remove(); } } return vars; } private List<TaskElementBuilder> getTeInSequence(){ int teId = 0; int lastSAccess = -1; List<TaskElementBuilder> sequentialListOfTeb = new ArrayList<TaskElementBuilder>(); TaskElementBuilder teb = new TaskElementBuilder(0, new String("TE_"+teId)); int prevLineNumber = -1; int curLineNumber = -1; List<Unit> jimpleCodeLines = new ArrayList<Unit>(); Unit firstUnit = units.next(); int firstLine = getLineNumber(firstUnit); List<Variable> localVars = null; try { localVars = filterThis(lva.getInLiveVariablesAtLine(firstLine)); } catch (NoDataForLine e) { // TODO Auto-generated catch block e.printStackTrace(); } teb.localVars(localVars); while(units.hasNext()){ Unit u = units.next(); curLineNumber = getLineNumber(u); if(curLineNumber != prevLineNumber && prevLineNumber != -1){ PointOfInterest poi = analyzeLine(prevLineNumber, jimpleCodeLines); jimpleCodeLines.clear(); // Check whether poi or not if(!poi.isPointOfInterest()){ // Not poi, we just store the line String originalSourceCodeLine = sch.getLineAt(poi.getSourceCodeLine()); teb.addCodeLine(originalSourceCodeLine); } else{ // process poi if(setsNewBound(poi, lastSAccess)){ // BUILD AND STORE PREVIOUS TE List<Variable> varsToStream = null; try { varsToStream = filterThis(lva.getInLiveVariablesAtLine(poi.getSourceCodeLine())); } catch (NoDataForLine e) { // TODO Auto-generated catch block e.printStackTrace(); } teb.varsToStream(varsToStream); sequentialListOfTeb.add(teb); //PREPARE NEW TE teId++; teb = new TaskElementBuilder(teId, new String("TE_"+teId)); String originalSourceCodeLine = sch.getLineAt(poi.getSourceCodeLine()); teb.addCodeLine(originalSourceCodeLine); // Add the POI teb = processPOI(poi, teb); // PROCESS poi try { localVars = filterThis(lva.getInLiveVariablesAtLine(firstLine)); } catch (NoDataForLine e) { // TODO Auto-generated catch block e.printStackTrace(); } teb.localVars(localVars); } else{ String originalSourceCodeLine = sch.getLineAt(poi.getSourceCodeLine()); teb.addCodeLine(originalSourceCodeLine); teb = processPOI(poi, teb); } //Regardless what happened with the line -> remember to update last state access if(poi.isStateAccess()){ lastSAccess = poi.getStateElementId(); } } } jimpleCodeLines.add(u); prevLineNumber = curLineNumber; } PointOfInterest poi = analyzeLine(prevLineNumber, jimpleCodeLines); if(poi.isPointOfInterest() && setsNewBound(poi, lastSAccess)){ // BUILD PREV TEB List<Variable> varsToStream = null; try { varsToStream = filterThis(lva.getInLiveVariablesAtLine(poi.getSourceCodeLine())); } catch (NoDataForLine e) { e.printStackTrace(); } teb.varsToStream(varsToStream); sequentialListOfTeb.add(teb); // BUILD NEW ONE teId++; teb = new TaskElementBuilder(teId, new String("TE_"+teId)); String originalSourceCodeLine = sch.getLineAt(poi.getSourceCodeLine()); teb.addCodeLine(originalSourceCodeLine); // Add the POI teb = processPOI(poi, teb); // PROCESS poi try { localVars = filterThis(lva.getInLiveVariablesAtLine(firstLine)); } catch (NoDataForLine e) { e.printStackTrace(); } teb.localVars(localVars); sequentialListOfTeb.add(teb); } else{ teb = processPOI(poi, teb); // We check if there is a previous TEB, so that we can tell it which vars to stream if(!sequentialListOfTeb.isEmpty()){ TaskElementBuilder previous = sequentialListOfTeb.get(sequentialListOfTeb.size()-1); List<Variable> varsToStream = null; try { varsToStream = filterThis(lva.getInLiveVariablesAtLine(curLineNumber)); } catch (NoDataForLine e) { e.printStackTrace(); } previous.varsToStream(varsToStream); } String originalSourceCodeLine = sch.getLineAt(poi.getSourceCodeLine()); teb.addCodeLine(originalSourceCodeLine); sequentialListOfTeb.add(teb); } return sequentialListOfTeb; } public void printOpCode(){ for(Map.Entry<TaskElementBuilder, LinkedHashSet<Integer>> opcode : op_code.entrySet()){ System.out.println(""); System.out.println("OP: "+opcode.getKey().getId()); for(Integer line : opcode.getValue()){ System.out.print(line+" "); } System.out.println(""); } System.out.println(""); } public void printOperatorBounds(){ units = cfg.iterator(); //reset iterator while(units.hasNext()){ Unit unit = units.next(); int lineNumber = -1; SourceLnPosTag lineTag = (SourceLnPosTag)unit.getTag("SourceLnPosTag"); if (lineTag != null){ lineNumber = lineTag.startLn(); } StringTag stringTag = (StringTag)unit.getTag("StringTag"); System.out.println("L: "+lineNumber+" TE: "+stringTag.getInfo()+" # "+unit.toString()); } } private int getStateElementId(String stateName){ InternalStateRepr isr = stateElements.get(stateName); return isr.getSeId(); } }