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