/****************************************************************************** * 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.concurrent; import java.util.Set; import com.ibm.wala.ipa.callgraph.CGNode; import com.ibm.wala.memsat.frontEnd.InlinedInstruction; import com.ibm.wala.memsat.frontEnd.InlinedInstruction.Action; import com.ibm.wala.memsat.frontEnd.WalaInformation; import com.ibm.wala.util.graph.Graph; import kodkod.ast.Expression; import kodkod.ast.Formula; import kodkod.ast.Relation; import kodkod.instance.Bounds; /** * A relational model of a concurrent program. A program * has one or more threads, each of which has a number * of instructions (reads, writes, locks, etc.). Each instruction, * when {@linkplain Execution executed}, performs an <i>action</i>. * For example, a write instruction performs a write action on a memory * location (variable) using a particular value. * * * @specfield info: WalaInformation * @specfield options: Options * @specfield instructions: set InlinedInstruction // all instructions in this program * @specfield universe: Universe // universe of interpretation for this program * @specfield threads: info.threads.nodes ->one Expression // constant unary expression that represents all threads in this program * @specifeld thread: Expression // constant binary expression that binds each action in this.universe to the unique thread that may execute that action * @specfield endsBefore: Expression // constant binary expression that specifies the end/start ordering between info.threads * @specfield actions: Action ->one Expression // binds each Action to the constant unary expression that contains all actions of that kind in this.universe * @specfield instructions = { inst: InlinedInstruction | some n: CGNode | info.concurrentInformation(n).actions().contains(inst) } * @author etorlak */ public interface Program { /** * Returns the wala info for this program. * @return this.info */ public abstract WalaInformation info(); /** * Returns the constant unary expression that represent the threads with the given root (entry) methods. * @requires roots in this.info.threads.nodes * @return union(this.threads[roots]) */ public abstract Expression threads(Set<CGNode> roots); /** * Returns the constant unary expression that represents all actions of the specified * kind that may be performed when this program is executed * @return kind.length==0 ? Expression.NONE : Expression.union(this.actions[kind[int]]) */ public abstract Expression allOf(Action... kind) ; /** * Returns an expression that evaluates to the actions that the given thread(s) may perform * when executed or to the empty set if the given expression does not evaluate to a thread * (or a set of threads) in this.universe. * @requires thread.arity = 1 * @return { e: Expression | [[e]] = [[this.thread]] . [[thread]] } */ public abstract Expression actionsOf(Expression thread); /** * Returns an expression that evaluates to the thread(s) that may execute the given action(s) or to * the empty set if the given expression does not evaluate to an action (or a set of actions) * in this.universe. * @requires action.arity = 1 * @return { e: Expression | [[e]] = [[action]] . [[this.thread]] } */ public abstract Expression threadOf(Expression action); /** * Returns the constant binary expression that represents the end/start ordering between threads. * In particular, if t1->t2 is in endsBefore, then the thread t1 must finish executing before t2 can start. * @return this.endsBefore */ public abstract Expression endsBefore(); /** * Returns a Formula that evaluates to true iff the given execution is sequentially valid with respect * to this program. A non-speculative execution is valid iff its po, v, and w respect the sequential * semantics of this program; it violates one or more of the user-specified assertions; and it satisfies * all of the user-specified assumptions. A speculative execution is valid iff its po, v and w respect * the sequential semantics of this program. * @requires exec.prog = this * @return a Formula that evaluates to true iff the given execution is sequentially valid with respect * to this program. */ public abstract Formula sequentiallyValid(Execution exec) ; /** * Returns a {@linkplain BoundsBuilder} for this program. The returned builder is initialized * with a fresh Bounds object that contains sounds lower/upper bounds on all the relations that define * this program. The builder provides a set of methods for building bounds for a {@linkplain Justification} * produced by the {@linkplain MemoryModel} used in the construction of this program. * @return a {@linkplain BoundsBuilder} for this program. */ public abstract BoundsBuilder builder(); /** * Provides a set of methods for building analysis bounds for * a {@linkplain Justification} produced by a particular {@linkplain MemoryModel}. * @specfield prog: Program * @specfield mem: prog.options.memoryModel() * @specfield lower: WalaStructures.instructions(prog) ->one TupleSet * @specfield upper: WalaStructures.instructions(prog) ->one TupleSet * @specfield bounds: Bounds \\ bounds being built * @author etorlak */ public static interface BoundsBuilder { /** * Bounds the key relations that comprise the given execution: e.action[InlinedInstruction], e.v, * e.w, e.location, and e.monitor. * @requires e.prog = this.prog * @effects this.bounds.relations' = this.bounds.relations + e.action[InlinedInstruction] + e.v + e.w + e.location + e.monitor */ public abstract void boundExecution(Execution e); /** * Bounds the given relation from above using the upper bounds on the instructions in the given graph. * @requires r.arity = 2 * @effects this.bounds.relations' = this.bounds.relations' + r * @effects this.bounds.lowerBound' = this.bounds.lowerBound * @effects this.bounds.upperBound' = this.bounds.upperBound' ++ * r->{t: Tuple | some i1, i2: InlinedInstruction | upper.hasEdge(i1, i2) && t in this.upper[i1]->this.upper[i2] } */ public abstract void boundOrdering(Relation r, Graph<InlinedInstruction> upper); /** * Bounds the given relation from above using the upper bounds on the given instructions. * @requires r.arity = 1 * @effects this.bounds.relations' = this.bounds.relations' + r * @effects this.bounds.lowerBound' = this.bounds.lowerBound * @effects this.bounds.upperBound' = this.bounds.upperBound' ++ * r->{t: Tuple | some i: upper | this.upper[i].contains(t)} */ public abstract void boundActions(Relation r, Set<InlinedInstruction> insts); /** * Returns the built bounds. * @return this.bounds */ public abstract Bounds build(); } }