Code Review for JEP 259: Stack-Walking API (original) (raw)

Peter Levart peter.levart at gmail.com
Tue Nov 17 20:57:28 UTC 2015


Hi Mandy,

On 11/17/2015 01:13 AM, Mandy Chung wrote:

I’d like to get the code review done by this week.

I renamed the static factory method from create to getInstance since “create” implies to create a new instance but the method returns a cached instance instead. I also changed the spec of getCallerClass per [1]. There is not much change since webrev.01. Webrev: http://cr.openjdk.java.net/~mchung/jdk9/jep259/webrev.02 javadoc: http://cr.openjdk.java.net/~mchung/jdk9/jep259/api/ Mandy [1] http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-November/036589.html

Just read the javadoc so-far...

There are several mistakes in getCallerClass() API Note (some probably a left-over from previous iterations of the API):

471 *

If this {@code getCallerClass} method is called by the entry point 472 * of a thread, the {@code Class} of the method invoked at thread's start 473 * time will be returned.

Hm, I can't decipher that. What about something like:

If this {@code getCallerClass} method is called by the entry point of a thread - a method overriding {@link Thread#run} (that's the only possibility), the declaring class of the method overriding {@link Thread#run} will be returned.

Or, if you accept my latest suggestion:

If this {@code getCallerClass} method is called by the entry point of a thread - a method overriding {@link Thread#run}, {@link IllegalArgumentException} will be thrown.

474 * 475 * @apiNote 476 * For example, {@code ResourceBundleUtil::getBundle} loads a resource bundle 477 * on behalf of the caller. It calls this {@code getCallerClass} method 478 * to find the method calling {@code Util::getResourceBundle} and use the caller's 479 * class loader to load the resource bundle. The caller class in this example 480 * is the {@code MyTool} class. 481 * 482 *

{@code
  483      *     class ResourceBundleUtil {
  484      *         private final StackWalker walker = 
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
  485      *         public ResourceBundle getBundle(String bundleName) {
  486      *             Class caller = walker.getCallerClass();
  487      *             return ResourceBundle.getBundle(bundleName, 
caller.getClassLoader());
  488      *         }
  489      *     }
  490      *
  491      *     class MyTool {
  492      *         private void init() {
  493      *             ResourceBundle rb = 
Util.getResourceBundle("mybundle");
  494      *         }
  495      *     }
  496      * }

hidden frames 501 * not shown below): 502 *

{@code
  503      *     Class caller = walker.walk(s ->
  504      *         s.map(StackFrame::getDeclaringClass)
  505      *          .skip(2)
  506      *          .findFirst());
  507      * }

thread {@code t}'s 510 * entry point, i.e. {@code PrimeRun::run}, it returns {@code PrimeRun} class 511 * that is the first stack frame below the stack frame for {@code getCallerClass} 512 * instead. 513 * 514 *

{@code
  515      *     class PrimeRun implements Runnable {
  516      *         public void run() {
  517      *             Class c = 
StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
  518      *                                     .getCallerClass();
  519      *         }
  520      *     }
  521      *     Thread t = new Thread(new PrimeRun()).start();
  522      * }
523 * 524 * Similarly, when the {@code getCallerClass} method is called from the 525 * {@code static public void main} method launched by the {@code java} launcher, 526 * it returns the {@code Class} of the {@code main} method. 527 * 528 * @return {@code Class} object of the caller's caller invoking this method; 529 * or the {@code Class} object of the method invoked by a thread at start time.

public class Thread { ... public void run() { if (target != null) { target.run(); } }

...so this example is not really suitable to describe the effect of invoking getCallerClass from thread's entry-point.

An example of that kind would be something like:

class PrimeThread extends Thread { @Override public void run() { Class<?> c = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE) .getCallerClass(); } }

Thread t = new PrimeThread().start();

There are only three situations to consider:

The last is special - It's not any method called by JNI. If Java calls a native method and that native method calls-back to Java via JNI, the method calling native method will be on the stack and getCallerClass() invoked from the called-back method will return it (this can be seen when observing reflection calls that go through sun.reflect.NativeMethodAccessorImpl).

Regards, Peter



More information about the hotspot-runtime-dev mailing list