001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 * 017 */ 018package org.apache.bcel.generic; 019 020import org.apache.bcel.classfile.CodeException; 021 022/** 023 * This class represents an exception handler, i.e., specifies the region where 024 * a handler is active and an instruction where the actual handling is done. 025 * pool as parameters. Opposed to the JVM specification the end of the handled 026 * region is set to be inclusive, i.e. all instructions between start and end 027 * are protected including the start and end instructions (handles) themselves. 028 * The end of the region is automatically mapped to be exclusive when calling 029 * getCodeException(), i.e., there is no difference semantically. 030 * 031 * @see MethodGen 032 * @see CodeException 033 * @see InstructionHandle 034 */ 035public final class CodeExceptionGen implements InstructionTargeter, Cloneable { 036 037 private InstructionHandle start_pc; 038 private InstructionHandle end_pc; 039 private InstructionHandle handler_pc; 040 private ObjectType catch_type; 041 042 043 /** 044 * Add an exception handler, i.e., specify region where a handler is active and an 045 * instruction where the actual handling is done. 046 * 047 * @param start_pc Start of handled region (inclusive) 048 * @param end_pc End of handled region (inclusive) 049 * @param handler_pc Where handling is done 050 * @param catch_type which exception is handled, null for ANY 051 */ 052 public CodeExceptionGen(final InstructionHandle start_pc, final InstructionHandle end_pc, 053 final InstructionHandle handler_pc, final ObjectType catch_type) { 054 setStartPC(start_pc); 055 setEndPC(end_pc); 056 setHandlerPC(handler_pc); 057 this.catch_type = catch_type; 058 } 059 060 061 /** 062 * Get CodeException object.<BR> 063 * 064 * This relies on that the instruction list has already been dumped 065 * to byte code or or that the `setPositions' methods has been 066 * called for the instruction list. 067 * 068 * @param cp constant pool 069 */ 070 public CodeException getCodeException( final ConstantPoolGen cp ) { 071 return new CodeException(start_pc.getPosition(), end_pc.getPosition() 072 + end_pc.getInstruction().getLength(), handler_pc.getPosition(), 073 (catch_type == null) ? 0 : cp.addClass(catch_type)); 074 } 075 076 077 /* Set start of handler 078 * @param start_pc Start of handled region (inclusive) 079 */ 080 public void setStartPC( final InstructionHandle start_pc ) { // TODO could be package-protected? 081 BranchInstruction.notifyTarget(this.start_pc, start_pc, this); 082 this.start_pc = start_pc; 083 } 084 085 086 /* Set end of handler 087 * @param end_pc End of handled region (inclusive) 088 */ 089 public void setEndPC( final InstructionHandle end_pc ) { // TODO could be package-protected? 090 BranchInstruction.notifyTarget(this.end_pc, end_pc, this); 091 this.end_pc = end_pc; 092 } 093 094 095 /* Set handler code 096 * @param handler_pc Start of handler 097 */ 098 public void setHandlerPC( final InstructionHandle handler_pc ) { // TODO could be package-protected? 099 BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this); 100 this.handler_pc = handler_pc; 101 } 102 103 104 /** 105 * @param old_ih old target, either start or end 106 * @param new_ih new target 107 */ 108 @Override 109 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { 110 boolean targeted = false; 111 if (start_pc == old_ih) { 112 targeted = true; 113 setStartPC(new_ih); 114 } 115 if (end_pc == old_ih) { 116 targeted = true; 117 setEndPC(new_ih); 118 } 119 if (handler_pc == old_ih) { 120 targeted = true; 121 setHandlerPC(new_ih); 122 } 123 if (!targeted) { 124 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", " 125 + end_pc + ", " + handler_pc + "}"); 126 } 127 } 128 129 130 /** 131 * @return true, if ih is target of this handler 132 */ 133 @Override 134 public boolean containsTarget( final InstructionHandle ih ) { 135 return (start_pc == ih) || (end_pc == ih) || (handler_pc == ih); 136 } 137 138 139 /** Sets the type of the Exception to catch. Set 'null' for ANY. */ 140 public void setCatchType( final ObjectType catch_type ) { 141 this.catch_type = catch_type; 142 } 143 144 145 /** Gets the type of the Exception to catch, 'null' for ANY. */ 146 public ObjectType getCatchType() { 147 return catch_type; 148 } 149 150 151 /** @return start of handled region (inclusive) 152 */ 153 public InstructionHandle getStartPC() { 154 return start_pc; 155 } 156 157 158 /** @return end of handled region (inclusive) 159 */ 160 public InstructionHandle getEndPC() { 161 return end_pc; 162 } 163 164 165 /** @return start of handler 166 */ 167 public InstructionHandle getHandlerPC() { 168 return handler_pc; 169 } 170 171 172 @Override 173 public String toString() { 174 return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")"; 175 } 176 177 178 @Override 179 public Object clone() { 180 try { 181 return super.clone(); 182 } catch (final CloneNotSupportedException e) { 183 throw new Error("Clone Not Supported"); // never happens 184 } 185 } 186}