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.baseline.ia32;
014
015 import org.jikesrvm.ArchitectureSpecific;
016 import org.jikesrvm.VM;
017 import org.jikesrvm.classloader.NormalMethod;
018 import org.jikesrvm.compilers.baseline.BaselineCompiledMethod;
019 import org.jikesrvm.compilers.common.CompiledMethod;
020 import org.jikesrvm.ia32.BaselineConstants;
021 import org.jikesrvm.objectmodel.ObjectModel;
022 import org.jikesrvm.runtime.ExceptionDeliverer;
023 import org.jikesrvm.runtime.Magic;
024 import org.jikesrvm.scheduler.RVMThread;
025 import org.vmmagic.pragma.Unpreemptible;
026 import org.vmmagic.unboxed.Address;
027 import org.vmmagic.unboxed.Offset;
028
029 /**
030 * Handle exception delivery and stack unwinding for methods compiled by
031 * baseline compiler.
032 */
033 public abstract class BaselineExceptionDeliverer extends ExceptionDeliverer implements BaselineConstants {
034
035 /**
036 * Pass control to a catch block.
037 */
038 @Override
039 @Unpreemptible("Deliver exception possibly from unpreemptible code")
040 public void deliverException(CompiledMethod compiledMethod, Address catchBlockInstructionAddress,
041 Throwable exceptionObject, ArchitectureSpecific.Registers registers) {
042 Address fp = registers.getInnermostFramePointer();
043 NormalMethod method = (NormalMethod) compiledMethod.getMethod();
044 RVMThread myThread = RVMThread.getCurrentThread();
045
046 // reset sp to "empty expression stack" state
047 //
048 Address sp = fp.plus(BaselineCompilerImpl.getEmptyStackOffset(method));
049
050 // push exception object as argument to catch block
051 //
052 sp = sp.minus(BYTES_IN_ADDRESS);
053 sp.store(Magic.objectAsAddress(exceptionObject));
054 registers.gprs.set(SP.value(), sp.toWord());
055
056 // set address at which to resume executing frame
057 registers.ip = catchBlockInstructionAddress;
058
059 // branch to catch block
060 //
061 VM.enableGC(); // disabled right before RuntimeEntrypoints.deliverException was called
062 if (VM.VerifyAssertions) VM._assert(registers.inuse);
063
064 registers.inuse = false;
065
066 // 'give back' the portion of the stack we borrowed to run
067 // exception delivery code when invoked for a hardware trap.
068 // If this was a straight software trap (athrow) then setting
069 // the stacklimit should be harmless, since the stacklimit should already have exactly
070 // the value we are setting it too.
071 myThread.stackLimit = Magic.objectAsAddress(myThread.getStack()).plus(STACK_SIZE_GUARD);
072 Magic.restoreHardwareExceptionState(registers);
073 if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
074 }
075
076 /**
077 * Unwind a stackframe.
078 */
079 @Unpreemptible("Unwind stack possibly from unpreemptible code")
080 public void unwindStackFrame(CompiledMethod compiledMethod, ArchitectureSpecific.Registers registers) {
081 NormalMethod method = (NormalMethod) compiledMethod.getMethod();
082 Address fp = registers.getInnermostFramePointer();
083 if (method.isSynchronized()) { // release the lock, if it is being held
084 Address ip = registers.getInnermostInstructionAddress();
085 Offset instr = compiledMethod.getInstructionOffset(ip);
086 Offset lockOffset = ((BaselineCompiledMethod) compiledMethod).getLockAcquisitionOffset();
087 if (instr.sGT(lockOffset)) { // we actually have the lock, so must unlock it.
088 Object lock;
089 if (method.isStatic()) {
090 lock = method.getDeclaringClass().getResolvedClassForType();
091 } else {
092 lock =
093 Magic.addressAsObject(fp.plus(BaselineCompilerImpl.locationToOffset(((BaselineCompiledMethod) compiledMethod).getGeneralLocalLocation(
094 0)) - BYTES_IN_ADDRESS).loadAddress());
095 }
096 if (ObjectModel.holdsLock(lock, RVMThread.getCurrentThread())) {
097 ObjectModel.genericUnlock(lock);
098 }
099 }
100 }
101 // Restore nonvolatile registers used by the baseline compiler.
102 if (VM.VerifyAssertions) VM._assert(SAVED_GPRS == 2);
103 registers.gprs.set(EDI.value(), fp.plus(EDI_SAVE_OFFSET).loadWord());
104 registers.gprs.set(EBX.value(), fp.plus(EBX_SAVE_OFFSET).loadWord());
105 if (method.hasBaselineSaveLSRegistersAnnotation()) {
106 registers.gprs.set(EBP.value(), fp.plus(EBP_SAVE_OFFSET).toWord());
107 }
108
109 registers.unwindStackFrame();
110 }
111 }
112
113