/****************************************************************************** * Copyright (c) 2009 - 2015 IBM Corporation. * 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: * IBM Corporation - initial API and implementation *****************************************************************************/ package com.ibm.wala.memsat.translation.concurrent; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.propagation.rta.CallSite; import com.ibm.wala.memsat.Options; import com.ibm.wala.memsat.frontEnd.InlinedInstruction; import com.ibm.wala.memsat.frontEnd.WalaCGNodeInformation; import com.ibm.wala.memsat.frontEnd.WalaConcurrentInformation; import com.ibm.wala.memsat.frontEnd.WalaInformation; import com.ibm.wala.memsat.representation.ArrayExpression; import com.ibm.wala.memsat.representation.ExpressionFactory; import com.ibm.wala.memsat.representation.FieldExpression; import com.ibm.wala.memsat.representation.Interpreter; import com.ibm.wala.memsat.translation.Environment; import com.ibm.wala.memsat.translation.MemoryInstructionHandler; import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; import com.ibm.wala.ssa.SSAArrayLoadInstruction; import com.ibm.wala.ssa.SSAArrayStoreInstruction; import com.ibm.wala.ssa.SSAGetInstruction; import com.ibm.wala.ssa.SSAMonitorInstruction; import com.ibm.wala.ssa.SSAPutInstruction; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.IntExpression; import kodkod.ast.Relation; import kodkod.util.collections.CacheSet; import kodkod.util.collections.Stack; /** * Handles memory acesses in a concurrent translation. * @author Emina Torlak */ final class ConcurrentMemoryHandler implements MemoryInstructionHandler { final ConcurrentFactory factory; private final Map<InlinedInstruction, Expression> locations; private final Map<InlinedInstruction, Expression> monitors; private final CacheSet<InlinedInstruction> insts; private final Map<InlinedInstruction, Formula> guards; private final Map<InlinedInstruction, Relation> reads; private final Map<InlinedInstruction, Expression> writes; /** * Constructs a new concurrent memory handler for the given info and * options, set to translate the thread with id 0. * @effects this.info' = info and this.options' = options and this.thread' = 0 and * this.factory' = new ExpressionFactory(info, options) no this.actions' * and no this.guards' */ public ConcurrentMemoryHandler(WalaInformation info, Options options) { this.factory = new ConcurrentFactory(new ExpressionFactory(info, options)); this.insts = new CacheSet<InlinedInstruction>(); this.guards = new LinkedHashMap<InlinedInstruction, Formula>(); for(CGNode thread : info.threads()) { final WalaConcurrentInformation tInfo = info.concurrentInformation(thread); insts.addAll( tInfo.actions() ); guards.put( tInfo.start(), Formula.TRUE); guards.put( tInfo.end(), Formula.TRUE); } this.locations = new LinkedHashMap<InlinedInstruction, Expression>(); this.monitors = new LinkedHashMap<InlinedInstruction, Expression>(); this.reads = new LinkedHashMap<InlinedInstruction, Relation>(); this.writes = new LinkedHashMap<InlinedInstruction, Expression>(); } /** * Returns the guard for the execution of the given instruction, as given to this * memory handler during translation. * @return guard for the execution of the given instruction */ Formula guardFor(InlinedInstruction inst) { return guards.get(inst); } /** * Returns an expression that describes the location that is read/written by the given * instruction, or null if the instruction is not a read or a write. * The read/write location for a static field is the empty set; the location for * a member field is the instance containing the accessed field; and the location for an array access * is the union of the accessed array instance and the accessed index. * @return an expression that describes the location that is read/written by the given * instruction, or null if the instruction is not a read or a write. */ Expression locationOf(InlinedInstruction inst) { return locations.get(inst); } /** * Returns an expression that evaluates to the object that is locked or unlocked by the given * instruction, or null if the instruction is not a monitor access. * @return an expression that evaluates to the object that is locked or unlocked by the given * instruction, or null if the instruction is not a monitor access. */ Expression monitorOf(InlinedInstruction inst) { return monitors.get(inst); } /** * Returns an expression that evaluates to the object that is written by the given * instruction, or null if the instruction is not a write. * @return an expression that evaluates to the object that is written by the given * instruction, or null if the instruction is not a write. */ Expression valueWritten(InlinedInstruction inst) { return writes.get(inst); } /** * Returns a map from the translated read instructions to free variables that represent the values * read by those instructions. * @return a map from the translated read instructions to free variables that represent the values * read by those instructions. */ Map<InlinedInstruction,Relation> valuesRead() { return reads; } /** * Returns an action corresponding to the given * instruction index in the given environment, if one exists in * any of the threads in this.info. Otherwise returns null. * @return { inst: InlinedInstruction | inst.instructionIndex() = instIdx && * inst.cgNode = env.top.callInfo.cgNode && * inst.callStack = env.callStack() } */ private InlinedInstruction action(int instIdx, Environment env) { final Stack<CallSite> callStack = env.callStack(); final CGNode cgNode = env.top().callInfo().cgNode(); final int hash = instIdx + callStack.hashCode() + cgNode.hashCode(); // System.out.println("-----------------------"); // System.out.println("HASH: " + hash); // System.out.println("cgNode: " + cgNode); // System.out.println("callstack: ["); // for(CallSite n : callStack) { // System.out.println(" (" + n.getNode() + " ; " + n.getSite() + "),"); // } // System.out.println("]"); // System.out.println("inst index: " + instIdx); for(Iterator<InlinedInstruction> itr = insts.get(hash); itr.hasNext(); ) { InlinedInstruction inst = itr.next(); if (inst.instructionIndex()==instIdx && inst.cgNode().equals(cgNode) && inst.callStack().equals(callStack)) { // System.out.println("RETURNING INST: " + inst); return inst; } } // System.out.println("RETURNING NULL!"); return null; } /** * Looks up the value read by the given field or array read instruction. * @requires inst.instruction in SSAGetInstruction + SSAArrayLoadInstruction * @return value read by the given field or array read instruction */ private Object value(InlinedInstruction inst) { final WalaCGNodeInformation nodeInfo = factory.base().info().cgNodeInformation(inst.cgNode()); final Interpreter<?> interpreter = factory.base().constants().interpreter(nodeInfo.typeOf(inst.instruction().getDef())); Relation val = reads.get(inst); if (val==null) { val = Relation.nary("val@"+inst.instruction(), interpreter.defaultObj().arity()); reads.put(inst, val); } return interpreter.fromObj(val); } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handleArrayLoad(int, com.ibm.wala.ssa.SSAArrayLoadInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handleArrayLoad(int instIdx, SSAArrayLoadInstruction inst, Formula guard, Environment env) { final Expression ref = env.refUse(inst.getArrayRef()); final IntExpression idx = env.intUse(inst.getIndex()); final InlinedInstruction action = action(instIdx, env); if (action==null) { final int arrayUse = env.top().callInfo().fieldSSA().getUse(inst, 0); final ArrayExpression<?> array = env.arrayUse(arrayUse); env.localDef(inst.getDef(), array.read(ref,idx)); } else { env.localDef(inst.getDef(), value(action)); guards.put(action, guard); locations.put(action, ref.union(factory.base().constants().intInterpreter().toObj(idx))); } } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handleArrayStore(int, com.ibm.wala.ssa.SSAArrayStoreInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handleArrayStore(int instIdx, SSAArrayStoreInstruction inst, Formula guard, Environment env) { final int arrayUse = env.top().callInfo().fieldSSA().getUse(inst, 0); final int arrayDef = env.top().callInfo().fieldSSA().getDef(inst, 0); final ArrayExpression<Object> array = env.arrayUse(arrayUse); final Expression ref = env.refUse(inst.getArrayRef()); final IntExpression idx = env.intUse(inst.getIndex()); final Object value = env.localUse(inst.getValue()); env.heapDef(arrayDef, array.write(ref,idx,value)); final InlinedInstruction action = action(instIdx, env); if (action != null) { guards.put(action, guard); locations.put(action, ref.union(array.indexInterpreter().toObj(idx))); writes.put(action, array.valueInterpreter().toObj(value)); } } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handleGet(int, com.ibm.wala.ssa.SSAGetInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handleGet(int instIdx, SSAGetInstruction inst, Formula guard, Environment env) { final Expression ref = inst.isStatic() ? null : env.refUse(inst.getRef()); final InlinedInstruction action = action(instIdx, env); if (action==null) { final int fieldUse = env.top().callInfo().fieldSSA().getUse(inst, 0); final FieldExpression<?> field = env.fieldUse(fieldUse); env.localDef(inst.getDef(), field.read(ref)); } else { env.localDef(inst.getDef(), value(action)); guards.put(action, guard); locations.put(action, ref==null ? factory.fieldOf(action) : ref.union(factory.fieldOf(action))); } } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handlePut(int, com.ibm.wala.ssa.SSAPutInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handlePut(int instIdx, SSAPutInstruction inst, Formula guard, Environment env) { final int fieldUse = env.top().callInfo().fieldSSA().getUse(inst, 0); final int fieldDef = env.top().callInfo().fieldSSA().getDef(inst, 0); final FieldExpression<Object> field = env.fieldUse(fieldUse); final Expression ref = inst.isStatic() ? null : env.refUse(inst.getRef()); final Object value = env.localUse(inst.getVal()); env.heapDef(fieldDef, field.write(ref, value)); final InlinedInstruction action = action(instIdx, env); if (action != null) { guards.put(action, guard); locations.put(action, ref==null ? factory.fieldOf(action) : ref.union(factory.fieldOf(action))); writes.put(action, field.valueInterpreter().toObj(value)); } } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handleMonitor(int, com.ibm.wala.ssa.SSAMonitorInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handleMonitor(int instIdx, SSAMonitorInstruction inst, Formula guard, Environment env) { final InlinedInstruction action = action(instIdx, env); assert (action!=null); guards.put(action, guard); monitors.put(action, env.refUse(inst.getRef())); } /** * {@inheritDoc} * @see com.ibm.wala.memsat.translation.MemoryInstructionHandler#handleSpecialInvoke(int, com.ibm.wala.ssa.SSAAbstractInvokeInstruction, kodkod.ast.Formula, com.ibm.wala.memsat.translation.Environment) */ public void handleSpecialInvoke(int instIdx, SSAAbstractInvokeInstruction inst, Formula guard, Environment env) { final InlinedInstruction action = action(instIdx, env); assert (action!=null); guards.put(action, guard); } public String toString() { final StringBuilder s = new StringBuilder(); s.append("INSTRUCTIONS: \n"); for(InlinedInstruction inst : insts) { s.append("[[" + System.identityHashCode(inst) + ", " + inst.hashCode() + "]] " + inst + "\n"); } s.append("GUARDS: \n"); for(Map.Entry<InlinedInstruction, Formula> entry : guards.entrySet()) { s.append("[[" + System.identityHashCode(entry.getKey()) + "]] "); s.append(entry.getKey() + " GUARDED BY " + entry.getValue()); s.append("\n"); } s.append("READS: \n"); for(Map.Entry<InlinedInstruction, Relation> entry : reads.entrySet()) { s.append("[[" + System.identityHashCode(entry.getKey()) + "]] "); s.append(entry.getKey() + " REPRESENTED BY " + entry.getValue()); s.append("\n"); } return s.toString(); } }