/****************************************************************************** * 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 static com.ibm.wala.memsat.util.Graphs.root; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.ipa.callgraph.propagation.PointerKey; import com.ibm.wala.memsat.Options; import com.ibm.wala.memsat.concurrent.Justification; import com.ibm.wala.memsat.frontEnd.FieldSSATable; import com.ibm.wala.memsat.frontEnd.InlinedInstruction; import com.ibm.wala.memsat.frontEnd.WalaConcurrentInformation; import com.ibm.wala.memsat.frontEnd.WalaInformation; import com.ibm.wala.memsat.representation.HeapExpression; import com.ibm.wala.memsat.translation.Environment; import com.ibm.wala.memsat.translation.Environment.Frame; import com.ibm.wala.memsat.translation.MethodTranslation; import com.ibm.wala.memsat.translation.TranslationWarning; import com.ibm.wala.memsat.translation.Translator; import com.ibm.wala.memsat.util.Nodes; import com.ibm.wala.ssa.SSAArrayReferenceInstruction; import com.ibm.wala.ssa.SSAFieldAccessInstruction; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.util.collections.Iterator2Set; import com.ibm.wala.util.graph.Graph; import com.ibm.wala.util.graph.traverse.DFS; /** * A translator for concurrent Wala programs. * * @author Emina Torlak */ public final class ConcurrentTranslator { private ConcurrentTranslator() {} /** * Returns the translation of the method described by the * given wala information instance, with respect to the * specified translation options. * @requires info.threads() > 1 * @return { t : Translation | t.info = info and t.options = options} */ public static ConcurrentTranslation translate(final WalaInformation info, final Options options) { System.out.println("RELEVANT CLASSES: " + info.relevantClasses()); System.out.println("RELEVANT FIELDS: " + info.relevantFields()); System.out.println("THREADS: " + info.threads()); final ConcurrentMemoryHandler handler = new ConcurrentMemoryHandler(info,options); final Map<CGNode, MethodTranslation> transls = translate(handler); // System.out.println(handler); final ConcurrentProgram prog = new ConcurrentProgram(handler, transls); final Justification just = options.memoryModel().justify(prog); final Set<TranslationWarning> warnings = new LinkedHashSet<TranslationWarning>(); for(MethodTranslation transl : transls.values()) { warnings.addAll(transl.warnings()); } //System.out.println(Strings.prettyPrint(just.formula().and(handler.factory.invariants()), 2)); return new ConcurrentTranslation(handler.factory.base(), Nodes.simplify(just.formula().and(handler.factory.invariants()), just.bounds()), just, warnings); } /** * Translates the threads in handler.factory.base.info.threads and returns the result. * In particular, let t1, t2 and t3 be threads such that t1->t3 + t2->t3 in handler.base.info.threads. * Suppose that there are two fields f1 and f2 read by t3 such that f1 is only written by t1 (and no other thread) and f2 is only * written by t2 (and no other thread). Then t3 is translated in an environment that is initialized * with the final value of f1 from the translation of t1 and the final value of f2 from the translation of t2. * This method assumes that if a field is f is written by more than one thread then every access to that field * will appear as an InlinedInstruction in each accessing thread's {@linkplain WalaConcurrentInformation#actions() actions} set. * @requires handler.factory.base().info().threads().equals(threads) * @return a map from each node in the given graph to its translation */ private static Map<CGNode, MethodTranslation> translate(ConcurrentMemoryHandler handler) { final Map<CGNode, MethodTranslation> transls = new LinkedHashMap<CGNode, MethodTranslation>(); final WalaInformation info = handler.factory.base().info(); final Graph<CGNode> threads = info.threads(); for(Iterator<CGNode> itr = DFS.iterateDiscoverTime(threads, root(threads)); itr.hasNext(); ) { final CGNode node = itr.next(); final Set<PointerKey> seqFields = sequentialFields(node, info); final Map<PointerKey,HeapExpression<?>> override; if (seqFields.isEmpty()) { override = Collections.emptyMap(); } else { override = new LinkedHashMap<PointerKey, HeapExpression<?>>(); for(Iterator<? extends CGNode> preds = threads.getPredNodes(node); preds.hasNext(); ) { final CGNode pred = preds.next(); final Frame frame = transls.get(pred).frame(); final FieldSSATable fieldSSA = info.cgNodeInformation(pred).fieldSSA(); for(Iterator<PointerKey> fields = fieldSSA.getFields(); fields.hasNext(); ) { final PointerKey field = fields.next(); if (seqFields.contains(field)) { final HeapExpression<?> initVal = frame.heapUse(fieldSSA.getEntryValue(field)); final HeapExpression<?> finalVal = frame.heapUse(fieldSSA.getExitValue(field)); if (!initVal.equals(finalVal)) { assert !override.containsKey(field); override.put(field, finalVal); } } } } } transls.put(node, Translator.translate((new Environment(handler.factory.base())).push(node, override), handler)); } return transls; } /** * Returns the set of field pointer keys that appear in the node's {@linkplain FieldSSATable field SSA table} * and that are neither used nor defined by an InlinedInstruction * in info.concurrentInformation(node).actions(). * @requires node in info.threads * @return set of field pointer keys that appear in the node's {@linkplain FieldSSATable field SSA table} * and that are neither used nor defined by an InlinedInstruction */ private final static Set<PointerKey> sequentialFields(CGNode node, WalaInformation info) { final FieldSSATable fieldSSA = info.cgNodeInformation(node).fieldSSA(); final Set<PointerKey> sequential = Iterator2Set.toSet(fieldSSA.getFields()); for(InlinedInstruction inst : info.concurrentInformation(node).actions()) { if (node.equals(inst.cgNode())) { final SSAInstruction obj = inst.instruction(); if (obj instanceof SSAFieldAccessInstruction) { for(int use : fieldSSA.getUses(inst.instruction())) { sequential.remove(fieldSSA.getField(use)); } for(int def : fieldSSA.getDefs(inst.instruction())) { sequential.remove(fieldSSA.getField(def)); } } else if (obj instanceof SSAArrayReferenceInstruction) { final int[] uses = fieldSSA.getUses(obj); final int[] defs = fieldSSA.getDefs(obj); assert uses.length == 2; assert defs.length <= 1; sequential.remove(fieldSSA.getField(uses[0])); if (defs.length>0) sequential.remove(fieldSSA.getField(defs[0])); } } } return sequential; } }