1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/* 2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2008 The Android Open Source Project 3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License. 6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at 7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and 14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License. 15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.code; 18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.BasicBlock; 20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.BasicBlockList; 21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.code.RopMethod; 22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.cst.CstType; 23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.Type; 24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.rop.type.TypeList; 25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.IntList; 26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.ArrayList; 28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.HashSet; 29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/** 31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Constructor of {@link CatchTable} instances from {@link RopMethod} 32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * and associated data. 33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class StdCatchBuilder implements CatchBuilder { 35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** the maximum range of a single catch handler, in code units */ 36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static final int MAX_CATCH_RANGE = 65535; 37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@code non-null;} method to build the list for */ 39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final RopMethod method; 40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@code non-null;} block output order */ 42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final int[] order; 43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@code non-null;} address objects for each block */ 45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final BlockAddresses addresses; 46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Constructs an instance. It merely holds onto its parameters for 49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * a subsequent call to {@link #build}. 50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param method {@code non-null;} method to build the list for 52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param order {@code non-null;} block output order 53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param addresses {@code non-null;} address objects for each block 54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public StdCatchBuilder(RopMethod method, int[] order, 56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BlockAddresses addresses) { 57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (method == null) { 58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("method == null"); 59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (order == null) { 62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("order == null"); 63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (addresses == null) { 66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("addresses == null"); 67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson this.method = method; 70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson this.order = order; 71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson this.addresses = addresses; 72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public CatchTable build() { 76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return build(method, order, addresses); 77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public boolean hasAnyCatches() { 81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlockList blocks = method.getBlocks(); 82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int size = blocks.size(); 83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < size; i++) { 85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock block = blocks.get(i); 86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson TypeList catches = block.getLastInsn().getCatches(); 87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (catches.size() != 0) { 88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return true; 89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return false; 93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public HashSet<Type> getCatchTypes() { 97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson HashSet<Type> result = new HashSet<Type>(20); 98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlockList blocks = method.getBlocks(); 99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int size = blocks.size(); 100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < size; i++) { 102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock block = blocks.get(i); 103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson TypeList catches = block.getLastInsn().getCatches(); 104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int catchSize = catches.size(); 105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int j = 0; j < catchSize; j++) { 107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result.add(catches.getType(j)); 108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return result; 112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Builds and returns the catch table for a given method. 116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param method {@code non-null;} method to build the list for 118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param order {@code non-null;} block output order 119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param addresses {@code non-null;} address objects for each block 120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code non-null;} the constructed table 121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public static CatchTable build(RopMethod method, int[] order, 123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BlockAddresses addresses) { 124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int len = order.length; 125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlockList blocks = method.getBlocks(); 126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ArrayList<CatchTable.Entry> resultList = 127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson new ArrayList<CatchTable.Entry>(len); 128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchHandlerList currentHandlers = CatchHandlerList.EMPTY; 129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock currentStartBlock = null; 130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock currentEndBlock = null; 131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < len; i++) { 133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock block = blocks.labelToBlock(order[i]); 134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (!block.canThrow()) { 136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * There is no need to concern ourselves with the 138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * placement of blocks that can't throw with respect 139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * to the blocks that *can* throw. 140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchHandlerList handlers = handlersFor(block, addresses); 145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (currentHandlers.size() == 0) { 147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // This is the start of a new catch range. 148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentStartBlock = block; 149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentEndBlock = block; 150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentHandlers = handlers; 151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (currentHandlers.equals(handlers) 155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson && rangeIsValid(currentStartBlock, block, addresses)) { 156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * The block we are looking at now has the same handlers 158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * as the block that started the currently open catch 159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * range, and adding it to the currently open range won't 160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * cause it to be too long. 161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentEndBlock = block; 163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson continue; 164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * The block we are looking at now has incompatible handlers, 168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * so we need to finish off the last entry and start a new 169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * one. Note: We only emit an entry if it has associated handlers. 170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (currentHandlers.size() != 0) { 172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchTable.Entry entry = 173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson makeEntry(currentStartBlock, currentEndBlock, 174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentHandlers, addresses); 175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson resultList.add(entry); 176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentStartBlock = block; 179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentEndBlock = block; 180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentHandlers = handlers; 181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (currentHandlers.size() != 0) { 184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Emit an entry for the range that was left hanging. 185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchTable.Entry entry = 186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson makeEntry(currentStartBlock, currentEndBlock, 187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson currentHandlers, addresses); 188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson resultList.add(entry); 189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Construct the final result. 192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int resultSz = resultList.size(); 194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (resultSz == 0) { 196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return CatchTable.EMPTY; 197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchTable result = new CatchTable(resultSz); 200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < resultSz; i++) { 202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result.set(i, resultList.get(i)); 203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result.setImmutable(); 206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return result; 207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Makes the {@link CatchHandlerList} for the given basic block. 211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param block {@code non-null;} block to get entries for 213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param addresses {@code non-null;} address objects for each block 214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code non-null;} array of entries 215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static CatchHandlerList handlersFor(BasicBlock block, 217579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BlockAddresses addresses) { 218579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson IntList successors = block.getSuccessors(); 219579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int succSize = successors.size(); 220579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int primary = block.getPrimarySuccessor(); 221579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson TypeList catches = block.getLastInsn().getCatches(); 222579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int catchSize = catches.size(); 223579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 224579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (catchSize == 0) { 225579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return CatchHandlerList.EMPTY; 226579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 227579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 228579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (((primary == -1) && (succSize != catchSize)) 229579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson || ((primary != -1) && 230579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson ((succSize != (catchSize + 1)) 231579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson || (primary != successors.get(catchSize))))) { 232579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 233579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Blocks that throw are supposed to list their primary 234579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * successor -- if any -- last in the successors list, but 235579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * that constraint appears to be violated here. 236579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 237579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new RuntimeException( 238579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson "shouldn't happen: weird successors list"); 239579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 240579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 241579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 242579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Reduce the effective catchSize if we spot a catch-all that 243579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * isn't at the end. 244579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 245579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < catchSize; i++) { 246579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson Type type = catches.getType(i); 247579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (type.equals(Type.OBJECT)) { 248579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson catchSize = i + 1; 249579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson break; 250579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 251579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 252579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 253579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CatchHandlerList result = new CatchHandlerList(catchSize); 254579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 255579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (int i = 0; i < catchSize; i++) { 256579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CstType oneType = new CstType(catches.getType(i)); 257579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CodeAddress oneHandler = addresses.getStart(successors.get(i)); 258579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result.set(i, oneType, oneHandler.getAddress()); 259579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 260579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 261579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson result.setImmutable(); 262579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return result; 263579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 264579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 265579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 266579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Makes a {@link CatchTable#Entry} for the given block range and 267579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * handlers. 268579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 269579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param start {@code non-null;} the start block for the range (inclusive) 270579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param end {@code non-null;} the start block for the range (also inclusive) 271579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param handlers {@code non-null;} the handlers for the range 272579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param addresses {@code non-null;} address objects for each block 273579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 274579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static CatchTable.Entry makeEntry(BasicBlock start, 275579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BasicBlock end, CatchHandlerList handlers, 276579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BlockAddresses addresses) { 277579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 278579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * We start at the *last* instruction of the start block, since 279579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * that's the instruction that can throw... 280579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 281579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CodeAddress startAddress = addresses.getLast(start); 282579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 283579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // ...And we end *after* the last instruction of the end block. 284579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson CodeAddress endAddress = addresses.getEnd(end); 285579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 286579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return new CatchTable.Entry(startAddress.getAddress(), 287579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson endAddress.getAddress(), handlers); 288579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 289579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 290579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 291579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Gets whether the address range for the given two blocks is valid 292579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * for a catch handler. This is true as long as the covered range is 293579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * under 65536 code units. 294579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 295579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param start {@code non-null;} the start block for the range (inclusive) 296579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param end {@code non-null;} the start block for the range (also inclusive) 297579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param addresses {@code non-null;} address objects for each block 298579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code true} if the range is valid as a catch range 299579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 300579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static boolean rangeIsValid(BasicBlock start, BasicBlock end, 301579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson BlockAddresses addresses) { 302579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (start == null) { 303579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("start == null"); 304579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 305579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 306579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (end == null) { 307579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("end == null"); 308579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 309579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 310579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // See above about selection of instructions. 311579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int startAddress = addresses.getLast(start).getAddress(); 312579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int endAddress = addresses.getEnd(end).getAddress(); 313579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 314579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return (endAddress - startAddress) <= MAX_CATCH_RANGE; 315579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 316579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson} 317