changeset 54408:73e3eeab3c0c nestmates

Summary: Instead of storing nonfindable class name in the constant pool, save it in the instanceKlass as the external_name. Reviewed-by: lfoltan
author hseigel
date Tue, 26 Feb 2019 13:11:28 -0500
parents ab7ea72963c9
children 82995b3833f0
files src/hotspot/share/classfile/classFileParser.cpp src/hotspot/share/classfile/classFileParser.hpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp src/hotspot/share/oops/klass.cpp test/jdk/java/lang/invoke/defineClass/DefineNonFindableClass.java test/jdk/java/lang/invoke/defineClass/nonFindable/NonFindable.java
diffstat 7 files changed, 221 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/classfile/classFileParser.cpp	Fri Feb 22 16:54:55 2019 -0800
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Tue Feb 26 13:11:28 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -5564,6 +5564,7 @@
   // Set name and CLD before adding to CLD
   ik->set_class_loader_data(_loader_data);
   ik->set_name(_class_name);
+  ik->set_nonf_external_name(_nonf_class_name);
 
   // Add all classes to our internal class loader list here,
   // including classes in the bootstrap (NULL) class loader.
@@ -5865,6 +5866,7 @@
                                  Publicity pub_level,
                                  TRAPS) :
   _stream(stream),
+  _nonf_class_name(NULL),
   _loader_data(loader_data),
   _unsafe_anonymous_host(unsafe_anonymous_host),
   _cp_patches(cp_patches),
@@ -6172,10 +6174,10 @@
   // un-named, nonfindable or unsafe-anonymous class.
 
   if (_is_nonfindable) {
-    // Replace the CP name with given _class_name and bump its reference count
-    cp->symbol_at_put(cp->klass_name_index_at(_this_class_index), _class_name);
-    _class_name->increment_refcount();
-    class_name_in_cp->decrement_refcount(); // no longer in cp
+    // Save the given _class_name before overwriting it with name in constant pool.
+    _nonf_class_name = _class_name;
+    _nonf_class_name->increment_refcount();
+     _class_name = class_name_in_cp;
   } else {
     // NOTE: !_is_nonfindable does not imply "findable" as it could be an old-style
     //       "non-findable" unsafe-anonymous class
--- a/src/hotspot/share/classfile/classFileParser.hpp	Fri Feb 22 16:54:55 2019 -0800
+++ b/src/hotspot/share/classfile/classFileParser.hpp	Tue Feb 26 13:11:28 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,7 @@
 
   const ClassFileStream* _stream; // Actual input stream
   Symbol* _class_name;
+  Symbol* _nonf_class_name;
   mutable ClassLoaderData* _loader_data;
   const InstanceKlass* _unsafe_anonymous_host;
   GrowableArray<Handle>* _cp_patches; // overrides for CP entries
@@ -538,6 +539,7 @@
   const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
   ClassLoaderData* loader_data() const { return _loader_data; }
   const Symbol* class_name() const { return _class_name; }
+  const Symbol* nonf_class_name() const { return _nonf_class_name; }
   const InstanceKlass* super_klass() const { return _super_klass; }
 
   ReferenceType reference_type() const { return _rt; }
--- a/src/hotspot/share/oops/instanceKlass.cpp	Fri Feb 22 16:54:55 2019 -0800
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Tue Feb 26 13:11:28 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -471,6 +471,7 @@
   _nest_members(NULL),
   _nest_host_index(0),
   _nest_host(NULL),
+  _nonf_external_name(NULL),
   _static_field_size(parser.static_field_size()),
   _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
   _itable_len(parser.itable_size()),
@@ -2556,6 +2557,8 @@
 
   // Decrement symbol reference counts associated with the unloaded class.
   if (_name != NULL) _name->decrement_refcount();
+  if (_nonf_external_name != NULL) _nonf_external_name->decrement_refcount();
+
   // unreference array name derived from this class name (arrays of an unloaded
   // class can't be referenced anymore).
   if (_array_name != NULL)  _array_name->decrement_refcount();
@@ -2653,12 +2656,12 @@
     // For now option #2 is used since a nest host is not set until
     // after the instance class is created in jvm_lookup_define_class().
     if (class_loader_data()->is_boot_class_loader_data()) {
-      return ClassLoaderData::the_null_class_loader_data()->unnamed_module(); 
+      return ClassLoaderData::the_null_class_loader_data()->unnamed_module();
     } else {
       oop module = java_lang_ClassLoader::unnamedModule(class_loader_data()->class_loader());
       assert(java_lang_Module::is_instance(module), "Not an instance of java.lang.Module");
       return java_lang_Module::module_entry(module);
-    } 
+    }
   }
 
   // Class is in a named package
--- a/src/hotspot/share/oops/instanceKlass.hpp	Fri Feb 22 16:54:55 2019 -0800
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Tue Feb 26 13:11:28 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -181,6 +181,9 @@
   // By always being set it makes nest-member access checks simpler.
   InstanceKlass* _nest_host;
 
+  // Provided name for nonfindable classes.
+  Symbol*         _nonf_external_name;
+
   // the source debug extension for this klass, NULL if not specified.
   // Specified as UTF-8 string without terminating zero byte in the classfile,
   // it is stored in the instanceklass as a NULL-terminated UTF-8 string
@@ -463,6 +466,14 @@
   // dynamic nest member support
   void set_nest_host(InstanceKlass* host, TRAPS);
 
+  // Store external name for a nonfindable class.
+  void set_nonf_external_name(Symbol* name) {
+    assert(name == NULL || is_nonfindable(), "Must be nonfindable class");
+    _nonf_external_name = name;
+  }
+
+  Symbol* nonf_external_name() const { return _nonf_external_name; }
+
 private:
   // Called to verify that k is a member of this nest - does not look at k's nest-host
   bool has_nest_member(InstanceKlass* k, TRAPS) const;
--- a/src/hotspot/share/oops/klass.cpp	Fri Feb 22 16:54:55 2019 -0800
+++ b/src/hotspot/share/oops/klass.cpp	Tue Feb 26 13:11:28 2019 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -700,6 +700,9 @@
       strcpy(result + name_len, addr_buf);
       assert(strlen(result) == name_len + addr_len, "");
       return result;
+    } else if (ik->is_nonfindable()) {
+      assert(ik->nonf_external_name() != NULL, "Nonfindable klass has null name");
+      return ik->nonf_external_name()->as_klass_external_name();
     }
   }
   if (name() == NULL)  return "<unknown>";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/defineClass/DefineNonFindableClass.java	Tue Feb 26 13:11:28 2019 -0500
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @build jdk.test.lib.JDKToolLauncher
+ *        jdk.test.lib.process.ProcessTools
+ *        jdk.test.lib.Utils
+ * @run main DefineNonFindableClass
+ */
+/*
+ * @test
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @build jdk.test.lib.JDKToolLauncher
+ *        jdk.test.lib.process.ProcessTools
+ *        jdk.test.lib.Utils
+ * @run main DefineNonFindableClass useUnsafe
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodHandles.Lookup;
+import static java.lang.invoke.MethodHandles.Lookup.ClassProperty.*;
+import static java.lang.invoke.MethodHandles.Lookup.PRIVATE;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import jdk.internal.misc.Unsafe;
+
+import jdk.test.lib.JDKToolLauncher;
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.Utils;
+
+/* package-private */ interface Test {
+  void test();
+}
+
+
+public class DefineNonFindableClass {
+
+    static final Class<?> klass = DefineNonFindableClass.class;
+    static final Path SRC_DIR = Paths.get(Utils.TEST_SRC, "nonFindable");
+    static final Path CLASSES_DIR = Paths.get(Utils.TEST_CLASSES, "nonFindable");
+
+    static void compileSources() throws Throwable {
+        JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("javac");
+        launcher.addToolArg("-cp")
+                .addToolArg(Utils.TEST_CLASSES.toString())
+                .addToolArg("-d")
+                .addToolArg(CLASSES_DIR.toString())
+            .addToolArg(Paths.get(SRC_DIR.toString(), "NonFindable.java").toString());
+
+        int exitCode = ProcessTools.executeCommand(launcher.getCommand())
+                                   .getExitValue();
+        if (exitCode != 0) {
+            throw new RuntimeException("Compilation of the test failed. "
+                    + "Unexpected exit code: " + exitCode);
+        }
+    }
+
+    static byte[] readClassFile() throws Exception {
+        File classFile = new File(CLASSES_DIR + "/NonFindable.class");
+        try (FileInputStream in = new FileInputStream(classFile);
+             ByteArrayOutputStream out = new ByteArrayOutputStream())
+        {
+            int b;
+            while ((b = in.read()) != -1) {
+                out.write(b);
+            }
+            return out.toByteArray();
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        compileSources();
+        Lookup lookup = MethodHandles.lookup();
+        byte[] bytes = readClassFile();
+        Class<?> c;
+        if (args.length > 0) {
+            System.out.println("Defining an anonymous class");
+            c = Unsafe.getUnsafe().defineAnonymousClass(klass, bytes, null);
+        } else {
+            System.out.println("Creating a nonfindable class");
+            c = lookup.defineClass(bytes, NESTMATE, HIDDEN);
+        }
+        Test t = (Test) c.newInstance();
+        t.test();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/defineClass/nonFindable/NonFindable.java	Tue Feb 26 13:11:28 2019 -0500
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ *  The classfile for this class will be loaded directly and used to define
+ *  either a non-findable or anonymous class.
+ */
+public class NonFindable implements Test {
+
+    NonFindable other = null;
+
+    private void realTest() {
+        other = this;  // test verification of putfield
+        Object o = other;
+        NonFindable local = this;
+        local = other;
+        local = (NonFindable) o;
+        local = new NonFindable();
+        other = local;
+
+        set_other(local); // method signature test
+        set_other(null);
+
+        local = getThis();
+
+        set_other_maybe(new Object());
+        set_other_maybe(this);
+        if (other != this)
+            throw new Error("set_other_maybe didn't work!");
+        if (other == this) {
+            try {
+                throw new Error("threw an exception");
+            } catch (Error e) {
+            }
+        }
+    }
+
+    private NonFindable getThis() {
+        return this; // areturn test
+    }
+
+    private void set_other(NonFindable t) {
+        other = t;
+    }
+
+    private void set_other_maybe(Object o) {
+        if (o instanceof NonFindable) {
+         other = (NonFindable) o;
+        }
+    }
+
+    public void test() {
+        realTest();
+    }
+}