8243586: Optimize calls to SystemDictionaryShared::define_shared_package for classpath

Define_shared_package only needs to be called once for each package in a jar specified in the shared class path.

Reviewed-by: iklam, dholmes, minqi
This commit is contained in:
Calvin Cheung 2020-07-01 21:05:14 +00:00
parent 4b85bd546e
commit dc74336a65
7 changed files with 118 additions and 22 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2020, 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
@ -27,6 +27,7 @@
#include "classfile/moduleEntry.hpp"
#include "oops/symbol.hpp"
#include "runtime/atomic.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/macros.hpp"
@ -114,6 +115,8 @@ private:
// Initial size of a package entry's list of qualified exports.
enum {QUAL_EXP_SIZE = 43};
// a bit map indicating which CDS classpath entries have defined classes in this package.
volatile int _defined_by_cds_in_class_path;
public:
void init() {
_module = NULL;
@ -121,6 +124,7 @@ public:
_classpath_index = -1;
_must_walk_exports = false;
_qualified_exports = NULL;
_defined_by_cds_in_class_path = 0;
}
// package name
@ -212,6 +216,24 @@ public:
void print(outputStream* st = tty);
void verify();
static int max_index_for_defined_in_class_path() {
return sizeof(int) * BitsPerByte;
}
bool is_defined_by_cds_in_class_path(int idx) const {
assert(idx < max_index_for_defined_in_class_path(), "sanity");
return((Atomic::load(&_defined_by_cds_in_class_path) & ((int)1 << idx)) != 0);
}
void set_defined_by_cds_in_class_path(int idx) {
assert(idx < max_index_for_defined_in_class_path(), "sanity");
int old_val = 0;
int new_val = 0;
do {
old_val = Atomic::load(&_defined_by_cds_in_class_path);
new_val = old_val | ((int)1 << idx);
} while (Atomic::cmpxchg(&_defined_by_cds_in_class_path, old_val, new_val) != old_val);
}
};
// The PackageEntryTable is a Hashtable containing a list of all packages defined

View File

@ -872,7 +872,19 @@ Handle SystemDictionaryShared::init_security_info(Handle class_loader, InstanceK
// the corresponding SystemDictionaryShared::get_shared_xxx() function.
Handle manifest = get_shared_jar_manifest(index, CHECK_(pd));
Handle url = get_shared_jar_url(index, CHECK_(pd));
define_shared_package(class_name, class_loader, manifest, url, CHECK_(pd));
int index_offset = index - ClassLoaderExt::app_class_paths_start_index();
if (index_offset < PackageEntry::max_index_for_defined_in_class_path()) {
if (pkg_entry == NULL || !pkg_entry->is_defined_by_cds_in_class_path(index_offset)) {
// define_shared_package only needs to be called once for each package in a jar specified
// in the shared class path.
define_shared_package(class_name, class_loader, manifest, url, CHECK_(pd));
if (pkg_entry != NULL) {
pkg_entry->set_defined_by_cds_in_class_path(index_offset);
}
}
} else {
define_shared_package(class_name, class_loader, manifest, url, CHECK_(pd));
}
pd = get_shared_protection_domain(class_loader, index, url, CHECK_(pd));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -27,10 +27,8 @@
* @summary AppCDS handling of package.
* @requires vm.cds
* @library /test/lib
* @compile test-classes/C1.java
* @compile test-classes/C2.java
* @compile test-classes/PackageSealingTest.java
* @compile test-classes/Hello.java
* @compile test-classes/C1.java test-classes/C2.java test-classes/C3.java
* test-classes/PackageSealingTest.java test-classes/Hello.java
* @run driver PackageSealing
*/
@ -39,10 +37,10 @@ import jdk.test.lib.process.OutputAnalyzer;
public class PackageSealing {
public static void main(String args[]) throws Exception {
String[] classList = {"sealed/pkg/C1", "pkg/C2", "PackageSealingTest"};
String appJar = ClassFileInstaller.writeJar("pkg_seal.jar",
String[] classList = {"foo/C1", "pkg/C2", "PackageSealingTest"};
String appJar = ClassFileInstaller.writeJar("foo-sealed.jar",
ClassFileInstaller.Manifest.fromSourceFile("test-classes/package_seal.mf"),
"PackageSealingTest", "sealed/pkg/C1", "pkg/C2");
"PackageSealingTest", "foo/C1", "pkg/C2");
String helloJar = JarBuilder.getOrCreateHelloJar();
String jars = helloJar + File.pathSeparator + appJar;
@ -50,13 +48,46 @@ public class PackageSealing {
// test shared package from -cp path
TestCommon.testDump(jars, TestCommon.list(classList));
OutputAnalyzer output;
output = TestCommon.exec(jars, "PackageSealingTest");
output = TestCommon.exec(jars, "PackageSealingTest",
"foo/C1", "sealed", "pkg/C2", "notSealed");
TestCommon.checkExec(output, "OK");
// test shared package from -Xbootclasspath/a
TestCommon.dump(helloJar, TestCommon.list(classList),
"-Xbootclasspath/a:" + appJar);
output = TestCommon.exec(helloJar, "-Xbootclasspath/a:" + appJar, "PackageSealingTest");
output = TestCommon.exec(helloJar, "-Xbootclasspath/a:" + appJar,
"PackageSealingTest",
"foo/C1", "sealed", "pkg/C2", "notSealed");
TestCommon.checkExec(output, "OK");
// Test loading of two classes from the same package from different jars.
// First loaded class is from a non-sealed package, the second loaded
// class is from the same package but sealed.
// The expected result is a SecurityException with a "sealing violation"
// for the second class.
classList[1] = "foo/C3"; // C3 is from a non-sealed package
String[] classList2 = {"foo/C3", "foo/C1", "PackageSealingTest"};
String nonSealedJar = ClassFileInstaller.writeJar("foo-unsealed.jar", "foo/C3");
jars = helloJar + File.pathSeparator + nonSealedJar;
TestCommon.testDump(jars, TestCommon.list(classList2));
jars += File.pathSeparator + appJar;
output = TestCommon.exec(jars, "-Xlog:class+load", "PackageSealingTest",
"foo/C3", "notSealed", "foo/C1", "sealed");
TestCommon.checkExec(output,
"foo.C3 source: shared objects file",
"sealing violation: can't seal package foo: already defined");
// Use the jar with the sealed package during dump time.
// Reverse the class loading order during runtime: load the class in the
// sealed package following by another class in the same package but unsealed.
// Same "sealing violation should result in loading the second class.
jars = helloJar + File.pathSeparator + appJar;
TestCommon.testDump(jars, TestCommon.list(classList2));
jars += File.pathSeparator + nonSealedJar;
output = TestCommon.exec(jars, "-Xlog:class+load", "PackageSealingTest",
"foo/C1", "sealed", "foo/C3", "notSealed");
TestCommon.checkExec(output,
"foo.C1 source: shared objects file",
"sealing violation: package foo is sealed");
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -22,7 +22,7 @@
*
*/
package sealed.pkg;
package foo;
public class C1 {
}

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2020, 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.
*
*/
package foo;
public class C3 {
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2020, 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
@ -26,21 +26,24 @@ import java.lang.Package;
public class PackageSealingTest {
public static void main(String args[]) {
if (args.length != 4) {
throw new RuntimeException("Expecting 4 arguments");
}
try {
Class c1 = PackageSealingTest.class.forName("sealed.pkg.C1");
Class c2 = PackageSealingTest.class.forName("pkg.C2");
Class c1 = PackageSealingTest.class.forName(args[0].replace('/', '.'));
Class c2 = PackageSealingTest.class.forName(args[2].replace('/', '.'));
Package p1 = c1.getPackage();
System.out.println("Package 1: " + p1.toString());
Package p2 = c2.getPackage();
System.out.println("Package 2: " + p2.toString());
if (!p1.isSealed()) {
System.out.println("Failed: sealed.pkg is not sealed.");
if (args[1].equals("sealed") && !p1.isSealed()) {
System.out.println("Failed: " + p1.toString() + " is not sealed.");
System.exit(0);
}
if (p2.isSealed()) {
System.out.println("Failed: pkg is sealed.");
if (args[3].equals("notSealed") && p2.isSealed()) {
System.out.println("Failed: " + p2.toString() + " is sealed.");
System.exit(0);
}

View File

@ -1,6 +1,6 @@
Manifest-Version: 1.0
Created-By: 1.9.0-internal (Oracle Corporation)
Name: sealed/pkg/
Name: foo/
Sealed: true