On 4/1/13 5:24 PM, John Rose wrote:
On Mar 27, 2013, at 10:35 AM, Mandy Chung <mandy.ch...@oracle.com <mailto:mandy.ch...@oracle.com>> wrote:

This is the JDK change for JEP 176: JEP 176: Mechanical Checking of Caller-Sensitive Methods [1]. Christian has posted the webrev for the hotspot VM change a couple weeks ago [2].

Webrev at:
http://cr.openjdk.java.net/~mchung/jdk8/webrevs/7198429/webrev.00/ <http://cr.openjdk.java.net/%7Emchung/jdk8/webrevs/7198429/webrev.00/>

This is very good work. It makes certain aspects of the system much easier to understand.

I have reviewed it all, with the following comments:

Thanks for the review.
The transform moves caller sensitivity into a clearly visible position. In many cases, the call to Reflection.getCallerClass now precedes the check of the security manager. For some customer codes, this may cause a performance regression, although it will probably be in the noise in most cases.

Agree.  I have restored the cases that should find caller class lazily.

If necessary, we can replace some uses of R.getCC() by something like (S.getSecurityManager() == null ? null : R.getCC()), recovering the original laziness of the stack check. This won't be necessary everywhere. Note that the server compiler can usually remove the stack walk. We may need to put something similar into the client compiler.

In the case of the reflective calls (Field, Constructor, Method), the check of the caller class is gated by both AccessibleObject.override and quickCheckMemberAccess, and you have preserved this for Constructor and Method (which are probably the most important performance case). Consider gating it also for Field, as noted below.

Per-file comments:

-- Class.java

(See below about checking for checkMemberAccess override.)


Done.
-- ClassLoader.java

Did you consider using Class.cast to get a runtime check instead of @SuppressWarnings("unchecked")?


Good point - I have modified it to do runtime check using Class.asSubclass.
-- MethodHandleNatives.java

Was this deletion intentional or was it something Eclipse or Netbeans did?
  -import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;

It was unintentional and I fixed it differently when I realized the reference of IMPL_LOOKUP. I now have restored to the original import static to be consistent with other files.

Good cleanups!

You can remove this since rAPC is static (error in original code):
         case "registerAsParallelCapable":
             return canBeCalledVirtual(mem, java.lang.ClassLoader.class);


Done.

Note that the subsequent call to canBeCalledVirtual will disqualify mem because it is static.


Yes.
-- MethodHandles.Lookup

Now that stack walking is out of the picture, make all the constructors private, and remove this scary comment:
         * <p>
         * Also, don't make it private, lest javac interpose
         * an access$N method.

Done.

I like this comment, and the manual inlining technique (in this very special case):
  // Inlined SecurityManager.checkMemberAccess
Since it tends to get lost in the previous comment block, I suggest you put it after the open brace of the inlined body.

Also, both parameters should be inlined at the top of the block, not just "which", so the rest of the block can a more or less verbatim copy.

  +      { // Inlined SecurityManager.checkMemberAccess
  +        final Class<?> clazz = refc/defc;
  +        final int which = Member.PUBLIC/PRIVATE;


I considered that too and made the change. I actually took out the redundant check (which != PUBLIC) since we know the value.

As previously noted, smgr.getClass() == SecurityManager.class is too strict. Suggest hoisting the nasty logic into a boolean, and using it twice:

boolean standardCMA = (smgr.getClass() == SecurityManager.class);
if (!standardCMA) try {
standardCMA = smgr.getClass().getDeclaredMethod("checkMemberAccess", ...).getDeclaringClass() == SecurityManager.class;
} catch (ReflectiveOperationException ex) { throw new InternalError(ex); }

if (standardCMA) {  // // Inlined SecurityManager.checkMemberAccess
  final Class<?> clazz = refc/defc;
  final int which = Member.PUBLIC/PRIVATE;
  ...
} else {
  smgr.checkMemberAccess(...);
}


OK. I modified a little. For subclass case, I can simply check if Class.getDeclaredMethod finds the method; if exists, it's overrided; otherwise, NoSuchMethodException thrown indicates using the standard one.

(And a similar comment for Class.java.)

Done.

Lots of trouble for a corner case!

-- Field.java

Consider making R.getCC more lazy as follows:

+ return getFieldAccessor(obj, needsMemberAccessCheck() ? Reflection.getCallerClass() : clazz).get(obj);

+  private boolean needsMemberAccessCheck() {
+ return !override && !Reflection.quickCheckMemberAccess(clazz, modifiers);
+  }

(This might affect the performance of serialization.)


-- CallerSensitiveFinder.java

This is a remarkable test. Does it statically determine whether the annotations are missing?

Yes - that's the purpose to catch if any use of Reflection.getCallerClass() but not missing @CS annotation.

 Does it process all of rt.jar?  How long does it take to complete?


It processes all JRE classes (i.e. rt.jar, jar files in JAVA_HOME/lib and JAVA_HOME/lib/ext).

I have made it done the minimal necessary work only. It takes 6 seconds on my MacMini (2GHz core i7 and 8GB memory) to parse 24243 classes. It takes 5-14 seconds on the jprt machines and here are some sample timing:
   linux_i586 jdk_lang took 14 mins and CallerSensitiveFinder took 8.5 sec
macosx_x64 jdk_lang took 20.5 mins and CallerSensitiveFinder took 14.5 sec solaris_i586 jdk_lang took 15.5 mins and CallerSensitiveFinder took 10 sec windows_x64 jdk_lang took 16.5 mins and CallerSensitiveFinder took 10 sec

And (I have to ask, though I'm sure the answer will be yes) have you run it on broken inputs (such as boot.GetCallerClass.missingCallerSensitiveAnnotation) and verified that it barks at them?

I ran it on an older JDK that calls Reflection.getCallerClass(int) and no @sun.reflect.CallerSensitive exist.

The test is currently tailored-made to only parses JRE classes. I can easily extend it to parse additional classes like boot.GetCallerClass that is a good test case to this tool itself. Will do so.

I'll post a new webrev once I finish the testing.

thanks for the detailed review.
Mandy

Reply via email to