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    }