001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm.compilers.opt.runtimesupport; 014 015 import java.util.Enumeration; 016 017 import org.jikesrvm.VM; 018 import org.jikesrvm.compilers.common.ExceptionTable; 019 import org.jikesrvm.compilers.opt.ir.BasicBlock; 020 import org.jikesrvm.compilers.opt.ir.ExceptionHandlerBasicBlock; 021 import org.jikesrvm.compilers.opt.ir.IR; 022 import org.jikesrvm.compilers.opt.ir.operand.TypeOperand; 023 024 /** 025 * Encoding of try ranges in the final machinecode and the 026 * corresponding exception type and catch block start. 027 */ 028 final class OptExceptionTable extends ExceptionTable { 029 030 /** 031 * Encode an exception table 032 * @param ir the IR to encode the exception table for 033 * @return the encoded exception table 034 */ 035 static int[] encode(IR ir) { 036 int index = 0; 037 int currStartOff, currEndOff; 038 int tableSize = countExceptionTableSize(ir); 039 int[] eTable = new int[tableSize * 4]; 040 041 // For each basic block 042 // See if it has code associated with it and if it has 043 // any reachable exception handlers. 044 // When such a block is found, check the blocks that follow 045 // it in code order to see if this block has the same 046 // Bag of exceptionHandlers as any of its immediate successors. 047 // If so the try region can be expanded to include those 048 // successors. Stop checking successors as soon as a non-match 049 // is found, or a block that doesn't have handlers is found. 050 // Successors that don't have any code associated with them can 051 // be ignored. 052 // If blocks were joined together then when adding the 053 // entries to the eTable it is important to not restrict the 054 // entries to reachable handlers; as the first block may only 055 // throw a subset of the exception types represented by the Bag 056 for (BasicBlock bblock = ir.firstBasicBlockInCodeOrder(); bblock != null;) { 057 // Iteration is explicit in loop 058 059 int startOff = bblock.firstInstruction().getmcOffset(); 060 int endOff = bblock.lastInstruction().getmcOffset(); 061 if (endOff > startOff) { 062 if (!bblock.hasExceptionHandlers()) { 063 bblock = bblock.nextBasicBlockInCodeOrder(); 064 continue; 065 } 066 067 BasicBlock followonBB; 068 Enumeration<BasicBlock> reachBBe, e; 069 boolean joinedBlocks; 070 071 // First make sure at least one of the exception handlers 072 // is reachable from this block 073 reachBBe = bblock.getReachableExceptionHandlers(); 074 if (!reachBBe.hasMoreElements()) { 075 bblock = bblock.nextBasicBlockInCodeOrder(); 076 continue; 077 } 078 079 currStartOff = startOff; 080 currEndOff = endOff; 081 joinedBlocks = false; 082 083 for (followonBB = bblock.nextBasicBlockInCodeOrder(); followonBB != null; followonBB = 084 followonBB.nextBasicBlockInCodeOrder()) { 085 int fStartOff = followonBB.firstInstruction().getmcOffset(); 086 int fEndOff = followonBB.lastInstruction().getmcOffset(); 087 // See if followon Block has any code 088 if (fEndOff > fStartOff) { 089 // See if followon Block has matching handler block bag 090 if (followonBB.hasExceptionHandlers() && bblock.isExceptionHandlerEquivalent(followonBB)) { 091 currEndOff = fEndOff; 092 joinedBlocks = true; 093 } else { 094 // Can't join any more blocks together 095 break; 096 } 097 } 098 } 099 // found all the matching followon blocks 100 // Now fill in the eTable with the handlers 101 if (joinedBlocks) { 102 e = bblock.getExceptionHandlers(); 103 } else { 104 e = reachBBe; 105 } 106 107 while (e.hasMoreElements()) { 108 ExceptionHandlerBasicBlock eBlock = (ExceptionHandlerBasicBlock) e.nextElement(); 109 for (java.util.Enumeration<TypeOperand> ets = eBlock.getExceptionTypes(); ets.hasMoreElements();) { 110 TypeOperand type = ets.nextElement(); 111 int catchOffset = eBlock.firstInstruction().getmcOffset(); 112 eTable[index + TRY_START] = currStartOff; 113 eTable[index + TRY_END] = currEndOff; 114 eTable[index + CATCH_START] = catchOffset; 115 try { 116 eTable[index + EX_TYPE] = type.getTypeRef().resolve().getId(); 117 } catch (NoClassDefFoundError except) { 118 // Yuck. If this happens beatup Dave and make him do the right 119 // thing. For now, we are forcing early loading of exception 120 // types to avoid a bunch of ugly issues in resolving the type 121 // when delivering the exception. The problem is that we 122 // currently can't allow a GC while in the midst of delivering 123 // an exception and resolving the type reference might entail 124 // calling arbitrary classloader code. 125 VM.sysWriteln("Trouble resolving a caught exception at compile time:"); 126 except.printStackTrace(); // sysFail won't print the stack trace 127 // that lead to the 128 // NoClassDefFoundError. 129 VM.sysFail("Unable to resolve caught exception type at compile time"); 130 } 131 index += 4; 132 } 133 } 134 bblock = followonBB; 135 } else { 136 // No code in bblock 137 bblock = bblock.nextBasicBlockInCodeOrder(); 138 } 139 } 140 141 if (index != eTable.length) { // resize array 142 int[] newETable = new int[index]; 143 for (int i = 0; i < index; i++) { 144 newETable[i] = eTable[i]; 145 } 146 eTable = newETable; 147 } 148 return eTable; 149 } 150 151 /** 152 * Return an upper bounds on the size of the exception table for an IR. 153 */ 154 private static int countExceptionTableSize(IR ir) { 155 int tSize = 0; 156 for (BasicBlock bblock = ir.firstBasicBlockInCodeOrder(); bblock != null; bblock = 157 bblock.nextBasicBlockInCodeOrder()) { 158 if (bblock.hasExceptionHandlers()) { 159 for (Enumeration<BasicBlock> e = bblock.getExceptionHandlers(); e.hasMoreElements();) { 160 ExceptionHandlerBasicBlock ebb = (ExceptionHandlerBasicBlock) e.nextElement(); 161 tSize += ebb.getNumberOfExceptionTableEntries(); 162 } 163 } 164 } 165 return tSize; 166 } 167 } 168 169 170