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

NoClassDefFound error in transforming lambdas

    Details

    • Subcomponent:
    • Resolved In Build:
      b135
    • CPU:
      x86
    • OS:
      generic

      Description

      FULL PRODUCT VERSION :
      java version "1.8.0_65"
      Java(TM) SE Runtime Environment (build 1.8.0_65-b17)
      Java HotSpot(TM) 64-Bit Server VM (build 25.65-b01, mixed mode)

      FULL OS VERSION :
      Darwin mybox 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53 PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64

      A DESCRIPTION OF THE PROBLEM :
      In attempting to transform a lambda instance, it appears the application class loader has no knowledge of its existence. Presumably, this is due to the lambda instance representation being generated at runtime.

      As a consequence, this causes a handful of instrumentation issues. For instance, simply passing a lambda instance through a class transformer and returning a null set of bytes to indicate 'do not transform', fails outright with a NoClassDefFoundError. In other cases, if in using instrumentation tools like ASM compute stack map frames for type checking; the composed stack map can be bogus as the 'type' doesn't really exist.

      I've noted the behavior on Stackoverflow to get a feel of whether or not this may be a JDK bug. Please see the following entry here: http://stackoverflow.com/questions/34162074/transforming-lambdas-in-java-8

      Additionally, I've created a simple repro for the issue in Github: https://github.com/akilman/java-lambda-retransform

      THE PROBLEM WAS REPRODUCIBLE WITH -Xint FLAG: Did not try

      THE PROBLEM WAS REPRODUCIBLE WITH -server FLAG: Did not try

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Please see https://github.com/akilman/java-lambda-retransform for source code. This is a set of two simple gradle projects for reproducing the issue.

      Assuming the environment has access to the web, clone the github repo, and execute run.sh. This will build and run both projects via Gradle.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Expectation is, transforming lambdas should be fair game. The instrumentation API doesn't exclude this category, so one would assume the two categories of functionality should work together.
      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.lang.NoClassDefFoundError: App$$Lambda$2
          at App$$Lambda$2/1329552164.run(Unknown Source)
          at App.main(App.java:9)
      Caused by: java.lang.ClassNotFoundException: App$$Lambda$2
          at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
          at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
          at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
          ... 2 more

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      Please see https://github.com/akilman/java-lambda-retransform for source code.
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No workaround at the moment

        Issue Links

          Activity

          Hide
          coleenp Coleen Phillimore added a comment -
          Agreed that we should skip VM Anonymous classes in redefinition and CFLH. [~never] The above doesn't make sense to me because the VM anonymous class doesn't share a constant pool with the host_class (unless it's a well hidden detail). But, yes I am sure that there are other problems and skipping them seems like the right thing to do. Here's John stating that transformers will not apply to VM anonymous classes from another thread.

          http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-January/038353.html
          Show
          coleenp Coleen Phillimore added a comment - Agreed that we should skip VM Anonymous classes in redefinition and CFLH. [~never] The above doesn't make sense to me because the VM anonymous class doesn't share a constant pool with the host_class (unless it's a well hidden detail). But, yes I am sure that there are other problems and skipping them seems like the right thing to do. Here's John stating that transformers will not apply to VM anonymous classes from another thread. http://mail.openjdk.java.net/pipermail/core-libs-dev/2016-January/038353.html
          Hide
          never Tom Rodriguez added a comment -
          Yes, I think I misunderstood why the fundamental breakage occurs. It's really that construction of anonymous classes has magic concerning the host_klass and that's not handled properly in the redefinition path, so the newly redefined anonymous class is malformed after the redefinition.

          I think an easy way to see this would be to get or write a lambda based microbenchmark and then look at it under the VisualVM profiler, which should trigger redefinition of the lambdas used in the benchmark. I know there are some JMH ones that are part of the test suites. The only visible symptom of the failed redefinition is the NoClassDefFoundError, which is caused by not executing this code:

              if (is_anonymous()) // I am well known to myself
                cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve

          in classFileParser.cpp when parsing the redefinition. lambdas aren't allowed to be resolved through normal lookup so it must be done this way.
          Show
          never Tom Rodriguez added a comment - Yes, I think I misunderstood why the fundamental breakage occurs. It's really that construction of anonymous classes has magic concerning the host_klass and that's not handled properly in the redefinition path, so the newly redefined anonymous class is malformed after the redefinition. I think an easy way to see this would be to get or write a lambda based microbenchmark and then look at it under the VisualVM profiler, which should trigger redefinition of the lambdas used in the benchmark. I know there are some JMH ones that are part of the test suites. The only visible symptom of the failed redefinition is the NoClassDefFoundError, which is caused by not executing this code:     if (is_anonymous()) // I am well known to myself       cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve in classFileParser.cpp when parsing the redefinition. lambdas aren't allowed to be resolved through normal lookup so it must be done this way.
          Hide
          coleenp Coleen Phillimore added a comment -
          [~never] your fix is good, do you want to be contributed-by? I added a test and am sending it out for review.
          Show
          coleenp Coleen Phillimore added a comment - [~never] your fix is good, do you want to be contributed-by? I added a test and am sending it out for review.
          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/hs/hotspot/rev/c8aaea51e2eb
          User: coleenp
          Date: 2016-08-19 22:27:43 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/hs/hotspot/rev/c8aaea51e2eb User: coleenp Date: 2016-08-19 22:27:43 +0000
          Hide
          hgupdate HG Updates added a comment -
          URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/c8aaea51e2eb
          User: lana
          Date: 2016-09-07 20:26:04 +0000
          Show
          hgupdate HG Updates added a comment - URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/c8aaea51e2eb User: lana Date: 2016-09-07 20:26:04 +0000

            People

            • Assignee:
              coleenp Coleen Phillimore
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              10 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: