/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* 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/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.compilers.opt.runtimesupport.ppc;
import static org.jikesrvm.VM.NOT_REACHED;
import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_DOUBLE;
import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
import org.jikesrvm.VM;
import org.jikesrvm.architecture.AbstractRegisters;
import org.jikesrvm.compilers.common.CompiledMethod;
import org.jikesrvm.compilers.opt.runtimesupport.OptCompiledMethod;
import org.jikesrvm.runtime.ExceptionDeliverer;
import org.jikesrvm.runtime.Magic;
import org.vmmagic.pragma.Unpreemptible;
import org.vmmagic.unboxed.Address;
import org.vmmagic.unboxed.Offset;
import org.vmmagic.unboxed.Word;
/**
* Handle exception delivery and stack unwinding for
* opt compiled methods.
*/
public final class OptExceptionDeliverer extends ExceptionDeliverer {
/**
* Pass control to a catch block.
*/
@Override
@Unpreemptible("Deliver exception possibly from unpreemptible code")
public void deliverException(CompiledMethod cm, Address catchBlockInstructionAddress, Throwable exceptionObject,
AbstractRegisters registers) {
// store exception object for later retrieval by catch block
OptCompiledMethod compiledMethod = (OptCompiledMethod) cm;
Offset offset = Offset.fromIntSignExtend(compiledMethod.getUnsignedExceptionOffset());
if (!offset.isZero()) {
// 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).
Address fp = registers.getInnermostFramePointer();
Magic.setObjectAtOffset(Magic.addressAsObject(fp), offset, exceptionObject);
}
// set address at which to resume executing frame
registers.setIP(catchBlockInstructionAddress);
VM.enableGC(); // disabled right before Runtime.deliverException was called
if (VM.VerifyAssertions) VM._assert(registers.getInUse());
registers.setInUse(false);
// "branches" to catchBlockInstructionAddress
Magic.restoreHardwareExceptionState(registers);
if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
}
/**
* Unwind a stackframe.
*/
@Override
@Unpreemptible("Deliver exception possibly from unpreemptible code")
public void unwindStackFrame(CompiledMethod cm, AbstractRegisters registers) {
Address fp = registers.getInnermostFramePointer();
OptCompiledMethod compiledMethod = (OptCompiledMethod) cm;
// restore non-volatile registers
Offset frameOffset = Offset.fromIntSignExtend(compiledMethod.getUnsignedNonVolatileOffset());
int firstInteger = compiledMethod.getFirstNonVolatileGPR();
if (firstInteger >= 0) {
if (VM.BuildFor64Addr) {
frameOffset = frameOffset.plus(7).toWord().and(Word.fromIntSignExtend(~7)).toOffset();
}
for (int i = firstInteger; i < 32; i++) {
registers.getGPRs().set(i, fp.loadWord(frameOffset));
frameOffset = frameOffset.plus(BYTES_IN_ADDRESS);
}
}
int firstFloat = compiledMethod.getFirstNonVolatileFPR();
if (firstFloat >= 0) {
frameOffset = frameOffset.plus(7).toWord().and(Word.fromIntSignExtend(~7)).toOffset();
for (int i = firstFloat; i < 32; i++) {
long temp = Magic.getLongAtOffset(Magic.addressAsObject(fp), frameOffset);
registers.getFPRs()[i] = Magic.longBitsAsDouble(temp);
frameOffset = frameOffset.plus(BYTES_IN_DOUBLE);
}
}
registers.unwindStackFrame();
}
}