mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8350549: MethodHandleProxies.WRAPPER_TYPES is not thread-safe
Reviewed-by: jpai, jvernee
This commit is contained in:
parent
c514f135cc
commit
bd7c77898a
@ -35,12 +35,10 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.UndeclaredThrowableException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -55,6 +53,7 @@ import jdk.internal.constant.ConstantUtils;
|
||||
import jdk.internal.loader.ClassLoaders;
|
||||
import jdk.internal.module.Modules;
|
||||
import jdk.internal.util.ClassFileDumper;
|
||||
import jdk.internal.util.ReferencedKeySet;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.*;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
@ -200,7 +199,7 @@ public final class MethodHandleProxies {
|
||||
private static final ClassFileDumper DUMPER = ClassFileDumper.getInstance(
|
||||
"jdk.invoke.MethodHandleProxies.dumpClassFiles", "DUMP_MH_PROXY_CLASSFILES");
|
||||
|
||||
private static final Set<Class<?>> WRAPPER_TYPES = Collections.newSetFromMap(new WeakHashMap<>());
|
||||
private static final Set<Class<?>> WRAPPER_TYPES = ReferencedKeySet.create(false, ReferencedKeySet.concurrentHashMapSupplier());
|
||||
private static final ClassValue<WeakReferenceHolder<Class<?>>> PROXIES = new ClassValue<>() {
|
||||
@Override
|
||||
protected WeakReferenceHolder<Class<?>> computeValue(Class<?> intfc) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2023, 2025, 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
|
||||
@ -30,6 +30,7 @@ import java.io.IOException;
|
||||
import java.lang.constant.ClassDesc;
|
||||
import java.lang.constant.MethodTypeDesc;
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandleProxies;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.WrongMethodTypeException;
|
||||
import java.lang.reflect.AccessFlag;
|
||||
@ -45,6 +46,7 @@ import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.IntSupplier;
|
||||
import java.util.function.ToLongFunction;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.lang.constant.ConstantDescs.*;
|
||||
import static java.lang.invoke.MethodHandleProxies.*;
|
||||
@ -55,7 +57,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6983726 8206955 8269351
|
||||
* @bug 6983726 8206955 8269351 8350549
|
||||
* @summary Basic sanity tests for MethodHandleProxies
|
||||
* @build BasicTest Client
|
||||
* @run junit BasicTest
|
||||
@ -251,6 +253,32 @@ public class BasicTest {
|
||||
assertThrows(ClassCastException.class, proxy::iterator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies {@code isWrapperInstance} works under race and is thread safe
|
||||
* like {@code Class} objects are.
|
||||
*/
|
||||
@Test
|
||||
public void testRacyWrapperCheck() {
|
||||
MethodHandle noop = MethodHandles.zero(void.class);
|
||||
var lookup = MethodHandles.lookup();
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
Stream.generate(() -> {
|
||||
String name = "MHPRaceIface" + counter.getAndIncrement();
|
||||
var bytes = ClassFile.of().build(ClassDesc.of(name), clb ->
|
||||
clb.withFlags(ACC_PUBLIC | ACC_ABSTRACT | ACC_INTERFACE)
|
||||
.withMethod("sam", MTD_void, ACC_PUBLIC | ACC_ABSTRACT, _ -> {}));
|
||||
try {
|
||||
return lookup.defineClass(bytes);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}).parallel()
|
||||
.map(cl -> MethodHandleProxies.asInterfaceInstance(cl, noop))
|
||||
.limit(100)
|
||||
.forEach(inst -> assertTrue(MethodHandleProxies.isWrapperInstance(inst),
|
||||
() -> Objects.toIdentityString(inst) + " should pass wrapper test"));
|
||||
}
|
||||
|
||||
private static <T extends Throwable> Closeable throwing(Class<T> clz, T value) {
|
||||
return asInterfaceInstance(Closeable.class, MethodHandles.throwException(void.class, clz).bindTo(value));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user