Initial webrev with changes for JDK 9
Paul Sandoz
paul.sandoz at oracle.com
Fri Mar 11 16:50:34 UTC 2016
> On 11 Mar 2016, at 10:39, Alan Bateman <Alan.Bateman at oracle.com> wrote:
>
>
> I've refreshed the webrevs here:
> http://cr.openjdk.java.net/~alanb/8142968/2
>
I browsed the code. Generally the feeling i get is it’s of good quality. Previously some of this area was quite legacy and it is refreshing to view more modern code.
Comments below, only the first is something i think we should really change, the others are up to you.
Once Jigsaw goes in i wonder if we should opportunistically revisit the use of URL and Enumeration with class loaders?
Paul.
sun/util/locale/provider/ResourceBundleProviderSupport.java
—
72 // java.base may not be able to read the bundleClass's module.
73 PrivilegedAction<Void> pa1 = () -> { ctor.setAccessible(true); return null; };
74 AccessController.doPrivileged(pa1);
75 try {
76 return ctor.newInstance((Object[]) null);
77 } catch (InvocationTargetException e) {
78 Unsafe.getUnsafe().throwException(e.getTargetException());
79 } catch (InstantiationException | IllegalAccessException e) {
80 throw new InternalError(e);
81 }
82 } catch (NoSuchMethodException e) {
83 }
84 }
85 return null;
86 }
Please avoid the use of Unsafe here, use a sneaky throw instead if necessary, or wrap.
That Unsafe method needs to die!
j.l.Class
—
2476 @CallerSensitive
2477 public URL getResource(String name) {
2478 name = resolveName(name);
2479
2480 // if this Class and the caller are in the same named module
2481 // then attempt to get URL to the resource in the module
2482 Module module = getModule();
2483 if (module.isNamed()) {
2484 Class<?> caller = Reflection.getCallerClass();
2485 if (caller != null && caller.getModule() == module) {
2486 String mn = getModule().getName();
2487 ClassLoader cl = getClassLoader0();
2488 try {
2489 if (cl == null) {
2490 return BootLoader.findResource(mn, name);
2491 } else {
2492 return cl.findResource(mn, name);
2493 }
2494 } catch (IOException ioe) {
2495 return null;
2496 }
2497 }
2498 }
The method getResourceAsStream has an optimisation for a BuiltinClassLoader:
2412 // special-case built-in class loaders to avoid the
2413 // need for a URL connection
2414 if (cl == null) {
2415 return BootLoader.findResourceAsStream(mn, name);
2416 } else if (cl instanceof BuiltinClassLoader) {
2417 return ((BuiltinClassLoader) cl).findResourceAsStream(mn, name);
2418 } else {
2419 URL url = cl.findResource(mn, name);
2420 return (url != null) ? url.openStream() : null;
2421 }
Is that something you plan to include for getResource too at some point?
j.l.ClassLoader
—
1777 // define Package object if the named package is not yet defined
1778 NamedPackage p = packages.computeIfAbsent(name,
1779 k -> NamedPackage.toPackage(name, m));
1780 if (p instanceof Package)
1781 return (Package)p;
1782
1783 // otherwise, replace the NamedPackage object with Package object
1784 return (Package)packages.compute(name, this::toPackage);
You could merge the computeIfAbsent and compute into a single compute call if you so wish.
return (Package)packages.compute((n, p) -> {
// define Package object if the named package is not yet defined
if (p == null) return NamedPackage.toPackage(name, m);
// otherwise, replace the NamedPackage object with Package object
return (p instanceof Package) ? p : toPackage(n, p);
});
2553 /**
2554 * Returns the ServiceCatalog for modules defined to this class loader,
2555 * creating it if it doesn't already exist.
2556 */
2557 ServicesCatalog createOrGetServicesCatalog() {
2558 ServicesCatalog catalog = servicesCatalog;
2559 if (catalog == null) {
2560 catalog = new ServicesCatalog();
2561 boolean set = trySetObjectField("servicesCatalog", catalog);
2562 if (!set) {
2563 // beaten by someone else
2564 catalog = servicesCatalog;
2565 }
2566 }
2567 return catalog;
2568 }
2569
2570 // the ServiceCatalog for modules associated with this class loader.
2571 private volatile ServicesCatalog servicesCatalog;
2572
2573
2574 /**
2575 * Attempts to atomically set a volatile field in this object. Returns
2576 * {@code true} if not beaten by another thread. Avoids the use of
2577 * AtomicReferenceFieldUpdater in this class.
2578 */
2579 private boolean trySetObjectField(String name, Object obj) {
2580 Unsafe unsafe = Unsafe.getUnsafe();
2581 Class<?> k = ClassLoader.class;
2582 long offset;
2583 try {
2584 Field f = k.getDeclaredField(name);
2585 offset = unsafe.objectFieldOffset(f);
2586 } catch (NoSuchFieldException e) {
2587 throw new InternalError(e);
2588 }
2589 return unsafe.compareAndSwapObject(this, offset, null, obj);
2590 }
If you can syncrhonize on this, just use double checked locking?
j.l.i.BoundMethodHandle
—
791 // ## FIXME
792 // assert F_SPECIES_DATA.getDeclaredAnnotation(Stable.class) != null;
That’s odd. Why did that need commenting out?
MethodHandles
—
That’s quite some trick to create PUBLIC_LOOKUP :-) spinning up a new class (“Unamed”) in a new class loader. If that mechanism is gonna stay and If there are costs associated with that, we could easily skip the ASM part and use hard coded bytes.
j.l.r.Proxy
—
636 private static final WeakCache<Module, List<Class<?>>, Class<?>> proxyCache =
637 new WeakCache<>(new KeyFactory<Module>(),
638 new BiFunction<Module, List<Class<?>>, Class<?>>() {
639 @Override
640 public Class<?> apply(Module m, List<Class<?>> interfaces) {
641 Objects.requireNonNull(m);
642 return defineProxyClass(m, interfaces);
643 }
644 });
Wild idea: this feels like an equivalent of j.l.i.ClassValue for Module.
781 static Set<Class<?>> referencedTypes(ClassLoader loader, List<Class<?>> interfaces) {
782 Set<Class<?>> types = new HashSet<>();
783 for (Class<?> intf : interfaces) {
784 for (Method m : intf.getMethods()) {
785 // return type, parameter types, and exception types
786 Stream.concat(Stream.concat(Stream.of(m.getReturnType()),
787 Arrays.stream(m.getParameterTypes())),
788 Arrays.stream(m.getExceptionTypes()))
789 .map(ProxyBuilder::getElementType)
790 .filter(t -> !t.isPrimitive())
791 .forEach(types::add);
792 }
793 }
794 return types;
795 }
Use Stream.flatMap e.g.
interfaces.stream().flatMap(i -> Stream.of(i.getMethods()).
flatMap(m -> f(m) /*extract all types on method*/).
map(…).filter(…).collect(toSet())
Stream<Class<?>> f(Method m) {
return Stream.of(new Class[] {m.getReturnType()}, m.getParameterTypes(), m.getExceptionTypes()).
flatMap(a -> Stream.of(a));
}
939 private static final WeakHashMap<ClassLoader, Module> dynProxyModules = new WeakHashMap<>();
940 private static final AtomicInteger counter = new AtomicInteger();
941
942 /*
943 * Define a dynamic module for the generated proxy classes in a non-exported package
944 * named com.sun.proxy.$MODULE.
945 *
946 * Each class loader will have one dynamic module.
947 */
948 static synchronized Module getDynamicModule(ClassLoader loader) {
949 Module m = dynProxyModules.get(loader);
950 if (m == null) {
951 String mn = "jdk.proxy" + counter.incrementAndGet();
952 String pn = PROXY_PACKAGE_PREFIX + "." + mn;
953 m = Modules.defineModule(loader, mn, Collections.singleton(pn));
954 Modules.addReads(m, Proxy.class.getModule());
955 // java.base to create proxy instance
956 Modules.addExports(m, pn, Object.class.getModule());
957 dynProxyModules.put(loader, m);
958 }
959 return m;
960 }
Consider using computeIfAbsent. At the moment no need for AtomicInteger.
1055 @CallerSensitive
1056 public static Object newProxyInstance(ClassLoader loader,
1057 Class<?>[] interfaces,
1058 InvocationHandler h) {
1059 Objects.requireNonNull(h);
1060
1061 final List<Class<?>> intfs = Arrays.asList(interfaces.clone());
Use List.of, which will also clone? This presumes that there are no null values in the array.
sun.invoke.util.VerifyAccess
—
198 while (c.isArray()) {
199 c = c.getComponentType();
200 }
This pattern is occurring a number of times.
Memo: add a method on Arrays, or somewhere…,
sun.net.www.protocol.jrt.JavaRuntimeURLConnection
—
56 private static final ImageReader reader = ImageReaderFactory.getImageReader();
reader -> READER
sun.util.resources.LocaleData
—
77 private static final Map<String, List<Locale>> candidatesMap = new ConcurrentHashMap<>();
candidatesMap -> CANDIDATES_MAP
native/libjimage/imageDecompressor.cpp
—
114 // Sparc to read unaligned content
115 // u8 l = (*(u8*) ptr);
116 // If ptr is not aligned, sparc will fail.
117 u8 ImageDecompressor::getU8(u1* ptr, Endian *endian) {
118 u8 ret;
119 if (endian->is_big_endian()) {
120 ret = (u8)ptr[0] << 56 | (u8)ptr[1] << 48 | (u8)ptr[2]<<40 | (u8)ptr[3]<<32 |
121 ptr[4]<<24 | ptr[5]<<16 | ptr[6]<<8 | ptr[7];
122 } else {
123 ret = ptr[0] | ptr[1]<<8 | ptr[2]<<16 | ptr[3]<<24 | (u8)ptr[4]<<32 |
124 (u8)ptr[5]<<40 | (u8)ptr[6]<<48 | (u8)ptr[7]<<56;
125 }
126 return ret;
127 }
128
129 u4 ImageDecompressor::getU4(u1* ptr, Endian *endian) {
130 u4 ret;
131 if (endian->is_big_endian()) {
132 ret = ptr[0] << 24 | ptr[1]<<16 | (ptr[2]<<8) | ptr[3];
133 } else {
134 ret = ptr[0] | ptr[1]<<8 | (ptr[2]<<16) | ptr[3]<<24;
135 }
136 return ret;
137 }
I dunno if hotspot/src/share/vm/utilities/bytes.hpp can be leveraged here.
java.lang.module.ModuleInfo
—
460 private static boolean isAttributeDisallowed(String name) {
461 Set<String> notAllowed = predefinedNotAllowed;
462 if (notAllowed == null) {
463 notAllowed = Stream.of(
464 "ConstantValue",
465 "Code",
466 "StackMapTable",
467 "Exceptions",
468 "EnclosingMethod",
469 "Signature",
470 "LineNumberTable",
471 "LocalVariableTable",
472 "LocalVariableTypeTable",
473 "RuntimeVisibleAnnotations",
474 "RuntimeInvisibleAnnotations",
475 "RuntimeVisibleParameterAnnotations",
476 "RuntimeInvisibleParameterAnnotations",
477 "RuntimeVisibleTypeAnnotations",
478 "RuntimeInvisibleTypeAnnotations",
479 "AnnotationDefault",
480 "BootstrapMethods",
481 "MethodParameters")
482 .collect(Collectors.toSet());
483 predefinedNotAllowed = notAllowed;
Consider using Set.of
484 }
485
486 if (notAllowed.contains(name)) {
487 return true;
488 } else {
489 return false;
490 }
491 }
j.l.ModuleReader
—
145 default Optional<ByteBuffer> read(String name) throws IOException {
146 final int BUFFER_SIZE = 8192;
147 final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
148
149 InputStream in = open(name).orElse(null);
150 if (in == null) {
151 // not found
152 return Optional.empty();
153 }
154
155 try (in) {
156 int capacity = in.available();
157 if (capacity == 0)
158 capacity = BUFFER_SIZE;
159
160 byte[] buf = new byte[capacity];
161 int nread = 0;
162 int n;
163 for (;;) {
Use InputStream.readAllBytes?
jdk.internal.module.Builder
—
56 private static final Set<Requires.Modifier> MANDATED =
57 Collections.singleton(Requires.Modifier.MANDATED);
58 private static final Set<Requires.Modifier> PUBLIC =
59 Collections.singleton(Requires.Modifier.PUBLIC);
Set.of ?
More information about the jigsaw-dev
mailing list