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