/* * This file is part of the Jikes RVM project (http://jikesrvm.org). * * This file is licensed to You under the Eclipse Public License (EPL); * You may not use this file except in compliance with the License. You * may obtain a copy of the License at * * http://www.opensource.org/licenses/eclipse-1.0.php * * See the COPYRIGHT.txt file distributed with this work for information * regarding copyright ownership. */ package gnu.classpath; import org.jikesrvm.VM; import org.jikesrvm.classloader.RVMType; import org.jikesrvm.runtime.Entrypoints; import org.jikesrvm.runtime.StackBrowser; /** * This is a cheap stack browser. Better would be something like * the Jikes RVM {@link StackBrowser} class. * <p> * This is our interface to GNU Classpath. We quote the official * Classpath Javadoc here, as part of clearly describing the interface. * Never the less, look at the source code of the GNU Class * (classpath/vm/reference/gnu/classpath/VMStackWalker.java) for the latest * description of what these methods should do. NOTE: we do not quote * any JavaDoc that would cause JavaDoc warnings to be emitted in JDK8. */ public final class VMStackWalker { /** * Walk up the stack and return the first non-{@code null} class loader. * If there aren't any non-{@code null} class loaders on the stack, return * {@code null}. * * @return the first non-{@code null} classloader on stack or {@code null} */ public static ClassLoader firstNonNullClassLoader() { for (Class<?> type : getClassContext()) { ClassLoader loader = type.getClassLoader(); if (loader != null) return loader; } return null; } /** * Classpath's Javadoc for this method says: * <blockquote> * Get a list of all the classes currently executing methods on the * Java stack. <code>getClassContext()[0]</code> is the class associated * with the currently executing method, i.e., the method that called * <code>VMStackWalker.getClassContext()</code> (possibly through * reflection). So you may need to pop off these stack frames from * the top of the stack: * <ul> * <li><code>VMStackWalker.getClassContext()</code> * <li><code>Method.invoke()</code> * </ul> * * @return an array of the declaring classes of each stack frame * </blockquote> */ public static Class<?>[] getClassContext() { StackBrowser b = new StackBrowser(); int frames = 0; VM.disableGC(); b.init(); b.up(); // skip VMStackWalker.getClassContext (this call) boolean reflected; // Were we invoked by reflection? if (b.getMethod() == Entrypoints.java_lang_reflect_Method_invokeMethod) { reflected = true; b.up(); // Skip Method.invoke, (if we were called by reflection) } else { reflected = false; } /* Count # of frames. */ while (b.hasMoreFrames()) { frames++; b.up(); } VM.enableGC(); RVMType[] iclasses = new RVMType[ frames ]; int i = 0; b = new StackBrowser(); VM.disableGC(); b.init(); b.up(); // skip this method if (reflected) b.up(); // Skip Method.invoke if we were called by reflection while (b.hasMoreFrames()) { iclasses[i++] = b.getCurrentClass(); b.up(); } VM.enableGC(); Class<?>[] classes = new Class[ frames ]; for (int j = 0; j < iclasses.length; j++) { classes[j] = iclasses[j].getClassForType(); } return classes; } // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag public static Class<?> getCallingClass() { return getCallingClass(1); // Skip this method (getCallingClass()) } // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag public static Class<?> getCallingClass(int skip) { StackBrowser b = new StackBrowser(); VM.disableGC(); b.init(); b.up(); // skip VMStackWalker.getCallingClass(int) (this call) while (skip-- > 0) // Skip what the caller asked for. b.up(); /* Skip Method.invoke, (if the caller was called by reflection) */ if (b.getMethod() == Entrypoints.java_lang_reflect_Method_invokeMethod) { b.up(); } /* skip past another frame, whatever getClassContext()[0] would be. */ if (!b.hasMoreFrames()) return null; b.up(); /* OK, we're there at getClassContext()[1] now. Return it. */ RVMType ret = b.getCurrentClass(); VM.enableGC(); return ret.getClassForType(); } // JavaDoc not quoted because Classpath 0.97.2's JavaDoc is missing a @return tag public static ClassLoader getCallingClassLoader() { Class<?> caller = getCallingClass(1); // skip getCallingClassLoader if (caller == null) return null; return caller.getClassLoader(); } }