8236075: Minor bootstrap improvements

Reviewed-by: mchung, alanb
This commit is contained in:
Claes Redestad 2020-01-21 13:28:15 +01:00
parent 3cf8b34d54
commit c639682887
10 changed files with 208 additions and 145 deletions

View File

@ -1564,7 +1564,7 @@ void SystemDictionary::define_instance_class(InstanceKlass* k, TRAPS) {
unsigned int d_hash = dictionary->compute_hash(name_h);
check_constraints(d_hash, k, class_loader_h, true, CHECK);
// Register class just loaded with class loader (placed in Vector)
// Register class just loaded with class loader (placed in ArrayList)
// Note we do this before updating the dictionary, as this can
// fail with an OutOfMemoryError (if it does, we will *not* put this
// class in the dictionary and will not update the class hierarchy).

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -31,11 +31,6 @@ class ClassLoaderHelper {
private ClassLoaderHelper() {}
/**
* Indicates, whether PATH env variable is allowed to contain quoted entries.
*/
static final boolean allowsQuotedPathElements = false;
/**
* Returns an alternate path name for the given file
* such that if the original pathname did not exist, then the
@ -50,4 +45,25 @@ class ClassLoaderHelper {
}
return new File(name.substring(0, index) + ".jnilib");
}
/**
* Parse a PATH env variable.
*
* Empty elements will be replaced by dot.
*/
static String[] parsePath(String ldPath) {
char ps = File.pathSeparatorChar;
ArrayList<String> paths = new ArrayList<>();
int pathStart = 0;
int pathEnd;
while ((pathEnd = ldPath.indexOf(ps, pathStart)) >= 0) {
paths.add((pathStart < pathEnd) ?
ldPath.substring(pathStart, pathEnd) : ".");
pathStart = pathEnd + 1;
}
int ldLen = ldPath.length();
paths.add((pathStart < ldLen) ?
ldPath.substring(pathStart, ldLen) : ".");
return paths.toArray(new String[paths.size()]);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -40,20 +40,19 @@ import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.security.cert.Certificate;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
@ -69,6 +68,7 @@ import jdk.internal.misc.VM;
import jdk.internal.ref.CleanerFactory;
import jdk.internal.reflect.CallerSensitive;
import jdk.internal.reflect.Reflection;
import jdk.internal.util.StaticProperty;
import sun.reflect.misc.ReflectUtil;
import sun.security.util.SecurityConstants;
@ -303,14 +303,14 @@ public abstract class ClassLoader {
private final ConcurrentHashMap<String, Object> parallelLockMap;
// Maps packages to certs
private final Map <String, Certificate[]> package2certs;
private final ConcurrentHashMap<String, Certificate[]> package2certs;
// Shared among all packages with unsigned classes
private static final Certificate[] nocerts = new Certificate[0];
// The classes loaded by this class loader. The only purpose of this table
// is to keep the classes from being GC'ed until the loader is GC'ed.
private final Vector<Class<?>> classes = new Vector<>();
private final ArrayList<Class<?>> classes = new ArrayList<>();
// The "default" domain. Set as the default ProtectionDomain on newly
// created classes.
@ -320,7 +320,9 @@ public abstract class ClassLoader {
// Invoked by the VM to record every loaded class with this loader.
void addClass(Class<?> c) {
classes.addElement(c);
synchronized (classes) {
classes.add(c);
}
}
// The packages defined in this class loader. Each package name is
@ -378,14 +380,13 @@ public abstract class ClassLoader {
this.unnamedModule = new Module(this);
if (ParallelLoaders.isRegistered(this.getClass())) {
parallelLockMap = new ConcurrentHashMap<>();
package2certs = new ConcurrentHashMap<>();
assertionLock = new Object();
} else {
// no finer-grained lock; lock on the classloader instance
parallelLockMap = null;
package2certs = new Hashtable<>();
assertionLock = this;
}
this.package2certs = new ConcurrentHashMap<>();
this.nameAndId = nameAndId(this);
}
@ -1135,18 +1136,8 @@ public abstract class ClassLoader {
if (cs != null) {
certs = cs.getCertificates();
}
Certificate[] pcerts = null;
if (parallelLockMap == null) {
synchronized (this) {
pcerts = package2certs.get(pname);
if (pcerts == null) {
package2certs.put(pname, (certs == null? nocerts:certs));
}
}
} else {
pcerts = ((ConcurrentHashMap<String, Certificate[]>)package2certs).
putIfAbsent(pname, (certs == null? nocerts:certs));
}
certs = certs == null ? nocerts : certs;
Certificate[] pcerts = package2certs.putIfAbsent(pname, certs);
if (pcerts != null && !compareCerts(pcerts, certs)) {
throw new SecurityException("class \"" + name
+ "\"'s signer information does not match signer information"
@ -1158,13 +1149,10 @@ public abstract class ClassLoader {
* check to make sure the certs for the new class (certs) are the same as
* the certs for the first class inserted in the package (pcerts)
*/
private boolean compareCerts(Certificate[] pcerts,
Certificate[] certs)
{
// certs can be null, indicating no certs.
if ((certs == null) || (certs.length == 0)) {
private boolean compareCerts(Certificate[] pcerts, Certificate[] certs) {
// empty array fast-path
if (certs.length == 0)
return pcerts.length == 0;
}
// the length must be the same at this point
if (certs.length != pcerts.length)
@ -2005,17 +1993,6 @@ public abstract class ClassLoader {
return scl;
}
/*
* Initialize default paths for native libraries search.
* Must be done early as JDK may load libraries during bootstrap.
*
* @see java.lang.System#initPhase1
*/
static void initLibraryPaths() {
usr_paths = initializePath("java.library.path");
sys_paths = initializePath("sun.boot.library.path");
}
// Returns true if the specified class loader can be found in this class
// loader's delegation chain.
boolean isAncestor(ClassLoader cl) {
@ -2570,59 +2547,17 @@ public abstract class ClassLoader {
static native void unload(String name, boolean isBuiltin, long handle);
}
// The paths searched for libraries
private static String usr_paths[];
private static String sys_paths[];
private static String[] initializePath(String propName) {
String ldPath = System.getProperty(propName, "");
int ldLen = ldPath.length();
char ps = File.pathSeparatorChar;
int psCount = 0;
if (ClassLoaderHelper.allowsQuotedPathElements &&
ldPath.indexOf('\"') >= 0) {
// First, remove quotes put around quoted parts of paths.
// Second, use a quotation mark as a new path separator.
// This will preserve any quoted old path separators.
char[] buf = new char[ldLen];
int bufLen = 0;
for (int i = 0; i < ldLen; ++i) {
char ch = ldPath.charAt(i);
if (ch == '\"') {
while (++i < ldLen &&
(ch = ldPath.charAt(i)) != '\"') {
buf[bufLen++] = ch;
}
} else {
if (ch == ps) {
psCount++;
ch = '\"';
}
buf[bufLen++] = ch;
}
}
ldPath = new String(buf, 0, bufLen);
ldLen = bufLen;
ps = '\"';
} else {
for (int i = ldPath.indexOf(ps); i >= 0;
i = ldPath.indexOf(ps, i + 1)) {
psCount++;
}
}
String[] paths = new String[psCount + 1];
int pathStart = 0;
for (int j = 0; j < psCount; ++j) {
int pathEnd = ldPath.indexOf(ps, pathStart);
paths[j] = (pathStart < pathEnd) ?
ldPath.substring(pathStart, pathEnd) : ".";
pathStart = pathEnd + 1;
}
paths[psCount] = (pathStart < ldLen) ?
ldPath.substring(pathStart, ldLen) : ".";
return paths;
/**
* Holds system and user library paths derived from the
* {@code java.library.path} and {@code sun.boot.library.path} system
* properties. The system properties are eagerly read at bootstrap, then
* lazily parsed on first use to avoid initialization ordering issues.
*/
private static class LibraryPaths {
static final String[] USER =
ClassLoaderHelper.parsePath(StaticProperty.javaLibraryPath());
static final String[] SYS =
ClassLoaderHelper.parsePath(StaticProperty.sunBootLibraryPath());
}
// Invoked in the java.lang.Runtime class to implement load and loadLibrary.
@ -2630,8 +2565,6 @@ public abstract class ClassLoader {
boolean isAbsolute) {
ClassLoader loader =
(fromClass == null) ? null : fromClass.getClassLoader();
assert sys_paths != null : "should be initialized at this point";
assert usr_paths != null : "should be initialized at this point";
if (isAbsolute) {
if (loadLibrary0(fromClass, new File(name))) {
@ -2653,8 +2586,8 @@ public abstract class ClassLoader {
throw new UnsatisfiedLinkError("Can't load " + libfilename);
}
}
for (String sys_path : sys_paths) {
File libfile = new File(sys_path, System.mapLibraryName(name));
for (String sysPath : LibraryPaths.SYS) {
File libfile = new File(sysPath, System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
@ -2664,8 +2597,8 @@ public abstract class ClassLoader {
}
}
if (loader != null) {
for (String usr_path : usr_paths) {
File libfile = new File(usr_path, System.mapLibraryName(name));
for (String userPath : LibraryPaths.USER) {
File libfile = new File(userPath, System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
@ -2677,7 +2610,7 @@ public abstract class ClassLoader {
}
// Oops, it failed
throw new UnsatisfiedLinkError("no " + name +
" in java.library.path: " + Arrays.toString(usr_paths));
" in java.library.path: " + Arrays.toString(LibraryPaths.USER));
}
private static native String findBuiltinLib(String name);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@ -2043,8 +2043,6 @@ public final class System {
// register shared secrets
setJavaLangAccess();
ClassLoader.initLibraryPaths();
// Subsystems that are invoked during initialization can invoke
// VM.isBooted() in order to avoid doing things that should
// wait until the VM is fully initialized. The initialization level

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -198,22 +198,23 @@ public class BuiltinClassLoader
* types in the module visible.
*/
public void loadModule(ModuleReference mref) {
String mn = mref.descriptor().name();
ModuleDescriptor descriptor = mref.descriptor();
String mn = descriptor.name();
if (nameToModule.putIfAbsent(mn, mref) != null) {
throw new InternalError(mn + " already defined to this loader");
}
LoadedModule loadedModule = new LoadedModule(this, mref);
for (String pn : mref.descriptor().packages()) {
for (String pn : descriptor.packages()) {
LoadedModule other = packageToModule.putIfAbsent(pn, loadedModule);
if (other != null) {
throw new InternalError(pn + " in modules " + mn + " and "
+ other.mref().descriptor().name());
+ other.name());
}
}
// clear resources cache if VM is already initialized
if (VM.isModuleSystemInited() && resourceCache != null) {
if (resourceCache != null && VM.isModuleSystemInited()) {
resourceCache = null;
}
}
@ -408,8 +409,11 @@ public class BuiltinClassLoader
SoftReference<Map<String, List<URL>>> ref = this.resourceCache;
Map<String, List<URL>> map = (ref != null) ? ref.get() : null;
if (map == null) {
map = new ConcurrentHashMap<>();
this.resourceCache = new SoftReference<>(map);
// only cache resources after VM is fully initialized
if (VM.isModuleSystemInited()) {
map = new ConcurrentHashMap<>();
this.resourceCache = new SoftReference<>(map);
}
} else {
List<URL> urls = map.get(name);
if (urls != null)
@ -444,7 +448,7 @@ public class BuiltinClassLoader
}
// only cache resources after VM is fully initialized
if (VM.isModuleSystemInited()) {
if (map != null) {
map.putIfAbsent(name, urls);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -25,6 +25,8 @@
package jdk.internal.util;
import java.util.Properties;
/**
* System Property access for internal use only.
* Read-only access to System property values initialized during Phase 1
@ -38,22 +40,41 @@ public final class StaticProperty {
// The class static initialization is triggered to initialize these final
// fields during init Phase 1 and before a security manager is set.
private static final String JAVA_HOME = initProperty("java.home");
private static final String USER_HOME = initProperty("user.home");
private static final String USER_DIR = initProperty("user.dir");
private static final String USER_NAME = initProperty("user.name");
private static final String JDK_SERIAL_FILTER = System.getProperty("jdk.serialFilter");
private static final String JAVA_HOME;
private static final String USER_HOME;
private static final String USER_DIR;
private static final String USER_NAME;
private static final String JAVA_LIBRARY_PATH;
private static final String SUN_BOOT_LIBRARY_PATH;
private static final String JDK_SERIAL_FILTER;
private StaticProperty() {}
private static String initProperty(String key) {
String v = System.getProperty(key);
static {
Properties props = System.getProperties();
JAVA_HOME = getProperty(props, "java.home");
USER_HOME = getProperty(props, "user.home");
USER_DIR = getProperty(props, "user.dir");
USER_NAME = getProperty(props, "user.name");
JAVA_LIBRARY_PATH = getProperty(props, "java.library.path", "");
SUN_BOOT_LIBRARY_PATH = getProperty(props, "sun.boot.library.path", "");
JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null);
}
private static String getProperty(Properties props, String key) {
String v = props.getProperty(key);
if (v == null) {
throw new InternalError("null property: " + key);
}
return v;
}
private static String getProperty(Properties props, String key,
String defaultVal) {
String v = props.getProperty(key);
return (v == null) ? defaultVal : v;
}
/**
* Return the {@code java.home} system property.
*
@ -106,6 +127,33 @@ public final class StaticProperty {
return USER_NAME;
}
/**
* Return the {@code java.library.path} system property.
*
* <strong>{@link SecurityManager#checkPropertyAccess} is NOT checked
* in this method. The caller of this method should take care to ensure
* that the returned property is not made accessible to untrusted code.</strong>
*
* @return the {@code java.library.path} system property
*/
public static String javaLibraryPath() {
return JAVA_LIBRARY_PATH;
}
/**
* Return the {@code sun.boot.library.path} system property.
*
* <strong>{@link SecurityManager#checkPropertyAccess} is NOT checked
* in this method. The caller of this method should take care to ensure
* that the returned property is not made accessible to untrusted code.</strong>
*
* @return the {@code sun.boot.library.path} system property
*/
public static String sunBootLibraryPath() {
return SUN_BOOT_LIBRARY_PATH;
}
/**
* Return the {@code jdk.serialFilter} system property.
*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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,16 +26,12 @@
package java.lang;
import java.io.File;
import java.util.ArrayList;
class ClassLoaderHelper {
private ClassLoaderHelper() {}
/**
* Indicates, whether PATH env variable is allowed to contain quoted entries.
*/
static final boolean allowsQuotedPathElements = false;
/**
* Returns an alternate path name for the given file
* such that if the original pathname did not exist, then the
@ -45,4 +41,25 @@ class ClassLoaderHelper {
static File mapAlternativeName(File lib) {
return null;
}
/**
* Parse a PATH env variable.
*
* Empty elements will be replaced by dot.
*/
static String[] parsePath(String ldPath) {
char ps = File.pathSeparatorChar;
ArrayList<String> paths = new ArrayList<>();
int pathStart = 0;
int pathEnd;
while ((pathEnd = ldPath.indexOf(ps, pathStart)) >= 0) {
paths.add((pathStart < pathEnd) ?
ldPath.substring(pathStart, pathEnd) : ".");
pathStart = pathEnd + 1;
}
int ldLen = ldPath.length();
paths.add((pathStart < ldLen) ?
ldPath.substring(pathStart, ldLen) : ".");
return paths.toArray(new String[paths.size()]);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 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
@ -31,11 +31,6 @@ class ClassLoaderHelper {
private ClassLoaderHelper() {}
/**
* Indicates, whether PATH env variable is allowed to contain quoted entries.
*/
static final boolean allowsQuotedPathElements = true;
/**
* Returns an alternate path name for the given file
* such that if the original pathname did not exist, then the
@ -45,4 +40,59 @@ class ClassLoaderHelper {
static File mapAlternativeName(File lib) {
return null;
}
/**
* Parse a PATH env variable. Windows allows quoted elements in a PATH,
* so special care needs to be taken.
*
* Empty elements will be replaced by dot.
*/
static String[] parsePath(String ldPath) {
int ldLen = ldPath.length();
char ps = File.pathSeparatorChar;
int psCount = 0;
if (ldPath.indexOf('\"') >= 0) {
// First, remove quotes put around quoted parts of paths.
// Second, use a quotation mark as a new path separator.
// This will preserve any quoted old path separators.
char[] buf = new char[ldLen];
int bufLen = 0;
for (int i = 0; i < ldLen; ++i) {
char ch = ldPath.charAt(i);
if (ch == '\"') {
while (++i < ldLen &&
(ch = ldPath.charAt(i)) != '\"') {
buf[bufLen++] = ch;
}
} else {
if (ch == ps) {
psCount++;
ch = '\"';
}
buf[bufLen++] = ch;
}
}
ldPath = new String(buf, 0, bufLen);
ldLen = bufLen;
ps = '\"';
} else {
for (int i = ldPath.indexOf(ps); i >= 0;
i = ldPath.indexOf(ps, i + 1)) {
psCount++;
}
}
String[] paths = new String[psCount + 1];
int pathStart = 0;
for (int j = 0; j < psCount; ++j) {
int pathEnd = ldPath.indexOf(ps, pathStart);
paths[j] = (pathStart < pathEnd) ?
ldPath.substring(pathStart, pathEnd) : ".";
pathStart = pathEnd + 1;
}
paths[psCount] = (pathStart < ldLen) ?
ldPath.substring(pathStart, ldLen) : ".";
return paths;
}
}

View File

@ -62,7 +62,7 @@ public class TestInstanceKlassSize {
public static WhiteBox wb = WhiteBox.getWhiteBox();
private static String[] SAInstanceKlassNames = new String[] {
"java.lang.Object",
"java.util.Vector",
"java.util.ArrayList",
"java.lang.String",
"java.lang.Thread",
"java.lang.Byte"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -23,8 +23,8 @@
/*
* @test
* @bug 8067951
* @summary Unit test for internal ClassLoader#initializePath().
* @bug 8067951 8236075
* @summary Unit test for internal ClassLoaderHelper#parsePath().
* Quoted entries should get unquoted on Windows.
* Empty entries should be replaced with dot.
* @library /test/lib
@ -40,14 +40,12 @@ import jdk.test.lib.Platform;
public class LibraryPathProperty {
static final String propName = "test.property.name";
static final String SP = File.pathSeparator;
static Method method;
public static void main(String[] args) throws Throwable {
method = ClassLoader.class
.getDeclaredMethod("initializePath",
String.class);
Class<?> klass = Class.forName("java.lang.ClassLoaderHelper");
method = klass.getDeclaredMethod("parsePath", String.class);
method.setAccessible(true);
test("", ".");
@ -74,8 +72,7 @@ public class LibraryPathProperty {
}
static void test(String s, String... expected) throws Throwable {
System.setProperty(propName, s);
String[] res = (String[])method.invoke(null, propName);
String[] res = (String[])method.invoke(null, s);
if (!Arrays.asList(res).equals(Arrays.asList(expected))) {
throw new RuntimeException("Parsing [" + s + "] " +
" result " + Arrays.asList(res) +