/* * JBoss, Home of Professional Open Source * Copyright 2009-10 Red Hat and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This 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 software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. * * @authors Andrew Dinn */ package org.jboss.byteman.agent.adapter.cfg; import org.objectweb.asm.Label; import java.util.List; import java.util.LinkedList; import java.util.Iterator; /** * auxiliary used by CFG to store details of a specific try catch block */ public class TryCatchDetails { /** * back link to the control flow graph */ private CFG cfg; /** * the label identifying the start of the try catch block */ private Label start; /** * the label identifying the end of the try catch block */ private Label end; /** * the label identifying the start of the try catch block handler */ private Label handler; /** * a list of monitor enter instructions which are opened within the scope of this try catch block * and hence which may require closing in the associated handler */ private List<CodeLocation> openEnters; /** * the name of the exception type handled by the handler or null if it is a catch all handler */ private String type; /** * true if this is a trigger handler otherwise false */ private boolean isTriggerHandler; /** * A list of details for all the try catch regions which shadow this region i.e. which prevent exception * control flow to it from an embedded region because they either catch everything or they catch the * same type or a supertype of this exception. */ private List<TryCatchDetails> shadowRegions; /** * construct a try catch details instance * @param cfg the control flow graph * @param start the try block start * @param end the try block end * @param handler the handler block start * @param type the handled exception type * @param isTriggerHandler true if this handler handles Byteman errors */ public TryCatchDetails(CFG cfg, Label start, Label end, Label handler, String type, boolean isTriggerHandler) { this.cfg = cfg; this.start = start; this.end = end; this.handler = handler; this.openEnters = new LinkedList<CodeLocation>(); this.type = type; this.isTriggerHandler = isTriggerHandler; this.shadowRegions = null; } // accessors public Label getStart() { return start; } public Label getEnd() { return end; } public Label getHandler() { return handler; } public String getType() { return type; } public boolean isTriggerHandler() { return isTriggerHandler; } /** * add a new monitor enter location to the list of open locations associated with this handler * maintaining the reverse position ordering * @param openEnter the location of the monitor enter */ public void addOpenEnter(CodeLocation openEnter) { Iterator<CodeLocation> iterator = openEnters.iterator(); int pos = 0; while (iterator.hasNext()) { CodeLocation next = iterator.next(); int compare = openEnter.compareTo(next); if (compare < 0) { // need to insert after this one pos++; } else if (compare > 0) { // need to insert before this one break; } else { // already in list! return; } } openEnters.add(pos, openEnter); } /** * check if a monitor enter location belongs to the list of open locations associated with this handler * @param openEnter the location of the monitor enter * @return true if it belongs ot the list */ public boolean containsOpenEnter(CodeLocation openEnter) { return openEnters.contains(openEnter); } /** * add all the open locations associated with this handler to the supplied list of open locations * maintaining the reverse position ordering * @param openMonitorEnters list of locations of the monitor enters */ public void addOpenLocations(List<CodeLocation> openMonitorEnters) { Iterator<CodeLocation> iterator = openEnters.iterator(); while (iterator.hasNext()) { CodeLocation location = iterator.next(); Iterator<CodeLocation> iterator2 = openMonitorEnters.iterator(); int pos = 0; while (iterator2.hasNext()) { CodeLocation next = iterator2.next(); int compare = location.compareTo(next); if (compare < 0) { // need to insert after this one pos++; } else { // need to insert before this one unless it is already present if (compare == 0) { pos = -1; } break; } } if (pos >= 0) { openMonitorEnters.add(pos, location); } } } public Iterator<CodeLocation> getOpenEnters() { return openEnters.iterator(); } /** * add a shadowing region to the list of regions which shadow this one * @param tryCatchDetails detaisl of a try catch block */ public void addShadowRegion(TryCatchDetails tryCatchDetails) { if (shadowRegions == null) { shadowRegions = new LinkedList<TryCatchDetails>(); } if (!shadowRegions.contains(tryCatchDetails)) { shadowRegions.add(tryCatchDetails); } } public List<TryCatchDetails> getShadowRegions() { return shadowRegions; } public boolean hasShadowRegion(TryCatchDetails tryCatchDetails) { return (shadowRegions != null && shadowRegions.contains(tryCatchDetails)); } public String toString() { StringBuilder builder = new StringBuilder(); builder.append("" + type + " try: " + cfg.getLocation(start) + " catch: " + cfg.getLocation(end) + " handler: " + cfg.getLocation(handler)); return builder.toString(); } }