/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Common Public License (CPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/cpl1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.ia32;
import org.jikesrvm.ArchitectureSpecific;
import org.jikesrvm.VM_Registers;
import org.jikesrvm.VM;
import org.jikesrvm.VM_Constants;
import org.jikesrvm.compilers.common.VM_CompiledMethod;
import org.jikesrvm.compilers.opt.VM_OptCompiledMethod;
import org.jikesrvm.runtime.VM_ExceptionDeliverer;
import org.jikesrvm.runtime.VM_Magic;
import org.jikesrvm.scheduler.VM_Processor;
import org.jikesrvm.scheduler.VM_Scheduler;
import org.jikesrvm.scheduler.VM_Thread;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.LocalAddress;
import org.vmmagic.unboxed.Offset;
/**
* Handle exception delivery and stack unwinding for methods
* compiled by optimizing Compiler
*/
public abstract class VM_OptExceptionDeliverer extends VM_ExceptionDeliverer
implements ArchitectureSpecific.VM_ArchConstants {
private static final boolean TRACE = false;
/**
* Pass control to a catch block.
*/
public void deliverException(VM_CompiledMethod compiledMethod, LocalAddress catchBlockInstructionAddress,
Throwable exceptionObject, VM_Registers registers) {
VM_OptCompiledMethod optMethod = (VM_OptCompiledMethod) compiledMethod;
LocalAddress fp = registers.getInnermostFramePointer();
VM_Thread myThread = VM_Scheduler.getCurrentThread();
if (TRACE) {
VM.sysWrite("Frame size of ");
VM.sysWrite(optMethod.getMethod());
VM.sysWrite(" is ");
VM.sysWrite(optMethod.getFrameFixedSize());
VM.sysWrite("\n");
}
// reset sp to "empty params" state (ie same as it was after prologue)
LocalAddress sp = fp.minus(optMethod.getFrameFixedSize());
registers.gprs.set(STACK_POINTER, sp.toWord());
// store exception object for later retrieval by catch block
int offset = optMethod.getUnsignedExceptionOffset();
if (offset != 0) {
// only put the exception object in the stackframe if the catch block is expecting it.
// (if the method hasn't allocated a stack slot for caught exceptions, then we can safely
// drop the exceptionObject on the floor).
VM_Magic.setObjectAtOffset(VM_Magic.localAddressAsObject(fp), Offset.fromIntSignExtend(-offset), exceptionObject);
if (TRACE) {
VM.sysWrite("Storing exception object ");
VM.sysWrite(VM_Magic.objectAsAddress(exceptionObject));
VM.sysWrite(" at offset ");
VM.sysWrite(offset);
VM.sysWrite(" from framepoint ");
VM.sysWrite(fp);
VM.sysWrite("\n");
}
}
if (TRACE) {
VM.sysWrite("Registers before delivering exception in ");
VM.sysWrite(optMethod.getMethod());
VM.sysWrite("\n");
for (int i = 0; i < NUM_GPRS; i++) {
VM.sysWrite(GPR_NAMES[i]);
VM.sysWrite(" = ");
VM.sysWrite(registers.gprs.get(i));
VM.sysWrite("\n");
}
}
// set address at which to resume executing frame
registers.ip = catchBlockInstructionAddress;
if (TRACE) {
VM.sysWrite("Set ip to ");
VM.sysWrite(registers.ip);
VM.sysWrite("\n");
}
VM.enableGC(); // disabled right before VM_Runtime.deliverException was called
if (VM.VerifyAssertions) VM._assert(registers.inuse);
registers.inuse = false;
// 'give back' the portion of the stack we borrowed to run
// exception delivery code when invoked for a hardware trap.
// If this was a straight software trap (athrow) then setting
// the stacklimit should be harmless, since the stacklimit should already have exactly
// the value we are setting it too.
if (!myThread.getHardwareExceptionRegisters().inuse) {
myThread.stackLimit = VM_Magic.objectAsLocalAddress(myThread.getStack()).plus(STACK_SIZE_GUARD);
VM_Processor.getCurrentProcessor().activeThreadStackLimit = myThread.stackLimit;
}
// "branches" to catchBlockInstructionAddress
VM_Magic.restoreHardwareExceptionState(registers);
if (VM.VerifyAssertions) VM._assert(VM_Constants.NOT_REACHED);
}
/**
* Unwind a stackframe.
*/
public void unwindStackFrame(VM_CompiledMethod compiledMethod, VM_Registers registers) {
LocalAddress fp = registers.getInnermostFramePointer();
VM_OptCompiledMethod optMethod = (VM_OptCompiledMethod) compiledMethod;
if (TRACE) {
VM.sysWrite("Registers before unwinding frame for ");
VM.sysWrite(optMethod.getMethod());
VM.sysWrite("\n");
for (int i = 0; i < NUM_GPRS; i++) {
VM.sysWrite(GPR_NAMES[i]);
VM.sysWrite(" = ");
VM.sysWrite(registers.gprs.get(i));
VM.sysWrite("\n");
}
}
// restore non-volatile registers
int frameOffset = optMethod.getUnsignedNonVolatileOffset();
for (int i = optMethod.getFirstNonVolatileGPR(); i < NUM_NONVOLATILE_GPRS; i++, frameOffset += 4) {
registers.gprs.set(NONVOLATILE_GPRS[i], fp.minus(frameOffset).loadWord());
}
if (VM.VerifyAssertions) VM._assert(NUM_NONVOLATILE_FPRS == 0);
registers.unwindStackFrame();
if (TRACE) {
VM.sysWrite("Registers after unwinding frame for ");
VM.sysWrite(optMethod.getMethod());
VM.sysWrite("\n");
for (int i = 0; i < NUM_GPRS; i++) {
VM.sysWrite(GPR_NAMES[i]);
VM.sysWrite(" = ");
VM.sysWrite(registers.gprs.get(i));
VM.sysWrite("\n");
}
}
}
}