Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8059357

ClassVerifier redundantly checks constant pool entries multiple times



    • b14


      If you run the updated jdk9-dev with JDK-8057846 and JDK-8057845 patches applied, and run the class loading benchmark with Nashorn generated classes:

      $ ~/trunks/jdk9-dev/build/linux-x86_64-normal-server-release/images/j2sdk-image/bin/java -jar ~shade/8053904/benchmarks.jar -p file=~shade/8053904/classes.jar

      (both files are available under the same names at cr.openjdk.java.net)

      Then you will see this profile:
      Notice the significant time is spent in ClassVerifier::verify_invoke_instructions -> ClassVerifier::change_sig_to_verificationType processing. If you look at the ClassVerifier::verify_invoke_instructions code, then you will realize the code can do the Symbol resolution for the given CP index over and over again, when the invoke instruction is referencing the same method signature:

       u2 index = bcs->get_index_u2();
       Symbol* method_sig = cp->signature_ref_at(index);
        SignatureStream sig_stream(method_sig);
        int sig_i = 0;
        while (!sig_stream.at_return_type()) {
          sig_i += change_sig_to_verificationType(
            &sig_stream, &sig_types[sig_i], CHECK_VERIFY(this));
        int nargs = sig_i;

      This is not a problem for ConstantPool itself, because taking the Symbol by index is very fast. But it starts to become a problem after we continuously parse the individual symbols from the signature wit SignatureStream. You see this as the hotspot in the profile above. We also redundantly check SignatureVerifier::is_valid_method_signature(method_sig) over and over again.

      To check I am not delusional, the very simple instrumentation patch can print the (cp index, method-under-verification hashcode) pairs to see if we indeed doing the same lookup for the same method over and over again:

      ...and these are the results:
       http://cr.openjdk.java.net/~shade/8059357/nashorn-verifier-dups.txt.gz (full log, 7 Mb)

      You can see there, we do up to 10K checks for the given (cpi, mhc) in this verification method. The average across the entire log is closer to 4.15 checks per (cpi, mhc).

      I think we need to do this thing once to significantly speed up the Verifier. Possible options:
       a) Let ConstantPool cache the parsed signature Symbols and hold the "verified" flags for data that do not require verification context;
       b) Make Verifier to do a single pass over ConstantPool, and verify all MethodRef entries at once.

      The rough estimate for performance improvement is at least 5-10% for the entire classloading, depending how much common code we can fold into doing once.


        Issue Links



              hseigel Harold Seigel (Inactive)
              shade Aleksey Shipilev
              0 Vote for this issue
              9 Start watching this issue