/* Soot - a J*va Optimization Framework * Copyright (C) 2011 Richard Xiao * * 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. */ package soot.jimple.spark.geom.ptinsE; import soot.jimple.spark.geom.geomPA.GeomPointsTo; import soot.jimple.spark.geom.geomPA.SegmentNode; import soot.jimple.spark.geom.geomPA.IFigureManager; import soot.jimple.spark.geom.geomPA.RectangleNode; /** * The figure manager for the PtIns descriptors. * The implementation is almost same to the HeapIns manager, please refer to HeapInsIntervalManager for more detailed comments. * * @author xiao * */ public class PtInsIntervalManager implements IFigureManager { public static final int Divisions = 3; public static final int ALL_TO_ALL = -1; // A special case public static final int ALL_TO_MANY = 0; public static final int MANY_TO_ALL = 1; public static final int ONE_TO_ONE = 2; int size[] = {0, 0, 0}; SegmentNode header[] = {null, null, null}; private boolean hasNewObject = false; public SegmentNode[] getFigures() { return header; } public int[] getSizes() { return size; } public boolean isThereUnprocessedFigures() { return hasNewObject; } public void flush() { hasNewObject = false; for ( int i = 0; i < Divisions; ++i ) { SegmentNode p = header[i]; while ( p != null && p.is_new == true ) { p.is_new = false; p = p.next; } } } public SegmentNode addNewFigure( int code, RectangleNode pnew ) { SegmentNode p; if ( code == ALL_TO_ALL ) { // Directly clean all the existing intervals if ( header[0] != null && header[0].I2 == 0 ) return null; p = new SegmentNode(); p.I1 = p.I2 = 0; p.L = GeomPointsTo.MAX_CONTEXTS; for ( int i = 0; i < Divisions; ++i ) { size[i] = 0; header[i] = null; } } else { // Duplicate testing if ( code == ALL_TO_MANY || code == ONE_TO_ONE ) { p = header[ALL_TO_MANY]; while ( p != null ) { if ( (p.I2 <= pnew.I2) && (p.I2 + p.L >= pnew.I2 + pnew.L) ) return null; p = p.next; } } if ( code == MANY_TO_ALL || code == ONE_TO_ONE ) { p = header[MANY_TO_ALL]; while ( p != null ) { if ( (p.I1 <= pnew.I1) && (p.I1 + p.L >= pnew.I1 + pnew.L) ) return null; p = p.next; } } // Be careful of this! if ( code == ONE_TO_ONE ) { p = header[ONE_TO_ONE]; while ( p != null ) { if (p.I1 - p.I2 == pnew.I1 - pnew.I2) { // On the same line if (p.I1 <= pnew.I1 && p.I1 + p.L >= pnew.I1 + pnew.L) return null; } p = p.next; } } // Insert the new interval immediately, and we delay the merging until necessary p = new SegmentNode(pnew); if ( code == ALL_TO_MANY ) clean_garbage_all_to_many(p); else if ( code == MANY_TO_ALL ) clean_garbage_many_to_all(p); else clean_garbage_one_to_one(p); } hasNewObject = true; size[code]++; p.next = header[code]; header[code] = p; return p; } public void mergeFigures(int upperSize) { if ( size[ONE_TO_ONE] > upperSize && header[ONE_TO_ONE].is_new == true ) { // After the merging, we must propagate this interval, thus it has to be a new interval SegmentNode p = generate_all_to_many( header[ONE_TO_ONE] ); clean_garbage_all_to_many(p); p.next = header[ALL_TO_MANY]; header[ALL_TO_MANY] = p; header[ONE_TO_ONE] = null; size[ALL_TO_MANY]++; size[ONE_TO_ONE] = 0; } if ( size[MANY_TO_ALL] > upperSize && header[MANY_TO_ALL].is_new == true ) { header[MANY_TO_ALL] = generate_many_to_all( header[MANY_TO_ALL] ); size[MANY_TO_ALL] = 1; } if ( size[ALL_TO_MANY] > upperSize && header[ALL_TO_MANY].is_new == true ) { header[0] = generate_all_to_many( header[ALL_TO_MANY] ); size[ALL_TO_MANY] = 1; } } public void removeUselessSegments() { int i; SegmentNode p, q, temp; p = header[ONE_TO_ONE]; size[ONE_TO_ONE] = 0; q = null; while ( p != null ) { boolean contained = false; for ( i = 0; i < 2; ++i ) { temp = header[i]; while ( temp != null ) { if ( temp.I1 == 0 || ((temp.I1 <= p.I1) && (temp.I1 + temp.L >= p.I1 + p.L)) ) { if (temp.I2 == 0 || ((temp.I2 <= p.I2) && (temp.I2 + temp.L >= p.I2 + p.L))) { contained = true; break; } } temp = temp.next; } } temp = p.next; if ( contained == false ) { p.next = q; q = p; ++size[ONE_TO_ONE]; } p = temp; } header[ONE_TO_ONE] = q; } /** * Merge all the context sensitive intervals. The result is * in the form (p, q, 0, I, L). */ private SegmentNode generate_all_to_many( SegmentNode mp ) { long left, right, t; SegmentNode p; left = mp.I2; right = left + mp.L; p = mp.next; while (p != null) { if (p.I2 < left) left = p.I2; t = p.I2 + p.L; if ( t > right ) right = t; p = p.next; } mp.I1 = 0; mp.I2 = left; mp.L = right - left; mp.next = null; return mp; } /** The result is in the form: (p, q, I, 0, L) */ private SegmentNode generate_many_to_all( SegmentNode mp ) { long left, right, t; SegmentNode p; left = mp.I1; right = left + mp.L; p = mp.next; while (p != null) { if (p.I1 < left) left = p.I1; t = p.I1 + p.L; if ( t > right ) right = t; p = p.next; } // Note, left could be 0. In that case, the propagation along this edge becomes totally insensitive mp.I1 = left; mp.I2 = 0; mp.L = right - left; mp.next = null; return mp; } // Clean garbages in list that the information is already covered by mp // BTW, we do some simple concatenation private void clean_garbage_many_to_all(SegmentNode mp) { SegmentNode p, q, list; int num; long right, left; list = header[1]; p = q = null; num = 0; left = mp.I1; right = left + mp.L; while (list != null) { if (list.I1 >= left) { if (list.I1 <= right) { if ( list.I1 + list.L > right ) { // We extend mp to the right right = list.I1 + list.L; } list = list.next; continue; } } else if (list.I1 + list.L >= left) { // We extend mp to the left left = list.I1; list = list.next; continue; } // No intersection, no overlap // Notice that, we have to preserve the order of the list // Because the unprocessed points-to tuples are headed at the list if ( q == null ) { p = q = list; } else { q.next = list; q = list; } ++num; list = list.next; } mp.I1 = left; mp.L = right - left; if ( q != null ) q.next = null; header[1] = p; size[1] = num; } private void clean_garbage_all_to_many(SegmentNode mp) { SegmentNode p, q, list; int num; long right, left; list = header[0]; p = q = null; num = 0; left = mp.I2; right = mp.I2 + mp.L; while (list != null) { if (list.I2 >= left) { if (list.I2 <= right) { if ( list.I2 + list.L > right ) { // We extend mp to the right right = list.I2 + list.L; } list = list.next; continue; } } else if (list.I2 + list.L >= left) { // We extend mp to the left left = list.I2; list = list.next; continue; } // No intersection, no overlap // Notice that, we have to preserve the order of the list // Because the unprocessed points-to tuples are headed at the list if ( q == null ) { p = q = list; } else { q.next = list; q = list; } ++num; list = list.next; } mp.I2 = left; mp.L = right - left; if ( q != null ) q.next = null; header[0] = p; size[0] = num; } /* * Eliminate the redundant ONE_TO_ONE figures */ private void clean_garbage_one_to_one(SegmentNode predator) { SegmentNode p, q, list; int num; list = header[ONE_TO_ONE]; p = q = null; num = 0; while (list != null) { long L = list.L; if ( (predator.I2 - predator.I1 == list.I2 - list.I1) && predator.I1 <= list.I1 && (predator.I1 + predator.L >= list.I2 + L) ) // The checked figure is completely contained in the predator // So we ignore it ; else { if ( q == null ) { p = q = list; } else { q.next = list; q = list; } ++num; } list = list.next; } if ( q != null ) q.next = null; header[ONE_TO_ONE] = p; size[ONE_TO_ONE] = num; } }