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.jni.ia32; 014 015import static org.jikesrvm.ia32.RegisterConstants.EBP; 016import static org.jikesrvm.ia32.RegisterConstants.EBX; 017import static org.jikesrvm.ia32.RegisterConstants.EDI; 018import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS; 019import static org.jikesrvm.runtime.UnboxedSizeConstants.LOG_BYTES_IN_ADDRESS; 020 021import org.jikesrvm.compilers.common.CompiledMethod; 022import org.jikesrvm.jni.JNIEnvironment; 023import org.jikesrvm.mm.mminterface.GCMapIterator; 024import org.jikesrvm.runtime.Magic; 025import org.jikesrvm.scheduler.RVMThread; 026import org.vmmagic.pragma.Uninterruptible; 027import org.vmmagic.unboxed.Address; 028import org.vmmagic.unboxed.AddressArray; 029import org.vmmagic.unboxed.Offset; 030 031/** 032 * Iterator for stack frames inserted at the transition from Java to 033 * JNI Native C. It will report JREFs associated with the executing 034 * C frames which are in the "JREFs stack" attached to the executing 035 * Threads JNIEnvironment. It will update register location addresses 036 * for the non-volatile registers to point to the registers saved 037 * in the transition frame. 038 * 039 * @see JNICompiler 040 */ 041@Uninterruptible 042public final class JNIGCMapIterator extends GCMapIterator { 043 044 // Java to Native C transition frame...(see JNICompiler) 045 // 046 // 0 + saved FP + <---- FP for Java to Native C glue frame 047 // -4 | methodID | 048 // -8 | saved EDI | non-volatile GPR 049 // -C | saved EBX | non-volatile GPR 050 // -10 | saved EBP | non-volatile GPR 051 // -14 | returnAddr | (for return from OutOfLineMachineCode) 052 // -18 | saved PR | 053 // -1C | arg n-1 | reordered arguments to native method 054 // -20 | ... | ... 055 // -24 | arg 1 | ... 056 // -28 | arg 0 | ... 057 // -2C | class/obj | required 2nd argument to all native methods 058 // -30 | jniEnv | required 1st argument to all native methods 059 // -34 | returnAddr | return address pushed by call to native method 060 // + saved FP + <---- FP for called native method 061 062 // additional instance fields added by this subclass of GCMapIterator 063 AddressArray jniRefs; 064 int jniNextRef; 065 int jniFramePtr; 066 067 public JNIGCMapIterator(AddressArray registerLocations) { 068 super(registerLocations); 069 } 070 071 // Override newStackWalk() in parent class GCMapIterator to 072 // initialize iterator for scan of JNI JREFs stack of refs 073 // Taken: thread 074 // Returned: nothing 075 // 076 @Override 077 public void newStackWalk(RVMThread thread) { 078 super.newStackWalk(thread); // sets this.thread, inits registerLocations[] 079 JNIEnvironment env = this.thread.getJNIEnv(); 080 // the "primordial" thread, created by JDK in the bootimage, does not have 081 // a JniEnv object, all threads created by the VM will. 082 if (env != null) { 083 this.jniRefs = env.refsArray(); 084 this.jniNextRef = env.refsTop(); 085 this.jniFramePtr = env.savedRefsFP(); 086 } 087 } 088 089 @Override 090 public void setupIterator(CompiledMethod compiledMethod, Offset instructionOffset, Address framePtr) { 091 this.framePtr = framePtr; 092 } 093 094 // return (address of) next ref in the current "frame" on the 095 // threads JNIEnvironment stack of refs 096 // When at the end of the current frame, update register locations to point 097 // to the non-volatile registers saved in the JNI transition frame. 098 // 099 @Override 100 public Address getNextReferenceAddress() { 101 // first report jni refs in the current frame in the jniRef side stack 102 // until all in the frame are reported 103 // 104 if (jniNextRef > jniFramePtr) { 105 Address ref_address = Magic.objectAsAddress(jniRefs).plus(jniNextRef); 106 jniNextRef -= BYTES_IN_ADDRESS; 107 return ref_address; 108 } 109 110 // no more refs to report, before returning 0, setup for processing 111 // the next jni frame, if any 112 113 // jniNextRef -> savedFramePtr for another "frame" of refs for another 114 // sequence of Native C frames lower in the stack, or to 0 if this is the 115 // last jni frame in the JNIRefs stack. If more frames, initialize for a 116 // later scan of those refs. 117 // 118 if (jniFramePtr > 0) { 119 jniFramePtr = jniRefs.get(jniFramePtr >> LOG_BYTES_IN_ADDRESS).toInt(); 120 jniNextRef = jniNextRef - BYTES_IN_ADDRESS; 121 } 122 123 // set register locations for non-volatiles to point to registers saved in 124 // the JNI transition frame at a fixed negative offset from the callers FP. 125 // the save non-volatiles are EBX EBP and EDI. 126 // 127 registerLocations.set(EDI.value(), framePtr.plus(JNICompiler.EDI_SAVE_OFFSET)); 128 registerLocations.set(EBX.value(), framePtr.plus(JNICompiler.EBX_SAVE_OFFSET)); 129 registerLocations.set(EBP.value(), framePtr.plus(JNICompiler.EBP_SAVE_OFFSET)); 130 131 return Address.zero(); // no more refs to report 132 } 133 134 @Override 135 public Address getNextReturnAddressAddress() { 136 return Address.zero(); 137 } 138 139 @Override 140 public void reset() { } 141 142 @Override 143 public void cleanupPointers() { } 144 145 @Override 146 public int getType() { 147 return CompiledMethod.JNI; 148 } 149}