/*******************************************************************************
* Copyright (c) 2007 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.demandpa.alg.refinepolicy;
import java.util.Collection;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.classLoader.IField;
import com.ibm.wala.demandpa.alg.statemachine.StateMachine;
import com.ibm.wala.demandpa.flowgraph.IFlowLabel;
import com.ibm.wala.demandpa.util.ArrayContents;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.cha.IClassHierarchy;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.HashSetFactory;
public class TunedFieldRefinementPolicy implements FieldRefinePolicy {
private static final boolean DEBUG = false;
private final IClassHierarchy cha;
private final Collection<IClass> typesToRefine = HashSetFactory.make();
private IClass firstSkippedClass = null;
@Override
public boolean nextPass() {
if (firstSkippedClass != null) {
typesToRefine.add(firstSkippedClass);
if (DEBUG) {
System.err.println("now refining " + firstSkippedClass);
}
firstSkippedClass = null;
return true;
} else {
return false;
}
}
@Override
public boolean shouldRefine(IField field, PointerKey basePtr, PointerKey val, IFlowLabel label, StateMachine.State state) {
if (field == null) {
throw new IllegalArgumentException("null field");
}
if (field == ArrayContents.v()) {
return true;
}
IClass classToCheck = removeInner(field.getDeclaringClass());
if (superOfAnyEncountered(classToCheck)) {
return true;
} else {
if (firstSkippedClass == null) {
firstSkippedClass = classToCheck;
}
return false;
}
}
private boolean superOfAnyEncountered(IClass klass) {
for (IClass toRefine : typesToRefine) {
if (cha.isAssignableFrom(klass, toRefine) || cha.isAssignableFrom(toRefine, klass)) {
return true;
}
}
return false;
}
/**
*
* @param klass
* @return the top-level {@link IClass} where klass is declared, or klass itself if klass is top-level or if top-level
* class not loaded
*/
private IClass removeInner(IClass klass) {
ClassLoaderReference cl = klass.getClassLoader().getReference();
String klassStr = klass.getName().toString();
int dollarIndex = klassStr.indexOf('$');
if (dollarIndex == -1) {
return klass;
} else {
String topMostName = klassStr.substring(0, dollarIndex);
IClass topMostClass = cha.lookupClass(TypeReference.findOrCreate(cl, topMostName));
return (topMostClass != null) ? topMostClass : klass;
}
}
public TunedFieldRefinementPolicy(IClassHierarchy cha) {
this.cha = cha;
}
}