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 * @version $Id: CodeExceptionGen.java 1806200 2017-08-25 16:33:06Z ggregory $ 032 * @see MethodGen 033 * @see CodeException 034 * @see InstructionHandle 035 */ 036public final class CodeExceptionGen implements InstructionTargeter, Cloneable { 037 038 private InstructionHandle start_pc; 039 private InstructionHandle end_pc; 040 private InstructionHandle handler_pc; 041 private ObjectType catch_type; 042 043 044 /** 045 * Add an exception handler, i.e., specify region where a handler is active and an 046 * instruction where the actual handling is done. 047 * 048 * @param start_pc Start of handled region (inclusive) 049 * @param end_pc End of handled region (inclusive) 050 * @param handler_pc Where handling is done 051 * @param catch_type which exception is handled, null for ANY 052 */ 053 public CodeExceptionGen(final InstructionHandle start_pc, final InstructionHandle end_pc, 054 final InstructionHandle handler_pc, final ObjectType catch_type) { 055 setStartPC(start_pc); 056 setEndPC(end_pc); 057 setHandlerPC(handler_pc); 058 this.catch_type = catch_type; 059 } 060 061 062 /** 063 * Get CodeException object.<BR> 064 * 065 * This relies on that the instruction list has already been dumped 066 * to byte code or or that the `setPositions' methods has been 067 * called for the instruction list. 068 * 069 * @param cp constant pool 070 */ 071 public CodeException getCodeException( final ConstantPoolGen cp ) { 072 return new CodeException(start_pc.getPosition(), end_pc.getPosition() 073 + end_pc.getInstruction().getLength(), handler_pc.getPosition(), 074 (catch_type == null) ? 0 : cp.addClass(catch_type)); 075 } 076 077 078 /* Set start of handler 079 * @param start_pc Start of handled region (inclusive) 080 */ 081 public void setStartPC( final InstructionHandle start_pc ) { // TODO could be package-protected? 082 BranchInstruction.notifyTarget(this.start_pc, start_pc, this); 083 this.start_pc = start_pc; 084 } 085 086 087 /* Set end of handler 088 * @param end_pc End of handled region (inclusive) 089 */ 090 public void setEndPC( final InstructionHandle end_pc ) { // TODO could be package-protected? 091 BranchInstruction.notifyTarget(this.end_pc, end_pc, this); 092 this.end_pc = end_pc; 093 } 094 095 096 /* Set handler code 097 * @param handler_pc Start of handler 098 */ 099 public void setHandlerPC( final InstructionHandle handler_pc ) { // TODO could be package-protected? 100 BranchInstruction.notifyTarget(this.handler_pc, handler_pc, this); 101 this.handler_pc = handler_pc; 102 } 103 104 105 /** 106 * @param old_ih old target, either start or end 107 * @param new_ih new target 108 */ 109 @Override 110 public void updateTarget( final InstructionHandle old_ih, final InstructionHandle new_ih ) { 111 boolean targeted = false; 112 if (start_pc == old_ih) { 113 targeted = true; 114 setStartPC(new_ih); 115 } 116 if (end_pc == old_ih) { 117 targeted = true; 118 setEndPC(new_ih); 119 } 120 if (handler_pc == old_ih) { 121 targeted = true; 122 setHandlerPC(new_ih); 123 } 124 if (!targeted) { 125 throw new ClassGenException("Not targeting " + old_ih + ", but {" + start_pc + ", " 126 + end_pc + ", " + handler_pc + "}"); 127 } 128 } 129 130 131 /** 132 * @return true, if ih is target of this handler 133 */ 134 @Override 135 public boolean containsTarget( final InstructionHandle ih ) { 136 return (start_pc == ih) || (end_pc == ih) || (handler_pc == ih); 137 } 138 139 140 /** Sets the type of the Exception to catch. Set 'null' for ANY. */ 141 public void setCatchType( final ObjectType catch_type ) { 142 this.catch_type = catch_type; 143 } 144 145 146 /** Gets the type of the Exception to catch, 'null' for ANY. */ 147 public ObjectType getCatchType() { 148 return catch_type; 149 } 150 151 152 /** @return start of handled region (inclusive) 153 */ 154 public InstructionHandle getStartPC() { 155 return start_pc; 156 } 157 158 159 /** @return end of handled region (inclusive) 160 */ 161 public InstructionHandle getEndPC() { 162 return end_pc; 163 } 164 165 166 /** @return start of handler 167 */ 168 public InstructionHandle getHandlerPC() { 169 return handler_pc; 170 } 171 172 173 @Override 174 public String toString() { 175 return "CodeExceptionGen(" + start_pc + ", " + end_pc + ", " + handler_pc + ")"; 176 } 177 178 179 @Override 180 public Object clone() { 181 try { 182 return super.clone(); 183 } catch (final CloneNotSupportedException e) { 184 throw new Error("Clone Not Supported"); // never happens 185 } 186 } 187}