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    }