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.ia32; 014 015 import org.jikesrvm.ArchitectureSpecific; 016 import org.jikesrvm.VM; 017 import org.jikesrvm.Constants; 018 import org.jikesrvm.ArchitectureSpecific.Registers; 019 import org.jikesrvm.compilers.common.CompiledMethod; 020 import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod; 021 import org.jikesrvm.runtime.ExceptionDeliverer; 022 import org.jikesrvm.runtime.Magic; 023 import org.jikesrvm.scheduler.RVMThread; 024 import org.vmmagic.pragma.Unpreemptible; 025 import org.vmmagic.unboxed.Address; 026 import org.vmmagic.unboxed.Offset; 027 028 /** 029 * Handle exception delivery and stack unwinding for methods 030 * compiled by optimizing Compiler. 031 */ 032 public abstract class OptExceptionDeliverer extends ExceptionDeliverer 033 implements ArchitectureSpecific.ArchConstants { 034 035 private static final boolean TRACE = false; 036 037 /** 038 * Pass control to a catch block. 039 */ 040 @Override 041 @Unpreemptible("Deliver exception possibly from unpreemptible code") 042 public void deliverException(CompiledMethod compiledMethod, Address catchBlockInstructionAddress, 043 Throwable exceptionObject, Registers registers) { 044 OptCompiledMethod optMethod = (OptCompiledMethod) compiledMethod; 045 Address fp = registers.getInnermostFramePointer(); 046 RVMThread myThread = RVMThread.getCurrentThread(); 047 048 if (TRACE) { 049 VM.sysWrite("Frame size of "); 050 VM.sysWrite(optMethod.getMethod()); 051 VM.sysWrite(" is "); 052 VM.sysWrite(optMethod.getFrameFixedSize()); 053 VM.sysWrite("\n"); 054 } 055 056 // reset sp to "empty params" state (ie same as it was after prologue) 057 Address sp = fp.minus(optMethod.getFrameFixedSize()); 058 registers.gprs.set(STACK_POINTER.value(), sp.toWord()); 059 060 // store exception object for later retrieval by catch block 061 int offset = optMethod.getUnsignedExceptionOffset(); 062 if (offset != 0) { 063 // only put the exception object in the stackframe if the catch block is expecting it. 064 // (if the method hasn't allocated a stack slot for caught exceptions, then we can safely 065 // drop the exceptionObject on the floor). 066 Magic.setObjectAtOffset(Magic.addressAsObject(fp), Offset.fromIntSignExtend(-offset), exceptionObject); 067 if (TRACE) { 068 VM.sysWrite("Storing exception object "); 069 VM.sysWrite(Magic.objectAsAddress(exceptionObject)); 070 VM.sysWrite(" at offset "); 071 VM.sysWrite(offset); 072 VM.sysWrite(" from framepoint "); 073 VM.sysWrite(fp); 074 VM.sysWrite("\n"); 075 } 076 } 077 078 if (TRACE) { 079 VM.sysWrite("Registers before delivering exception in "); 080 VM.sysWrite(optMethod.getMethod()); 081 VM.sysWrite("\n"); 082 for (GPR reg : GPR.values()) { 083 VM.sysWrite(reg.toString()); 084 VM.sysWrite(" = "); 085 VM.sysWrite(registers.gprs.get(reg.value())); 086 VM.sysWrite("\n"); 087 } 088 } 089 090 // set address at which to resume executing frame 091 registers.ip = catchBlockInstructionAddress; 092 093 if (TRACE) { 094 VM.sysWrite("Set ip to "); 095 VM.sysWrite(registers.ip); 096 VM.sysWrite("\n"); 097 } 098 099 VM.enableGC(); // disabled right before RuntimeEntrypoints.deliverException was called 100 101 if (VM.VerifyAssertions) VM._assert(registers.inuse); 102 registers.inuse = false; 103 104 // 'give back' the portion of the stack we borrowed to run 105 // exception delivery code when invoked for a hardware trap. 106 // If this was a straight software trap (athrow) then setting 107 // the stacklimit should be harmless, since the stacklimit should already have exactly 108 // the value we are setting it too. 109 myThread.stackLimit = Magic.objectAsAddress(myThread.getStack()).plus(STACK_SIZE_GUARD); 110 111 // "branches" to catchBlockInstructionAddress 112 Magic.restoreHardwareExceptionState(registers); 113 if (VM.VerifyAssertions) VM._assert(Constants.NOT_REACHED); 114 } 115 116 /** 117 * Unwind a stackframe. 118 */ 119 @Override 120 @Unpreemptible("Unwind stack possibly from unpreemptible code") 121 public void unwindStackFrame(CompiledMethod compiledMethod, Registers registers) { 122 Address fp = registers.getInnermostFramePointer(); 123 OptCompiledMethod optMethod = (OptCompiledMethod) compiledMethod; 124 125 if (TRACE) { 126 VM.sysWrite("Registers before unwinding frame for "); 127 VM.sysWrite(optMethod.getMethod()); 128 VM.sysWrite("\n"); 129 for (GPR reg : GPR.values()) { 130 VM.sysWrite(reg.toString()); 131 VM.sysWrite(" = "); 132 VM.sysWrite(registers.gprs.get(reg.value())); 133 VM.sysWrite("\n"); 134 } 135 } 136 137 // restore non-volatile registers 138 int frameOffset = optMethod.getUnsignedNonVolatileOffset(); 139 for (int i = optMethod.getFirstNonVolatileGPR(); i < NUM_NONVOLATILE_GPRS; i++, frameOffset += 4) { 140 registers.gprs.set(NONVOLATILE_GPRS[i].value(), fp.minus(frameOffset).loadWord()); 141 } 142 if (VM.VerifyAssertions) VM._assert(NUM_NONVOLATILE_FPRS == 0); 143 144 registers.unwindStackFrame(); 145 146 if (TRACE) { 147 VM.sysWrite("Registers after unwinding frame for "); 148 VM.sysWrite(optMethod.getMethod()); 149 VM.sysWrite("\n"); 150 for (GPR reg : GPR.values()) { 151 VM.sysWrite(reg.toString()); 152 VM.sysWrite(" = "); 153 VM.sysWrite(registers.gprs.get(reg.value())); 154 VM.sysWrite("\n"); 155 } 156 } 157 } 158 }