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