/*
* Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.max.vm.bytecode;
import java.util.*;
import com.sun.max.vm.classfile.*;
import com.sun.max.vm.classfile.constant.*;
/**
* A node in a linked list of objects describing the exception handlers active for a given BCI.
*/
public final class ExceptionHandler {
private final ExceptionHandler next;
private final int catchTypeIndex;
private final int bci;
/**
* Creates an object representing an exception handler.
*
* @param next one or more other exception handlers that cover the same BCI as this handler
* @param catchTypeIndex the constant pool index of the {@link ClassConstant} representing the type of exceptions
* caught by this handler
* @param bci the BCI denoting the start of this exception handler
*/
private ExceptionHandler(ExceptionHandler next, int catchTypeIndex, int bci) {
this.catchTypeIndex = catchTypeIndex;
this.bci = bci;
ExceptionHandler n = next;
while (n != null && n.catchTypeIndex == catchTypeIndex) {
n = n.next;
}
this.next = n;
}
public ExceptionHandler next() {
return next;
}
/**
* Gets the constant pool index of the {@link ClassConstant} representing the type of exceptions caught by this
* handler.
*/
public int catchTypeIndex() {
return catchTypeIndex;
}
/**
* Gets the BCI denoting the start of this exception handler.
*/
public int bci() {
return bci;
}
@Override
public int hashCode() {
final int n = bci ^ catchTypeIndex;
if (next == null) {
return n;
}
return n * next.hashCode();
}
@Override
public boolean equals(Object other) {
if (!(other instanceof ExceptionHandler)) {
return false;
}
final ExceptionHandler handler = (ExceptionHandler) other;
if (catchTypeIndex != handler.catchTypeIndex || bci != handler.bci) {
return false;
}
if (next == null) {
return handler.next == null;
}
return next.equals(handler.next);
}
/**
* Creates a mapping from each BCI within the range covered by at least one exception handler to the
* list of exception handlers that cover the BCI. Note that the returned mapping includes non-null entries for
* all BCIs covered by at least one exception handler, including BCIs that may be in the middle of an
* instruction.
*
* @return an array mapping each BCI to an exception handler list (or null)
*/
public static ExceptionHandler[] createHandlerMap(int codeLength, ExceptionHandlerEntry[] exceptionHandlerEntries) {
final ExceptionHandler[] handlerMap = new ExceptionHandler[codeLength];
final HashMap<ExceptionHandler, ExceptionHandler> handlers = new HashMap<ExceptionHandler, ExceptionHandler>();
for (int i = exceptionHandlerEntries.length - 1; i >= 0; i--) {
ExceptionHandlerEntry info = exceptionHandlerEntries[i];
final int catchTypeIndex = info.catchTypeIndex();
for (int bci = info.startBCI(); bci < info.endBCI(); bci++) {
final ExceptionHandler candidate = new ExceptionHandler(handlerMap[bci], catchTypeIndex, info.handlerBCI());
ExceptionHandler handler = handlers.get(candidate);
if (handler == null) {
handlers.put(candidate, candidate);
handler = candidate;
}
handlerMap[bci] = handler;
}
}
return handlerMap;
}
public static ExceptionHandler[] createHandlerMap(CodeAttribute codeAttribute) {
final ExceptionHandlerEntry[] exceptionHandlerTable = codeAttribute.exceptionHandlerTable();
if (exceptionHandlerTable.length == 0) {
return null;
}
return createHandlerMap(codeAttribute.code().length, exceptionHandlerTable);
}
}