Skip to content
This repository has been archived by the owner. It is now read-only.
Permalink
Browse files
8243586: Optimize calls to SystemDictionaryShared::define_shared_pack…
…age 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
  • Loading branch information
calvinccheung committed Jul 1, 2020
1 parent 4b85bd5 commit dc74336a65fdded28c7951c912605bc2211cc9fc
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 22 deletions.
@@ -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,13 +115,16 @@ class PackageEntry : public HashtableEntry<Symbol*, mtModule> {
// 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;
_export_flags = 0;
_classpath_index = -1;
_must_walk_exports = false;
_qualified_exports = NULL;
_defined_by_cds_in_class_path = 0;
}

// package name
@@ -212,6 +216,24 @@ class PackageEntry : public HashtableEntry<Symbol*, mtModule> {

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
@@ -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));
}
}
@@ -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,24 +37,57 @@

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;

// 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");
}
}
@@ -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 {
}
@@ -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 {
}
@@ -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 @@

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);
}

@@ -1,6 +1,6 @@
Manifest-Version: 1.0
Created-By: 1.9.0-internal (Oracle Corporation)

Name: sealed/pkg/
Name: foo/
Sealed: true

0 comments on commit dc74336

Please sign in to comment.