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