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 @Override 080 @Unpreemptible("Unwind stack possibly from unpreemptible code") 081 public void unwindStackFrame(CompiledMethod compiledMethod, ArchitectureSpecific.Registers registers) { 082 NormalMethod method = (NormalMethod) compiledMethod.getMethod(); 083 Address fp = registers.getInnermostFramePointer(); 084 if (method.isSynchronized()) { // release the lock, if it is being held 085 Address ip = registers.getInnermostInstructionAddress(); 086 Offset instr = compiledMethod.getInstructionOffset(ip); 087 Offset lockOffset = ((BaselineCompiledMethod) compiledMethod).getLockAcquisitionOffset(); 088 if (instr.sGT(lockOffset)) { // we actually have the lock, so must unlock it. 089 Object lock; 090 if (method.isStatic()) { 091 lock = method.getDeclaringClass().getResolvedClassForType(); 092 } else { 093 lock = 094 Magic.addressAsObject(fp.plus(BaselineCompilerImpl.locationToOffset(((BaselineCompiledMethod) compiledMethod).getGeneralLocalLocation( 095 0)) - BYTES_IN_ADDRESS).loadAddress()); 096 } 097 if (ObjectModel.holdsLock(lock, RVMThread.getCurrentThread())) { 098 ObjectModel.genericUnlock(lock); 099 } 100 } 101 } 102 // Restore nonvolatile registers used by the baseline compiler. 103 if (VM.VerifyAssertions) VM._assert(SAVED_GPRS == 2); 104 registers.gprs.set(EDI.value(), fp.plus(EDI_SAVE_OFFSET).loadWord()); 105 registers.gprs.set(EBX.value(), fp.plus(EBX_SAVE_OFFSET).loadWord()); 106 if (method.hasBaselineSaveLSRegistersAnnotation()) { 107 registers.gprs.set(EBP.value(), fp.plus(EBP_SAVE_OFFSET).toWord()); 108 } 109 110 registers.unwindStackFrame(); 111 } 112 } 113 114