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 gnu.classpath; 014 015import org.jikesrvm.VM; 016import org.jikesrvm.classloader.RVMType; 017import org.jikesrvm.runtime.Entrypoints; 018import org.jikesrvm.runtime.StackBrowser; 019 020/** 021 * This is a cheap stack browser. Better would be something like 022 * the Jikes RVM {@link StackBrowser} class. 023 * <p> 024 * This is our interface to GNU Classpath. We quote the official 025 * Classpath Javadoc here, as part of clearly describing the interface. 026 * Never the less, look at the source code of the GNU Class 027 * (classpath/vm/reference/gnu/classpath/VMStackWalker.java) for the latest 028 * description of what these methods should do. NOTE: we do not quote 029 * any JavaDoc that would cause JavaDoc warnings to be emitted in JDK8. 030 */ 031public final class VMStackWalker { 032 033 /** 034 * Walk up the stack and return the first non-{@code null} class loader. 035 * If there aren't any non-{@code null} class loaders on the stack, return 036 * {@code null}. 037 * 038 * @return the first non-{@code null} classloader on stack or {@code null} 039 */ 040 public static ClassLoader firstNonNullClassLoader() { 041 for (Class<?> type : getClassContext()) { 042 ClassLoader loader = type.getClassLoader(); 043 if (loader != null) 044 return loader; 045 } 046 return null; 047 } 048 049 /** 050 * Classpath's Javadoc for this method says: 051 * <blockquote> 052 * Get a list of all the classes currently executing methods on the 053 * Java stack. <code>getClassContext()[0]</code> is the class associated 054 * with the currently executing method, i.e., the method that called 055 * <code>VMStackWalker.getClassContext()</code> (possibly through 056 * reflection). So you may need to pop off these stack frames from 057 * the top of the stack: 058 * <ul> 059 * <li><code>VMStackWalker.getClassContext()</code> 060 * <li><code>Method.invoke()</code> 061 * </ul> 062 * 063 * @return an array of the declaring classes of each stack frame 064 * </blockquote> 065 */ 066 public static Class<?>[] getClassContext() { 067 StackBrowser b = new StackBrowser(); 068 int frames = 0; 069 VM.disableGC(); 070 071 b.init(); 072 b.up(); // skip VMStackWalker.getClassContext (this call) 073 074 boolean reflected; // Were we invoked by reflection? 075 if (b.getMethod() == Entrypoints.java_lang_reflect_Method_invokeMethod) { 076 reflected = true; 077 b.up(); // Skip Method.invoke, (if we were called by reflection) 078 } else { 079 reflected = false; 080 } 081 082 /* Count # of frames. */ 083 while (b.hasMoreFrames()) { 084 frames++; 085 b.up(); 086 } 087 088 VM.enableGC(); 089 090 091 RVMType[] iclasses = new RVMType[ frames ]; 092 093 int i = 0; 094 b = new StackBrowser(); 095 096 VM.disableGC(); 097 b.init(); 098 b.up(); // skip this method 099 if (reflected) 100 b.up(); // Skip Method.invoke if we were called by reflection 101 102 while (b.hasMoreFrames()) { 103 iclasses[i++] = b.getCurrentClass(); 104 b.up(); 105 } 106 VM.enableGC(); 107 108 Class<?>[] classes = new Class[ frames ]; 109 for (int j = 0; j < iclasses.length; j++) { 110 classes[j] = iclasses[j].getClassForType(); 111 } 112 113 return classes; 114 } 115 116 // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag 117 public static Class<?> getCallingClass() { 118 return getCallingClass(1); // Skip this method (getCallingClass()) 119 } 120 121 // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag 122 public static Class<?> getCallingClass(int skip) { 123 StackBrowser b = new StackBrowser(); 124 VM.disableGC(); 125 126 b.init(); 127 b.up(); // skip VMStackWalker.getCallingClass(int) (this call) 128 while (skip-- > 0) // Skip what the caller asked for. 129 b.up(); 130 131 /* Skip Method.invoke, (if the caller was called by reflection) */ 132 if (b.getMethod() == Entrypoints.java_lang_reflect_Method_invokeMethod) { 133 b.up(); 134 } 135 /* skip past another frame, whatever getClassContext()[0] would be. */ 136 if (!b.hasMoreFrames()) 137 return null; 138 b.up(); 139 140 /* OK, we're there at getClassContext()[1] now. Return it. */ 141 RVMType ret = b.getCurrentClass(); 142 VM.enableGC(); 143 144 return ret.getClassForType(); 145 } 146 147 // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag 148 public static ClassLoader getCallingClassLoader() { 149 Class<?> caller = getCallingClass(1); // skip getCallingClassLoader 150 if (caller == null) 151 return null; 152 return caller.getClassLoader(); 153 } 154} 155