package com.sun.tools.javac.code;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.sun.tools.javac.code.Effect.VariableEffect;
import com.sun.tools.javac.code.Symbol.MethodSymbol;
import com.sun.tools.javac.code.Symbol.VarSymbol;
import com.sun.tools.javac.code.Substitute.AsMemberOf;
import com.sun.tools.javac.code.Substitute.Subst;
import com.sun.tools.javac.code.Substitute.SubstRPLs;
import com.sun.tools.javac.code.Type.ClassType;
import com.sun.tools.javac.comp.Attr;
import com.sun.tools.javac.comp.AttrContext;
import com.sun.tools.javac.comp.Env;
import com.sun.tools.javac.comp.Resolve;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.JCTree.JCExpression;
import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
import com.sun.tools.javac.tree.JCTree.JCIdent;
import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
import com.sun.tools.javac.tree.JCTree.JCTreeWithEffects;
import com.sun.tools.javac.util.List;
import com.sun.tools.javac.util.ListBuffer;
import com.sun.tools.javac.util.Pair;
/**
* A collection class representing a set of effects.
*/
public class Effects implements
Iterable<Effect>,
SubstRPLs<Effects>,
AsMemberOf<Effects>
{
private Set<Effect> effects = new HashSet<Effect>();
public static final Effects UNKNOWN = new Effects();
public Effects() {}
public Effects(Effect effect) {
add(effect);
}
/** If this effect collection represents a single effect variable, extract the
* variable; otherwise return null.
*/
public VariableEffect asVariableEffect() {
if (effects.size() != 1) return null;
Effect effect = effects.iterator().next();
return (effect instanceof VariableEffect) ?
(VariableEffect) effect : null;
}
public void add(Effect effect) {
effects.add(effect);
}
public void addAll(Effects otherEffects) {
for (Effect e : otherEffects)
this.add(e);
}
public void addAllEffects(Iterable<? extends JCTreeWithEffects> trees) {
for (JCTreeWithEffects tree : trees)
this.addAll(tree.effects);
}
public boolean isEmpty() {
return effects.isEmpty();
}
/** @return an arbitrary effect from this set, or <code>null</code> if it is empty */
public Effect first() {
Iterator<Effect> it = effects.iterator();
if (it.hasNext())
return it.next();
else
return null;
}
/** @return a new Effects set that is a duplicate of this one without the given Effect */
public Effects without(Effect e) {
Effects result = new Effects();
for (Effect effect : effects)
if (!effect.equals(e))
result.add(effect);
return result;
}
/**
* Do all the RPL and effect parameter substitutions implied by the bindings of t
*/
public Effects substForAllParams(Type t) {
Effects result = new Effects();
for (Effect e : effects) {
result.addAll(e.substAllParams(t));
}
return result;
}
/** @return a new Effects set where the RPL parameters 'from'
* have been replaced with the RPLs 'to' */
public Effects substRPLParams(Iterable<RPL> from, Iterable<RPL> to) {
Effects result = new Effects();
for (Effect e : effects) {
result.add(e.substRPLParams(from, to));
}
return result;
}
public Effects substTRParams(Iterable<Type> from, Iterable<Type> to) {
Effects result = new Effects();
for (Effect e : effects) {
result.add(e.substTRParams(from, to));
}
return result;
}
public Effects substEffectParams(Iterable<Effects> from,
Iterable<Effects> to) {
Effects result = new Effects();
for (Effect e : effects) {
result.addAll(e.substEffectParams(from, to));
}
return result;
}
public Effects substRPLForVar(VarSymbol from, RPL to) {
Effects result = new Effects();
for (Effect e : effects) {
result.add(e.substRPLForVar(from, to));
}
return result;
}
public Effects substVars(Iterable<VarSymbol> from,
Iterable<VarSymbol> to) {
Effects result = new Effects();
for (Effect e : effects) {
result.add(e.substVars(from, to));
}
return result;
}
public Effects substExpsForVars(Iterable<VarSymbol> from,
Iterable<JCExpression> to) {
Effects result = new Effects();
for (Effect e : effects) {
result.add(e.substExpsForVars(from, to));
}
return result;
}
public Effects substIndices(Iterable<VarSymbol> from,
Iterable<JCExpression> to) {
Effects result = new Effects();
for (Effect e: effects) {
result.add(e.substIndices(from, to));
}
return result;
}
public Iterator<Effect> iterator() {
return effects.iterator();
}
@Override public String toString() {
return trim().effects.toString();
}
@Override
public int hashCode() {
return this.effects.hashCode();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Effects))
return false;
return effects.equals(((Effects)o).effects);
}
/** @return true iff every Effect in this set is a subeffect of at least one
* Effect in the given set
*/
public boolean areSubeffectsOf(Effects otherEffects) {
if (effects.isEmpty()) return true;
if (effects == UNKNOWN || otherEffects == UNKNOWN) return true;
Effect e = this.first();
if (!e.isSubeffectOf(otherEffects)) {
return false;
} else {
return this.without(e).areSubeffectsOf(otherEffects);
}
}
/** @return a set of Effects in this set that are <b>not</b> subeffects
* of at least one Effect in the given set
*/
public Effects missingFrom(Effects otherEffects) {
Effects result = new Effects();
for (Effect e : effects)
if (!e.isSubeffectOf(otherEffects))
result.add(e);
return result;
}
/**
* The effects as a member of t
*/
public Effects asMemberOf(Type t, Types types) {
Effects memberEffects = new Effects();
for (Effect e : effects) {
memberEffects.addAll(e.asMemberOf(t, types));
}
return memberEffects;
}
/**
* Translate effects from method signature context to method use context. This
* is used both for declared effects and for method effect constraints.
* @return Translated effects
*/
public Effects translateMethodEffects(JCMethodInvocation tree,
Types types, Attr attr, Env<AttrContext> env) {
MethodSymbol sym = tree.getMethodSymbol();
JCExpression selectedExp = attr.rs.selectedExp(tree.meth,env);
Effects result = this;
if (sym != null) {
// Translate to subclass and substitute for class
// region and effect params
if (selectedExp.type instanceof ClassType) {
ClassType ct = (ClassType) selectedExp.type;
result =
result.asMemberOf(ct.tsym.type, types);
if (ct.getRPLArguments().size() ==
ct.tsym.type.getRPLArguments().size()) {
result =
result.substRPLParams(ct.tsym.type.getRPLArguments(),
ct.getRPLArguments());
}
result =
result.substEffectParams(ct.tsym.type.getEffectArguments(),
ct.getEffectArguments());
}
// Substitute for actual arg expressions
RPL rpl = attr.exprToRPL(selectedExp);
if (rpl != null) {
result = result.substRPLForVar(tree.getThisSymbol(), rpl);
}
result = result.substExpsForVars(sym.params, tree.args);
MethodSymbol methSym = tree.getMethodSymbol();
if (tree.mtype != null) {
// Substitute for method region params
if (sym.rgnParams != null) {
result = result.substRPLParams(sym.rgnParams,
tree.mtype.regionActuals);
}
// Substitute for type region params
if (sym.typarams != null) {
result = result.substTRParams(sym.typarams,
tree.mtype.typeactuals);
}
if (methSym != null) {
List<Type> paramtypes = methSym.type.getParameterTypes();
ListBuffer<Type> argtypes = ListBuffer.lb();
for (JCExpression arg : tree.getArguments())
argtypes.append(arg.type);
result = result.substTRParams(paramtypes, argtypes.toList());
}
}
// Substitute for index exprs
if (methSym != null && methSym.params != null &&
!effects.isEmpty() && !tree.getArguments().isEmpty()) {
result = result.substIndices(methSym.params,
tree.getArguments());
}
// Substitute for method effect params
if (sym.effectparams != null && tree.mtype != null) {
result = result.substEffectParams(sym.effectparams,
tree.mtype.effectactuals);
}
}
return result;
}
/**
* The effect set as it appears in the environment env:
* - RPLs that refer to out-of-scope variables get converted to
* more general RPLs
* - RPLs that refer to out-of-scope local region names get
* deleted
* - Stack regions corresponding to out-of-scope local variables
* get deleted
*/
public Effects inEnvironment(Resolve rs, Env<AttrContext> env,
boolean pruneLocalEffects) {
Effects newEffects = new Effects();
boolean changed = false;
for (Effect e : effects) {
Effect newEffect = e.inEnvironment(rs, env, pruneLocalEffects);
if (newEffect == null) {
changed = true;
} else {
newEffects.add(newEffect);
if (newEffect != e) changed = true;
}
}
return changed ? newEffects : this;
}
/**
* Return an effect set given by the argument effect set, occurring
* in an atomic statement.
*/
public Effects inAtomic() {
Effects newEffects = new Effects();
boolean changed = false;
for (Effect e : effects) {
Effect newEffect = e.inAtomic();
newEffects.add(newEffect);
if (newEffect != e) changed = true;
}
return changed ? newEffects : this;
}
/**
* Capture all effects
*/
public Effects capture() {
Effects capturedEffects = new Effects();
boolean changed = false;
for (Effect e : effects) {
Effect capturedEffect = e.capture();
capturedEffects.add(capturedEffect);
if (capturedEffect != e) changed = true;
}
return changed ? capturedEffects : this;
}
/**
* Check whether two effect sets are noninterfering
*/
public static boolean noninterferingEffects(Effects effects1, Effects effects2,
Constraints constraints, boolean atomicOK) {
if (effects1.isEmpty()) return true;
Effect e = effects1.first();
boolean result = e.isNoninterferingWith(effects2, constraints, atomicOK);
if (result) {
effects1 = effects1.without(e);
result = noninterferingEffects(effects1, effects2,
constraints, atomicOK);
}
return result;
}
/**
* Check whether noninterference constraints are satisfied
*/
public static boolean nonintConstraintsAreSatisfied
(Iterable<Pair<Effects,Effects>> constraints,
Type t, Constraints envConstraints) {
for (Pair<Effects,Effects> constraint : constraints) {
Effects first = constraint.fst.substForAllParams(t);
Effects second = constraint.snd.substForAllParams(t);
if (!noninterferingEffects(first, second, envConstraints, false)) {
return false;
}
}
return true;
}
public static boolean nonintConstraintsAreSatisfied
(Iterable<Pair<Effects,Effects>> constraints,
JCMethodInvocation tree,
List<RPL> rplFormals, List<RPL> rplActuals,
List<Effects> effectFormals, List<Effects> effectActuals,
Types types, Attr attr, Env<AttrContext> env) {
Constraints envConstraints = env.info.constraints;
for (Pair<Effects,Effects> constraint : constraints) {
Effects first = constraint.fst.translateMethodEffects(tree, types, attr, env);
first = first.substRPLParams(rplFormals, rplActuals);
first = first.substEffectParams(effectFormals, effectActuals);
Effects second = constraint.snd.translateMethodEffects(tree, types, attr, env);
second = second.substRPLParams(rplFormals, rplActuals);
second = second.substEffectParams(effectFormals, effectActuals);
if (!noninterferingEffects(first, second, envConstraints, false)) {
System.out.println(first + " interferes with " +second);
return false;
}
}
return true;
}
/** Trim effects to minimal set
*/
public Effects trim() {
Effects newEffects = new Effects();
newEffects.effects.addAll(this.effects);
boolean changed = false;
for (Effect e : effects) {
newEffects.effects.remove(e);
if (e.isSubeffectOf(newEffects)) {
changed = true;
} else {
newEffects.effects.add(e);
}
}
return changed ? newEffects : this;
}
/**
* Substitution classes
*/
public static final Subst substRPLParams = new Subst<Effects,RPL,RPL>() {
public Effects basic(Effects effects, RPL from, RPL to) {
return effects.substRPLParams(List.of(from), List.of(to));
}
public Effects substIterable(Effects effects, Iterable<RPL> from,
Iterable<RPL> to) {
return effects.substRPLParams(from, to);
}
};
public static final Subst substEffectParams = new Subst<Effects,Effects,Effects>() {
public Effects basic(Effects effects, Effects from, Effects to) {
return effects.substEffectParams(List.of(from), List.of(to));
}
public Effects substIterable(Effects effects, Iterable<Effects> from,
Iterable<Effects> to) {
return effects.substEffectParams(from, to);
}
};
public static final Subst substRPLsForVars = new Subst<Effects,VarSymbol,RPL>() {
public Effects basic(Effects effects, VarSymbol from, RPL to) {
return effects.substRPLForVar(from, to);
}
};
public static final Subst substIndices =
new Subst<Effects,VarSymbol,JCExpression>() {
public Effects basic(Effects effects, VarSymbol from, JCExpression to) {
return effects.substIndices(List.of(from), List.of(to));
}
public Effects substIterable(Effects effects, Iterable<VarSymbol> from,
Iterable<JCExpression> to) {
return effects.substIndices(from, to);
}
};
}