1 // ASM: a very small and fast Java bytecode manipulation framework 2 // Copyright (c) 2000-2011 INRIA, France Telecom 3 // All rights reserved. 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions 7 // are met: 8 // 1. Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // 2. Redistributions in binary form must reproduce the above copyright 11 // notice, this list of conditions and the following disclaimer in the 12 // documentation and/or other materials provided with the distribution. 13 // 3. Neither the name of the copyright holders nor the names of its 14 // contributors may be used to endorse or promote products derived from 15 // this software without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 // THE POSSIBILITY OF SUCH DAMAGE. 28 package org.objectweb.asm; 29 30 /** 31 * Information about an exception handler. Corresponds to an element of the exception_table array of 32 * a Code attribute, as defined in the Java Virtual Machine Specification (JVMS). Handler instances 33 * can be chained together, with their {@link #nextHandler} field, to describe a full JVMS 34 * exception_table array. 35 * 36 * @see <a href="https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html#jvms-4.7.3">JVMS 37 * 4.7.3</a> 38 * @author Eric Bruneton 39 */ 40 final class Handler { 41 42 /** 43 * The start_pc field of this JVMS exception_table entry. Corresponds to the beginning of the 44 * exception handler's scope (inclusive). 45 */ 46 final Label startPc; 47 48 /** 49 * The end_pc field of this JVMS exception_table entry. Corresponds to the end of the exception 50 * handler's scope (exclusive). 51 */ 52 final Label endPc; 53 54 /** 55 * The handler_pc field of this JVMS exception_table entry. Corresponding to the beginning of the 56 * exception handler's code. 57 */ 58 final Label handlerPc; 59 60 /** 61 * The catch_type field of this JVMS exception_table entry. This is the constant pool index of the 62 * internal name of the type of exceptions handled by this handler, or 0 to catch any exceptions. 63 */ 64 final int catchType; 65 66 /** 67 * The internal name of the type of exceptions handled by this handler, or {@literal null} to 68 * catch any exceptions. 69 */ 70 final String catchTypeDescriptor; 71 72 /** The next exception handler. */ 73 Handler nextHandler; 74 75 /** 76 * Constructs a new Handler. 77 * 78 * @param startPc the start_pc field of this JVMS exception_table entry. 79 * @param endPc the end_pc field of this JVMS exception_table entry. 80 * @param handlerPc the handler_pc field of this JVMS exception_table entry. 81 * @param catchType The catch_type field of this JVMS exception_table entry. 82 * @param catchTypeDescriptor The internal name of the type of exceptions handled by this handler, 83 * or {@literal null} to catch any exceptions. 84 */ Handler( final Label startPc, final Label endPc, final Label handlerPc, final int catchType, final String catchTypeDescriptor)85 Handler( 86 final Label startPc, 87 final Label endPc, 88 final Label handlerPc, 89 final int catchType, 90 final String catchTypeDescriptor) { 91 this.startPc = startPc; 92 this.endPc = endPc; 93 this.handlerPc = handlerPc; 94 this.catchType = catchType; 95 this.catchTypeDescriptor = catchTypeDescriptor; 96 } 97 98 /** 99 * Constructs a new Handler from the given one, with a different scope. 100 * 101 * @param handler an existing Handler. 102 * @param startPc the start_pc field of this JVMS exception_table entry. 103 * @param endPc the end_pc field of this JVMS exception_table entry. 104 */ Handler(final Handler handler, final Label startPc, final Label endPc)105 Handler(final Handler handler, final Label startPc, final Label endPc) { 106 this(startPc, endPc, handler.handlerPc, handler.catchType, handler.catchTypeDescriptor); 107 this.nextHandler = handler.nextHandler; 108 } 109 110 /** 111 * Removes the range between start and end from the Handler list that begins with the given 112 * element. 113 * 114 * @param firstHandler the beginning of a Handler list. May be {@literal null}. 115 * @param start the start of the range to be removed. 116 * @param end the end of the range to be removed. Maybe {@literal null}. 117 * @return the exception handler list with the start-end range removed. 118 */ removeRange(final Handler firstHandler, final Label start, final Label end)119 static Handler removeRange(final Handler firstHandler, final Label start, final Label end) { 120 if (firstHandler == null) { 121 return null; 122 } else { 123 firstHandler.nextHandler = removeRange(firstHandler.nextHandler, start, end); 124 } 125 int handlerStart = firstHandler.startPc.bytecodeOffset; 126 int handlerEnd = firstHandler.endPc.bytecodeOffset; 127 int rangeStart = start.bytecodeOffset; 128 int rangeEnd = end == null ? Integer.MAX_VALUE : end.bytecodeOffset; 129 // Return early if [handlerStart,handlerEnd[ and [rangeStart,rangeEnd[ don't intersect. 130 if (rangeStart >= handlerEnd || rangeEnd <= handlerStart) { 131 return firstHandler; 132 } 133 if (rangeStart <= handlerStart) { 134 if (rangeEnd >= handlerEnd) { 135 // If [handlerStart,handlerEnd[ is included in [rangeStart,rangeEnd[, remove firstHandler. 136 return firstHandler.nextHandler; 137 } else { 138 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [rangeEnd,handlerEnd[ 139 return new Handler(firstHandler, end, firstHandler.endPc); 140 } 141 } else if (rangeEnd >= handlerEnd) { 142 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = [handlerStart,rangeStart[ 143 return new Handler(firstHandler, firstHandler.startPc, start); 144 } else { 145 // [handlerStart,handlerEnd[ - [rangeStart,rangeEnd[ = 146 // [handlerStart,rangeStart[ + [rangeEnd,handerEnd[ 147 firstHandler.nextHandler = new Handler(firstHandler, end, firstHandler.endPc); 148 return new Handler(firstHandler, firstHandler.startPc, start); 149 } 150 } 151 152 /** 153 * Returns the number of elements of the Handler list that begins with the given element. 154 * 155 * @param firstHandler the beginning of a Handler list. May be {@literal null}. 156 * @return the number of elements of the Handler list that begins with 'handler'. 157 */ getExceptionTableLength(final Handler firstHandler)158 static int getExceptionTableLength(final Handler firstHandler) { 159 int length = 0; 160 Handler handler = firstHandler; 161 while (handler != null) { 162 length++; 163 handler = handler.nextHandler; 164 } 165 return length; 166 } 167 168 /** 169 * Returns the size in bytes of the JVMS exception_table corresponding to the Handler list that 170 * begins with the given element. <i>This includes the exception_table_length field.</i> 171 * 172 * @param firstHandler the beginning of a Handler list. May be {@literal null}. 173 * @return the size in bytes of the exception_table_length and exception_table structures. 174 */ getExceptionTableSize(final Handler firstHandler)175 static int getExceptionTableSize(final Handler firstHandler) { 176 return 2 + 8 * getExceptionTableLength(firstHandler); 177 } 178 179 /** 180 * Puts the JVMS exception_table corresponding to the Handler list that begins with the given 181 * element. <i>This includes the exception_table_length field.</i> 182 * 183 * @param firstHandler the beginning of a Handler list. May be {@literal null}. 184 * @param output where the exception_table_length and exception_table structures must be put. 185 */ putExceptionTable(final Handler firstHandler, final ByteVector output)186 static void putExceptionTable(final Handler firstHandler, final ByteVector output) { 187 output.putShort(getExceptionTableLength(firstHandler)); 188 Handler handler = firstHandler; 189 while (handler != null) { 190 output 191 .putShort(handler.startPc.bytecodeOffset) 192 .putShort(handler.endPc.bytecodeOffset) 193 .putShort(handler.handlerPc.bytecodeOffset) 194 .putShort(handler.catchType); 195 handler = handler.nextHandler; 196 } 197 } 198 } 199