/******************************************************************************* * Copyright (c) 2002 - 2006 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.ipa.callgraph.propagation; import java.util.Comparator; import com.ibm.wala.classLoader.ArrayClass; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.ipa.callgraph.propagation.cfa.ExceptionReturnValueKey; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.types.TypeReference; import com.ibm.wala.util.debug.Assertions; public class PointerKeyComparator implements Comparator { private final IClassHierarchy cha; public PointerKeyComparator(IClassHierarchy cha) { if (cha == null) { throw new IllegalArgumentException("null cha"); } this.cha = cha; } protected int comparePrimitives(TypeReference r1, TypeReference r2) { int h1 = r1.hashCode(); int h2 = r2.hashCode(); if (h1 != h2) return h1-h2; else { assert r1 == r2; return 0; } } protected int compareConcreteTypes(IClass k1, IClass k2) { int n1 = cha.getNumber( k1 ); int n2 = cha.getNumber( k2 ); if (n1 != n2) return n1-n2; else { int s1 = k1.hashCode(); int s2 = k2.hashCode(); assert k1 == k2 || s1 != s2; return s1-s2; } } protected int compareInstanceKeys(InstanceKey k1, InstanceKey k2) { return compareConcreteTypes( k1.getConcreteType(), k2.getConcreteType() ); } protected int compareFields(IField if1, IField if2) { int f1 = if1.hashCode(); int f2 = if2.hashCode(); if (f1 != f2) return f1-f2; else { assert if1 == if2; return 0; } } private int compareLocalKey(LocalPointerKey key1, Object key2) { if (key2 instanceof LocalPointerKey) { int l1 = key1.getValueNumber(); int l2 = ((LocalPointerKey)key2).getValueNumber(); if (l1 != l2) return l1-l2; else { int n1 = key1.getNode().getGraphNodeId(); int n2 = ((LocalPointerKey)key2).getNode().getGraphNodeId(); if (n1 != n2) return n1-n2; else { assert key1.equals(key2); return 0; } } } else return -1; } private int compareReturnValueKey(ReturnValueKey key1, Object key2) { if (key2 instanceof ReturnValueKey) { int n1 = key1.getNode().getGraphNodeId(); int n2 = ((ReturnValueKey)key2).getNode().getGraphNodeId(); if (n1 != n2) return n1-n2; else { assert key1.equals(key2); return 0; } } else return -1; } private int compareExceptionKey(ExceptionReturnValueKey key1, Object key2) { if (key2 instanceof ExceptionReturnValueKey) { int n1 = key1.getNode().getGraphNodeId(); int n2 = ((ExceptionReturnValueKey)key2).getNode().getGraphNodeId(); if (n1 != n2) return n1-n2; else { assert key1.equals(key2); return 0; } } else return -1; } private int compareFieldKey(InstanceFieldKey key1, Object key2) { if (key2 instanceof InstanceFieldKey) { int r1 = compareInstanceKeys(key1.getInstanceKey(), ((InstanceFieldKey)key2).getInstanceKey()); if (r1 != 0) return r1; else { return compareFields(key1.getField(), ((InstanceFieldKey)key2).getField()); } } else return -1; } private int compareStaticKey(StaticFieldKey key1, Object key2) { if (key2 instanceof StaticFieldKey) { int n1 = cha.getNumber( key1.getField().getDeclaringClass() ); int n2 = cha.getNumber( ((StaticFieldKey)key2).getField().getDeclaringClass() ); if (n1 != n2) return n1-n2; else { return compareFields(key1.getField(), ((StaticFieldKey)key2).getField()); } } else return -1; } private int compareArrayKey(ArrayContentsKey key1, Object key2) { if (key2 instanceof ArrayContentsKey) { ArrayClass k1 = (ArrayClass)key1.getInstanceKey().getConcreteType(); ArrayClass k2 = (ArrayClass)((ArrayContentsKey)key2).getInstanceKey().getConcreteType(); int d1 = k1.getDimensionality(); int d2 = k2.getDimensionality(); if (d1 != d2) { return d1-d2; } else if (k1.getInnermostElementClass() == null) { if (k2.getInnermostElementClass() == null) return comparePrimitives( k1.getReference().getInnermostElementType(), k2.getReference().getInnermostElementType()); else return -1; } else if (k2.getInnermostElementClass() == null) { return 1; } else { return compareConcreteTypes( k1.getInnermostElementClass(), k2.getInnermostElementClass()); } } else return -1; } @Override public int compare(Object key1, Object key2) { if (key1 == key2) return 0; else if (key1 instanceof LocalPointerKey) { return compareLocalKey((LocalPointerKey) key1, key2); } else if (key2 instanceof LocalPointerKey) { return -1*compareLocalKey((LocalPointerKey) key2, key1); } // at this point, neither key is local else if (key1 instanceof ReturnValueKey) { return compareReturnValueKey((ReturnValueKey)key1, key2); } else if (key2 instanceof ReturnValueKey) { return -1*compareReturnValueKey((ReturnValueKey)key2, key1); } // at this point, neither key is local or retval else if (key1 instanceof ExceptionReturnValueKey) { return compareExceptionKey((ExceptionReturnValueKey)key1, key2); } else if (key2 instanceof ExceptionReturnValueKey) { return -1*compareExceptionKey((ExceptionReturnValueKey)key2, key1); } // at this point, neither key is local or retval, expretval else if (key1 instanceof InstanceFieldKey) { return compareFieldKey((InstanceFieldKey)key1, key2); } else if (key2 instanceof InstanceFieldKey) { return -1*compareFieldKey((InstanceFieldKey)key2, key1); } // at this point, neither key is local or retval, expretval, field else if (key1 instanceof StaticFieldKey) { return compareStaticKey((StaticFieldKey)key1, key2); } else if (key2 instanceof StaticFieldKey) { return -1*compareStaticKey((StaticFieldKey)key2, key1); } // at this point, neither key is local or retval, expretval, field, static else if (key1 instanceof ArrayContentsKey) { return compareArrayKey((ArrayContentsKey)key1, key2); } else if (key2 instanceof ArrayContentsKey) { return -1*compareArrayKey((ArrayContentsKey)key2, key1); } else { return compareOtherKeys(key1, key2); } } protected int compareOtherKeys(Object key1, Object key2) { System.err.println("Cannot compare " + key1 + " and " + key2); Assertions.UNREACHABLE(); return 0; } @Override public boolean equals(Object o) { return (o instanceof PointerKeyComparator) && ((PointerKeyComparator)o).cha.equals(cha); } @Override public int hashCode() { return cha.hashCode(); } }