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}