/* Soot - a J*va Optimization Framework
* Copyright (C) 1997-2000 Etienne Gagnon. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.jimple.toolkits.typing.integer;
import java.util.*;
/** Represents a type variable. **/
class TypeVariable implements Comparable
{
private static final boolean DEBUG = false;
private final int id;
private TypeVariable rep = this;
private int rank = 0;
private TypeNode approx;
private TypeNode inv_approx;
private TypeNode type;
private List<TypeVariable> parents = Collections.unmodifiableList(new LinkedList());
private List<TypeVariable> children = Collections.unmodifiableList(new LinkedList());
public TypeVariable(int id, TypeResolver resolver)
{
this.id = id;
}
public TypeVariable(int id, TypeResolver resolver, TypeNode type)
{
this.id = id;
this.type = type;
approx = type;
inv_approx = type;
}
public int hashCode()
{
if(rep != this)
{
return ecr().hashCode();
}
return id;
}
public boolean equals(Object obj)
{
if(rep != this)
{
return ecr().equals(obj);
}
if(obj == null)
{
return false;
}
if(!obj.getClass().equals(getClass()))
{
return false;
}
TypeVariable ecr = ((TypeVariable) obj).ecr();
if(ecr != this)
{
return false;
}
return true;
}
public int compareTo(Object o)
{
if(rep != this)
{
return ecr().compareTo(o);
}
return id - ((TypeVariable) o).ecr().id;
}
private TypeVariable ecr()
{
if(rep != this)
{
rep = rep.ecr();
}
return rep;
}
public TypeVariable union(TypeVariable var) throws TypeException
{
if(rep != this)
{
return ecr().union(var);
}
TypeVariable y = var.ecr();
if(this == y)
{
return this;
}
if(rank > y.rank)
{
y.rep = this;
merge(y);
y.clear();
return this;
}
rep = y;
if(rank == y.rank)
{
y.rank++;
}
y.merge(this);
clear();
return y;
}
private void clear()
{
inv_approx = null;
approx = null;
type = null;
parents = null;
children = null;
}
private void merge(TypeVariable var) throws TypeException
{
// Merge types
if(type == null)
{
type = var.type;
}
else if(var.type != null)
{
error("Type Error(22): Attempt to merge two types.");
}
// Merge parents
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
set.addAll(var.parents);
set.remove(this);
parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
// Merge children
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
set.addAll(var.children);
set.remove(this);
children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public int id()
{
if(rep != this)
{
return ecr().id();
}
return id;
}
public void addParent(TypeVariable variable)
{
if(rep != this)
{
ecr().addParent(variable);
return;
}
TypeVariable var = variable.ecr();
if(var == this)
{
return;
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
set.add(var);
parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(var.children);
set.add(this);
var.children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public void removeParent(TypeVariable variable)
{
if(rep != this)
{
ecr().removeParent(variable);
return;
}
TypeVariable var = variable.ecr();
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
set.remove(var);
parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(var.children);
set.remove(this);
var.children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public void addChild(TypeVariable variable)
{
if(rep != this)
{
ecr().addChild(variable);
return;
}
TypeVariable var = variable.ecr();
if(var == this)
{
return;
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
set.add(var);
children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(var.parents);
set.add(this);
var.parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public void removeChild(TypeVariable variable)
{
if(rep != this)
{
ecr().removeChild(variable);
return;
}
TypeVariable var = variable.ecr();
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
set.remove(var);
children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(var.parents);
set.remove(this);
var.parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public List<TypeVariable> parents()
{
if(rep != this)
{
return ecr().parents();
}
return parents;
}
public List<TypeVariable> children()
{
if(rep != this)
{
return ecr().children();
}
return children;
}
public TypeNode approx()
{
if(rep != this)
{
return ecr().approx();
}
return approx;
}
public TypeNode inv_approx()
{
if(rep != this)
{
return ecr().inv_approx();
}
return inv_approx;
}
public TypeNode type()
{
if(rep != this)
{
return ecr().type();
}
return type;
}
static void error(String message) throws TypeException
{
try
{
throw new TypeException(message);
}
catch(TypeException e)
{
if(DEBUG)
{
e.printStackTrace();
}
throw e;
}
}
/** Computes approximative types. The work list must be
* initialized with all constant type variables. */
public static void computeApprox(TreeSet<TypeVariable> workList) throws TypeException
{
while(workList.size() > 0)
{
TypeVariable var = workList.first();
workList.remove(var);
var.fixApprox(workList);
}
}
public static void computeInvApprox(TreeSet<TypeVariable> workList) throws TypeException
{
while(workList.size() > 0)
{
TypeVariable var = workList.first();
workList.remove(var);
var.fixInvApprox(workList);
}
}
private void fixApprox(TreeSet<TypeVariable> workList) throws TypeException
{
if(rep != this)
{
ecr().fixApprox(workList);
return;
}
for (TypeVariable typeVariable : parents) {
TypeVariable parent = typeVariable.ecr();
if(parent.approx == null)
{
parent.approx = approx;
workList.add(parent);
}
else
{
TypeNode type = parent.approx.lca_2(approx);
if(type != parent.approx)
{
parent.approx = type;
workList.add(parent);
}
}
}
if(type != null)
{
approx = type;
}
}
private void fixInvApprox(TreeSet<TypeVariable> workList) throws TypeException
{
if(rep != this)
{
ecr().fixInvApprox(workList);
return;
}
for (TypeVariable typeVariable : children) {
TypeVariable child = typeVariable.ecr();
if(child.inv_approx == null)
{
child.inv_approx = inv_approx;
workList.add(child);
}
else
{
TypeNode type = child.inv_approx.gcd_2(inv_approx);
if(type != child.inv_approx)
{
child.inv_approx = type;
workList.add(child);
}
}
}
if(type != null)
{
inv_approx = type;
}
}
public String toString()
{
if(rep != this)
{
return ecr().toString();
}
StringBuffer s = new StringBuffer();
s.append(",[parents:");
{
boolean comma = false;
for (TypeVariable typeVariable : parents) {
if(comma)
{
s.append(",");
}
else
{
comma = true;
}
s.append(typeVariable.id());
}
}
s.append("],[children:");
{
boolean comma = false;
for (TypeVariable typeVariable : children) {
if(comma)
{
s.append(",");
}
else
{
comma = true;
}
s.append(typeVariable.id());
}
}
s.append("]");
return "[id:" + id + ((type != null) ? (",type:" + type) : "") + ",approx:" + approx + ",inv_approx:" + inv_approx + s + "]";
}
public void fixParents()
{
if(rep != this)
{
ecr().fixParents();
return;
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(parents);
parents = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
public void fixChildren()
{
if(rep != this)
{
ecr().fixChildren();
return;
}
{
Set<TypeVariable> set = new TreeSet<TypeVariable>(children);
children = Collections.unmodifiableList(new LinkedList<TypeVariable>(set));
}
}
}