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