From 88d14cd6510675d187c656edc77b541ac0b06a9b Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 5 Oct 2023 06:02:02 +0000 Subject: [PATCH 1/6] 8314654: Metaspace: move locking out of MetaspaceArena Reviewed-by: adinn, jsjolen --- .../gtest/metaspace/test_metaspacearena.cpp | 15 +++------------ .../metaspace/test_metaspacearena_stress.cpp | 10 +--------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp index c81a4cb6b22..79643ab2925 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena.cpp @@ -24,15 +24,15 @@ */ #include "precompiled.hpp" +#include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/commitLimiter.hpp" #include "memory/metaspace/counters.hpp" #include "memory/metaspace/internalStats.hpp" #include "memory/metaspace/metaspaceArena.hpp" #include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp" +#include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/metaspaceSettings.hpp" #include "memory/metaspace/metaspaceStatistics.hpp" -#include "runtime/mutex.hpp" -#include "runtime/mutexLocker.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" @@ -55,22 +55,14 @@ class MetaspaceArenaTestHelper { MetaspaceGtestContext& _context; - Mutex* _lock; const ArenaGrowthPolicy* _growth_policy; SizeAtomicCounter _used_words_counter; MetaspaceArena* _arena; void initialize(const ArenaGrowthPolicy* growth_policy, const char* name = "gtest-MetaspaceArena") { _growth_policy = growth_policy; - _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTest_lock"); - // Lock during space creation, since this is what happens in the VM too - // (see ClassLoaderData::metaspace_non_null(), which we mimick here). - { - MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); - _arena = new MetaspaceArena(&_context.cm(), _growth_policy, _lock, &_used_words_counter, name); - } + _arena = new MetaspaceArena(&_context.cm(), _growth_policy, &_used_words_counter, name); DEBUG_ONLY(_arena->verify()); - } public: @@ -94,7 +86,6 @@ class MetaspaceArenaTestHelper { ~MetaspaceArenaTestHelper() { delete_arena_with_tests(); - delete _lock; } const CommitLimiter& limiter() const { return _context.commit_limiter(); } diff --git a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp index 2d0dc665f9a..2481ae04e4b 100644 --- a/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspacearena_stress.cpp @@ -59,8 +59,6 @@ class MetaspaceArenaTestBed : public CHeapObj { MetaspaceArena* _arena; - Mutex* _lock; - const SizeRange _allocation_range; size_t _size_of_last_failed_allocation; @@ -131,18 +129,13 @@ class MetaspaceArenaTestBed : public CHeapObj { MetaspaceArenaTestBed(ChunkManager* cm, const ArenaGrowthPolicy* alloc_sequence, SizeAtomicCounter* used_words_counter, SizeRange allocation_range) : _arena(NULL), - _lock(NULL), _allocation_range(allocation_range), _size_of_last_failed_allocation(0), _allocations(NULL), _alloc_count(), _dealloc_count() { - _lock = new Mutex(Monitor::nosafepoint, "gtest-MetaspaceArenaTestBed_lock"); - // Lock during space creation, since this is what happens in the VM too - // (see ClassLoaderData::metaspace_non_null(), which we mimick here). - MutexLocker ml(_lock, Mutex::_no_safepoint_check_flag); - _arena = new MetaspaceArena(cm, alloc_sequence, _lock, used_words_counter, "gtest-MetaspaceArenaTestBed-sm"); + _arena = new MetaspaceArena(cm, alloc_sequence, used_words_counter, "gtest-MetaspaceArenaTestBed-sm"); } ~MetaspaceArenaTestBed() { @@ -161,7 +154,6 @@ class MetaspaceArenaTestBed : public CHeapObj { // Delete MetaspaceArena. That should clean up all metaspace. delete _arena; - delete _lock; } From cc1ef49e366cdbf650ba01085cf0da3c8b187207 Mon Sep 17 00:00:00 2001 From: Emanuel Peter Date: Thu, 5 Oct 2023 06:46:44 +0000 Subject: [PATCH 2/6] 8316594: C2 SuperWord: wrong result with hand unrolled loops Reviewed-by: kvn, thartmann --- .../superword/TestMovingLoadBeforeStore.java | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java index 71d9050160f..80922aeffe9 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestMovingLoadBeforeStore.java @@ -25,27 +25,35 @@ /** * @test * @requires vm.compiler2.enabled - * @bug 8316679 + * @requires vm.cpu.features ~= ".*avx2.*" + * @bug 8316679 8316594 * @summary In SuperWord::output, LoadVector can be moved before StoreVector, but only if it is proven to be safe. * @key randomness + * @modules java.base/jdk.internal.misc * @library /test/lib * @run main/othervm -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestMovingLoadBeforeStore::test* * -Xbatch -XX:LoopUnrollLimit=100 * -XX:+UnlockDiagnosticVMOptions -XX:+StressLCM + * --add-modules java.base --add-exports java.base/jdk.internal.misc=ALL-UNNAMED * compiler.loopopts.superword.TestMovingLoadBeforeStore */ package compiler.loopopts.superword; import java.util.Random; import jdk.test.lib.Utils; +import jdk.internal.misc.Unsafe; public class TestMovingLoadBeforeStore { static int RANGE = 1024*64; + static int NINE = 9; + private static final Random random = Utils.getRandomInstance(); + static Unsafe UNSAFE = Unsafe.getUnsafe(); public static void main(String[] strArr) { byte a[] = new byte[RANGE]; + byte b[] = new byte[RANGE]; for (int i = 0; i < 100; i++) { for (int j = 0; j < a.length; j++) { a[j] = (byte)random.nextInt(); @@ -56,6 +64,30 @@ public static void main(String[] strArr) { test1(a_res, a_res, i % 2); verify("a in test1", a_ref, a_res, a); } + for (int i = 0; i < 100; i++) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte)random.nextInt(); + b[j] = (byte)random.nextInt(); + } + byte[] a_ref = a.clone(); + byte[] b_ref = b.clone(); + byte[] a_res = a.clone(); + byte[] b_res = b.clone(); + ref2(a_ref, b_ref); + test2(a_res, b_res); + verify("a in test2", a_ref, a_res, a); + verify("b in test2", b_ref, b_res, b); + } + for (int i = 0; i < 100; i++) { + for (int j = 0; j < a.length; j++) { + a[j] = (byte)random.nextInt(); + } + byte[] a_ref = a.clone(); + byte[] a_res = a.clone(); + ref3(a_ref); + test3(a_res); + verify("a in test3", a_ref, a_res, a); + } } static void verify(String name, byte[] ref, byte[] res, byte[] orig) { @@ -96,4 +128,60 @@ static void ref1(byte[] a, byte[] b, int inv) { b[inv + i + 3]++; } } + + static void test2(byte[] a, byte[] b) { + for (int i = 46; i < 6000; i++) { + a[47 + i + 0]++; + a[47 + i + 1]++; + a[47 + i + 2]++; + a[47 + i + 3]++; + b[NINE + i + 0]++; + b[NINE + i + 1]++; + b[NINE + i + 2]++; + b[NINE + i + 3]++; + } + } + + static void ref2(byte[] a, byte[] b) { + for (int i = 46; i < 6000; i++) { + a[47 + i + 0]++; + a[47 + i + 1]++; + a[47 + i + 2]++; + a[47 + i + 3]++; + b[NINE + i + 0]++; + b[NINE + i + 1]++; + b[NINE + i + 2]++; + b[NINE + i + 3]++; + } + } + + static void test3(byte[] a) { + for (int i = 51; i < 6000; i++) { + int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + 42 + i; + UNSAFE.putIntUnaligned(a, adr + 0*4, UNSAFE.getIntUnaligned(a, adr + 0*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 1*4, UNSAFE.getIntUnaligned(a, adr + 1*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 2*4, UNSAFE.getIntUnaligned(a, adr + 2*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 3*4, UNSAFE.getIntUnaligned(a, adr + 3*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 4*4, UNSAFE.getIntUnaligned(a, adr + 4*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 5*4, UNSAFE.getIntUnaligned(a, adr + 5*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 6*4, UNSAFE.getIntUnaligned(a, adr + 6*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 7*4, UNSAFE.getIntUnaligned(a, adr + 7*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 8*4, UNSAFE.getIntUnaligned(a, adr + 8*4) + 1); + } + } + + static void ref3(byte[] a) { + for (int i = 51; i < 6000; i++) { + int adr = UNSAFE.ARRAY_BYTE_BASE_OFFSET + 42 + i; + UNSAFE.putIntUnaligned(a, adr + 0*4, UNSAFE.getIntUnaligned(a, adr + 0*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 1*4, UNSAFE.getIntUnaligned(a, adr + 1*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 2*4, UNSAFE.getIntUnaligned(a, adr + 2*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 3*4, UNSAFE.getIntUnaligned(a, adr + 3*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 4*4, UNSAFE.getIntUnaligned(a, adr + 4*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 5*4, UNSAFE.getIntUnaligned(a, adr + 5*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 6*4, UNSAFE.getIntUnaligned(a, adr + 6*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 7*4, UNSAFE.getIntUnaligned(a, adr + 7*4) + 1); + UNSAFE.putIntUnaligned(a, adr + 8*4, UNSAFE.getIntUnaligned(a, adr + 8*4) + 1); + } + } } From 76276ddb5e76378d5af01c6897603d2f2d8ea47d Mon Sep 17 00:00:00 2001 From: Ludvig Janiuk Date: Thu, 5 Oct 2023 07:54:34 +0000 Subject: [PATCH 3/6] 8317039: Enable specifying the JDK used to run jtreg Reviewed-by: erikj --- make/RunTests.gmk | 2 +- make/RunTestsPrebuilt.gmk | 2 ++ make/autoconf/lib-tests.m4 | 38 +++++++++++++++++++++++++++++++++++++- make/autoconf/spec.gmk.in | 2 ++ 4 files changed, 42 insertions(+), 2 deletions(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index ff0ac736ca0..d328afce5f7 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -868,7 +868,7 @@ define SetupRunJtregTestBody $$(RM) -r $$($1_TEST_RESULTS_DIR) $1_COMMAND_LINE := \ - $$(JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ + $$(JTREG_JAVA) $$($1_JTREG_LAUNCHER_OPTIONS) \ -Dprogram=jtreg -jar $$(JT_HOME)/lib/jtreg.jar \ $$($1_JTREG_BASIC_OPTIONS) \ -testjdk:$$(JDK_UNDER_TEST) \ diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index ca20ccf26ad..363644ecf0a 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -122,6 +122,7 @@ $(eval $(call SetupVariable,JT_HOME)) $(eval $(call SetupVariable,JDK_IMAGE_DIR,$(OUTPUTDIR)/images/jdk)) $(eval $(call SetupVariable,TEST_IMAGE_DIR,$(OUTPUTDIR)/images/test)) $(eval $(call SetupVariable,SYMBOLS_IMAGE_DIR,$(OUTPUTDIR)/images/symbols,NO_CHECK)) +$(eval $(call SetupVariable,JTREG_JAVA,$(BOOT_JDK)/bin/java)) # Provide default values for tools that we need $(eval $(call SetupVariable,MAKE,make,NO_CHECK)) @@ -248,6 +249,7 @@ $(call CreateNewSpec, $(NEW_SPEC), \ TOPDIR := $(TOPDIR), \ OUTPUTDIR := $(OUTPUTDIR), \ BOOT_JDK := $(BOOT_JDK), \ + JTREG_JAVA := $(FIXPATH) $(JTREG_JAVA), \ JT_HOME := $(JT_HOME), \ JDK_IMAGE_DIR := $(JDK_IMAGE_DIR), \ JCOV_IMAGE_DIR := $(JCOV_IMAGE_DIR), \ diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index aecea86b744..5c03d433c38 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -227,12 +227,48 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_JTREG], UTIL_FIXUP_PATH(JT_HOME) AC_SUBST(JT_HOME) + # Specify a JDK for running jtreg. Defaults to the BOOT_JDK. + AC_ARG_WITH(jtreg-jdk, [AS_HELP_STRING([--with-jdk], + [path to JDK for running jtreg @<:@BOOT_JDK@:>@])]) + + AC_MSG_CHECKING([for jtreg jdk]) + if test "x${with_jtreg_jdk}" != x; then + if test "x${with_jtreg_jdk}" = xno; then + AC_MSG_RESULT([no, jtreg jdk not specified]) + elif test "x${with_jtreg_jdk}" = xyes; then + AC_MSG_RESULT([not specified]) + AC_MSG_ERROR([--with-jtreg-jdk needs a value]) + else + JTREG_JDK="${with_jtreg_jdk}" + AC_MSG_RESULT([$JTREG_JDK]) + UTIL_FIXUP_PATH(JTREG_JDK) + if test ! -f "$JTREG_JDK/bin/java"; then + AC_MSG_ERROR([Could not find jtreg java at $JTREG_JDK/bin/java]) + fi + fi + else + JTREG_JDK="${BOOT_JDK}" + AC_MSG_RESULT([no, using BOOT_JDK]) + fi + + JTREG_JAVA="$JTREG_JDK/bin/java" + UTIL_FIXUP_PATH(JTREG_JAVA) + JTREG_JAVA="$FIXPATH $JTREG_JAVA" + AC_SUBST([JTREG_JAVA]) + + # Verify jtreg version if test "x$JT_HOME" != x; then + AC_MSG_CHECKING([jtreg jar existence]) + if test ! -f "$JT_HOME/lib/jtreg.jar"; then + AC_MSG_ERROR([Could not find jtreg jar at $JT_HOME/lib/jtreg.jar]) + fi + AC_MSG_CHECKING([jtreg version number]) # jtreg -version looks like this: "jtreg 6.1+1-19" # Extract actual version part ("6.1" in this case) - jtreg_version_full=`$JAVA -jar $JT_HOME/lib/jtreg.jar -version | $HEAD -n 1 | $CUT -d ' ' -f 2` + jtreg_version_full=$($JTREG_JAVA -jar $JT_HOME/lib/jtreg.jar -version | $HEAD -n 1 | $CUT -d ' ' -f 2) + jtreg_version=${jtreg_version_full/%+*} AC_MSG_RESULT([$jtreg_version]) diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 1cead7d051d..1f2accf3a67 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -666,6 +666,8 @@ JAVA_FLAGS_SMALL:=@JAVA_FLAGS_SMALL@ BUILDJDK_JAVA_FLAGS_SMALL:=@BUILDJDK_JAVA_FLAGS_SMALL@ JAVA_TOOL_FLAGS_SMALL:=@JAVA_TOOL_FLAGS_SMALL@ +JTREG_JAVA:=@JTREG_JAVA@ + # The *_CMD variables are defined separately to be easily overridden in bootcycle-spec.gmk # for bootcycle-images build. Make sure to keep them in sync. Do not use the *_CMD # versions of the variables directly. From 08415b9fb9d001de354844eb5f5d36f3e98ce2db Mon Sep 17 00:00:00 2001 From: Daniel Fuchs Date: Thu, 5 Oct 2023 10:44:05 +0000 Subject: [PATCH 4/6] 8317522: Test logic for BODY_CF in AbstractThrowingSubscribers.java is wrong Reviewed-by: djelinski --- .../AbstractThrowingSubscribers.java | 98 ++++++++++++++----- 1 file changed, 71 insertions(+), 27 deletions(-) diff --git a/test/jdk/java/net/httpclient/AbstractThrowingSubscribers.java b/test/jdk/java/net/httpclient/AbstractThrowingSubscribers.java index d4100b7eb04..077ae346462 100644 --- a/test/jdk/java/net/httpclient/AbstractThrowingSubscribers.java +++ b/test/jdk/java/net/httpclient/AbstractThrowingSubscribers.java @@ -21,9 +21,6 @@ * questions. */ -import com.sun.net.httpserver.HttpServer; -import com.sun.net.httpserver.HttpsConfigurator; -import com.sun.net.httpserver.HttpsServer; import jdk.test.lib.net.SimpleSSLContext; import org.testng.ITestContext; import org.testng.ITestResult; @@ -33,7 +30,6 @@ import org.testng.annotations.BeforeMethod; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; import javax.net.ssl.SSLContext; import java.io.BufferedReader; @@ -42,11 +38,8 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UncheckedIOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; import java.net.URI; import java.net.http.HttpClient; -import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodyHandler; @@ -63,7 +56,7 @@ import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executor; import java.util.concurrent.Executors; -import java.util.concurrent.Flow; +import java.util.concurrent.Flow.Subscription; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; @@ -72,7 +65,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.httpclient.test.lib.common.HttpServerAdapters; -import jdk.httpclient.test.lib.http2.Http2TestServer; import static java.lang.System.out; import static java.lang.String.format; @@ -99,6 +91,7 @@ public abstract class AbstractThrowingSubscribers implements HttpServerAdapters String https2URI_chunk; static final int ITERATION_COUNT = 1; + static final int REPEAT_RESPONSE = 3; // a shared executor helps reduce the amount of threads created by the test static final Executor executor = new TestExecutor(Executors.newCachedThreadPool()); static final ConcurrentMap FAILURES = new ConcurrentHashMap<>(); @@ -313,7 +306,8 @@ protected void testSanityImpl(String uri, boolean sameClient) BodyHandlers.ofString()); HttpResponse response = client.send(req, handler); String body = response.body(); - assertEquals(URI.create(body).getPath(), URI.create(uri2).getPath()); + Stream.of(body.split("\n")).forEach(u -> + assertEquals(URI.create(u).getPath(), URI.create(uri2).getPath())); if (!sameClient) { // Wait for the client to be garbage collected. // we use the ReferenceTracker API rather than HttpClient::close here, @@ -443,6 +437,7 @@ private void testThrowing(String uri, boolean sameClient, throws Exception { HttpClient client = null; + var throwing = thrower; for (Where where : EnumSet.complementOf(excludes)) { if (!sameClient || client == null) @@ -451,6 +446,9 @@ private void testThrowing(String uri, boolean sameClient, HttpRequest req = HttpRequest. newBuilder(URI.create(uri2)) .build(); + + thrower = thrower(where, throwing); + BodyHandler handler = new ThrowingBodyHandler(where.select(thrower), handlers.get()); System.out.println("try throwing in " + where); @@ -468,12 +466,9 @@ private void testThrowing(String uri, boolean sameClient, response = client.send(req, handler); } catch (Error | Exception t) { // synchronous send will rethrow exceptions - Throwable throwable = t.getCause(); - assert throwable != null; - - if (thrower.test(throwable)) { - System.out.println(now() + "Got expected exception: " + throwable); - } else throw causeNotFound(where, t); + Throwable throwable = findCause(t, thrower); + if (throwable == null) throw causeNotFound(where, t); + System.out.println(now() + "Got expected exception: " + throwable); } } if (response != null) { @@ -658,9 +653,38 @@ public BodySubscriber apply(HttpResponse.ResponseInfo rinfo) { } } + static final class BodyCFThrower implements Thrower { + final Thrower thrower; + BodyCFThrower(Thrower thrower) { + this.thrower = thrower; + } + @Override + public boolean test(Throwable throwable) { + // In case of BODY_CF we also cancel the stream, + // which can cause "Stream XX cancelled" to be reported + return thrower.test(throwable) || + throwable instanceof IOException io && ( + io.getMessage().matches("Stream [0-9]+ cancelled") || + io.getMessage().equals("subscription cancelled") + ); + } + @Override + public void accept(Where where) { + thrower.accept(where); + } + } + + static Thrower thrower(Where where, Thrower thrower) { + return switch (where) { + case BODY_CF -> new BodyCFThrower(thrower); + default -> thrower; + }; + } + static final class ThrowingBodySubscriber implements BodySubscriber { private final BodySubscriber subscriber; - volatile boolean onSubscribeCalled; + volatile Subscription subscription; + final CompletableFuture subscriptionCF = new CompletableFuture<>(); final Consumer throwing; ThrowingBodySubscriber(Consumer throwing, BodySubscriber subscriber) { this.throwing = throwing; @@ -668,17 +692,22 @@ static final class ThrowingBodySubscriber implements BodySubscriber { } @Override - public void onSubscribe(Flow.Subscription subscription) { + public void onSubscribe(Subscription subscription) { //out.println("onSubscribe "); - onSubscribeCalled = true; + this.subscription = subscription; throwing.accept(Where.ON_SUBSCRIBE); subscriber.onSubscribe(subscription); + subscriptionCF.complete(subscription); + } + + boolean onSubscribeCalled() { + return subscription != null; } @Override public void onNext(List item) { // out.println("onNext " + item); - assertTrue(onSubscribeCalled); + assertTrue(onSubscribeCalled(), "onNext called before onSubscribe"); throwing.accept(Where.ON_NEXT); subscriber.onNext(item); } @@ -686,7 +715,7 @@ public void onNext(List item) { @Override public void onError(Throwable throwable) { //out.println("onError"); - assertTrue(onSubscribeCalled); + assertTrue(onSubscribeCalled(), "onError called before onSubscribe"); throwing.accept(Where.ON_ERROR); subscriber.onError(throwable); } @@ -694,7 +723,7 @@ public void onError(Throwable throwable) { @Override public void onComplete() { //out.println("onComplete"); - assertTrue(onSubscribeCalled, "onComplete called before onSubscribe"); + assertTrue(onSubscribeCalled(), "onComplete called before onSubscribe"); throwing.accept(Where.ON_COMPLETE); subscriber.onComplete(); } @@ -702,10 +731,19 @@ public void onComplete() { @Override public CompletionStage getBody() { throwing.accept(Where.GET_BODY); + boolean shouldCancel = false; try { throwing.accept(Where.BODY_CF); } catch (Throwable t) { + shouldCancel = true; return CompletableFuture.failedFuture(t); + } finally { + // if a BodySubscriber returns a failed future, it + // should take responsibility for cancelling the + // subscription explicitly if needed. + if (shouldCancel) { + subscriptionCF.thenAccept(Subscription::cancel); + } } return subscriber.getBody(); } @@ -785,10 +823,13 @@ public void handle(HttpTestExchange t) throws IOException { try (InputStream is = t.getRequestBody()) { is.readAllBytes(); } - byte[] resp = t.getRequestURI().toString().getBytes(StandardCharsets.UTF_8); - t.sendResponseHeaders(200, resp.length); //fixed content length + byte[] resp = (t.getRequestURI() + "\n").getBytes(StandardCharsets.UTF_8); + t.sendResponseHeaders(200, resp.length * 3); //fixed content length try (OutputStream os = t.getResponseBody()) { - os.write(resp); + for (int i=0 ; i < REPEAT_RESPONSE; i++) { + os.write(resp); + os.flush(); + } } } } @@ -797,13 +838,16 @@ static class HTTP_ChunkedHandler implements HttpTestHandler { @Override public void handle(HttpTestExchange t) throws IOException { out.println("HTTP_ChunkedHandler received request to " + t.getRequestURI()); - byte[] resp = t.getRequestURI().toString().getBytes(StandardCharsets.UTF_8); + byte[] resp = (t.getRequestURI() + "\n").getBytes(StandardCharsets.UTF_8); try (InputStream is = t.getRequestBody()) { is.readAllBytes(); } t.sendResponseHeaders(200, -1); // chunked/variable try (OutputStream os = t.getResponseBody()) { - os.write(resp); + for (int i=0 ; i < REPEAT_RESPONSE; i++) { + os.write(resp); + os.flush(); + } } } } From f4a48f0b5328e99295ab01ae4f8d6bb3c4c5a571 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Thu, 5 Oct 2023 14:40:15 +0000 Subject: [PATCH 5/6] 8313348: Fix typo in JFormattedTextField: 'it self' Reviewed-by: honkar, dnguyen, psadhukhan --- .../javax/swing/JFormattedTextField.java | 8 +- .../javax/swing/plaf/basic/BasicTreeUI.java | 87 ++++++++++++++++--- 2 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java b/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java index 77dc47ebd0e..6b870cba8b1 100644 --- a/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java +++ b/src/java.desktop/share/classes/javax/swing/JFormattedTextField.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2023, 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 @@ -144,7 +144,7 @@ * Alternatively, you could invoke commitEdit, which would also * commit the value. *

- * JFormattedTextField does not do the formatting it self, + * JFormattedTextField does not do the formatting itself, * rather formatting is done through an instance of * JFormattedTextField.AbstractFormatter which is obtained from * an instance of JFormattedTextField.AbstractFormatterFactory. @@ -152,7 +152,7 @@ * notified when they become active by way of the * install method, at which point the * JFormattedTextField.AbstractFormatter can install whatever - * it needs to, typically a DocumentFilter. Similarly when + * it needs to, typically a DocumentFilter. Similarly, when * JFormattedTextField no longer * needs the AbstractFormatter, it will invoke * uninstall. @@ -164,7 +164,7 @@ * policy is JFormattedTextField.PERSIST * and the JFormattedTextField has been edited, the * AbstractFormatterFactory will not be queried until the - * value has been committed. Similarly if the focus lost policy is + * value has been committed. Similarly, if the focus lost policy is * JFormattedTextField.COMMIT and an exception * is thrown from stringToValue, the * AbstractFormatterFactory will not be queried when focus is diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java index 01bf20cfd7c..d2f59f9f51e 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicTreeUI.java @@ -25,26 +25,85 @@ package javax.swing.plaf.basic; -import javax.swing.*; -import javax.swing.event.*; -import java.awt.*; -import java.awt.event.*; -import java.awt.datatransfer.*; -import java.beans.*; -import java.util.Enumeration; -import java.util.Hashtable; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Stroke; +import java.awt.datatransfer.Transferable; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; +import java.awt.event.ComponentListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Comparator; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.CellRendererPane; +import javax.swing.Icon; +import javax.swing.InputMap; +import javax.swing.JComponent; +import javax.swing.JScrollBar; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.JTree; +import javax.swing.JViewport; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +import javax.swing.TransferHandler; +import javax.swing.UIDefaults; +import javax.swing.UIManager; +import javax.swing.event.CellEditorListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.MouseInputListener; +import javax.swing.event.TreeExpansionEvent; +import javax.swing.event.TreeExpansionListener; +import javax.swing.event.TreeModelEvent; +import javax.swing.event.TreeModelListener; +import javax.swing.event.TreeSelectionEvent; +import javax.swing.event.TreeSelectionListener; import javax.swing.plaf.ComponentUI; -import javax.swing.plaf.UIResource; import javax.swing.plaf.TreeUI; -import javax.swing.tree.*; -import javax.swing.text.Position; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.DragRecognitionSupport.BeforeDrag; -import sun.awt.AWTAccessor; -import sun.swing.SwingUtilities2; +import javax.swing.text.Position; +import javax.swing.tree.AbstractLayoutCache; +import javax.swing.tree.DefaultTreeCellEditor; +import javax.swing.tree.DefaultTreeCellRenderer; +import javax.swing.tree.FixedHeightLayoutCache; +import javax.swing.tree.TreeCellEditor; +import javax.swing.tree.TreeCellRenderer; +import javax.swing.tree.TreeModel; +import javax.swing.tree.TreePath; +import javax.swing.tree.TreeSelectionModel; +import javax.swing.tree.VariableHeightLayoutCache; +import sun.awt.AWTAccessor; import sun.swing.DefaultLookup; +import sun.swing.SwingUtilities2; import sun.swing.UIAction; /** @@ -4082,7 +4141,7 @@ void handleSelection(MouseEvent e) { } // Preferably checkForClickInExpandControl could take - // the Event to do this it self! + // the Event to do this itself! if(SwingUtilities.isLeftMouseButton(e)) { checkForClickInExpandControl(pressedPath, e.getX(), e.getY()); } From ddff4598b7ed6df5216c7b3e071380e4eb0910fd Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Thu, 5 Oct 2023 23:06:20 +0000 Subject: [PATCH 6/6] 8317443: StackOverflowError on calling ListFormat::getInstance() for Norwegian locales Reviewed-by: joehw --- .../util/locale/provider/LocaleResources.java | 21 ++++++++++--------- .../Format/ListFormat/TestListFormat.java | 7 ++++--- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java index dd7064416bd..e83f2896304 100644 --- a/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java +++ b/src/java.base/share/classes/sun/util/locale/provider/LocaleResources.java @@ -849,19 +849,20 @@ public String[] getListPatterns(ListFormat.Type type, ListFormat.Style style) { ResourceReference data = cache.get(cacheKey); if (data == null || ((lpArray = (String[]) data.get()) == null)) { - ResourceBundle rb = localeData.getDateFormatData(locale); - lpArray = rb.getStringArray("ListPatterns_" + typeStr + (style == ListFormat.Style.FULL ? "" : "-" + styleStr)); + var rbKey = "ListPatterns_" + typeStr + (style == ListFormat.Style.FULL ? "" : "-" + styleStr); + lpArray = localeData.getDateFormatData(locale).getStringArray(rbKey); if (lpArray[0].isEmpty() || lpArray[1].isEmpty() || lpArray[2].isEmpty()) { - var adapter = LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.CLDR); - if (adapter instanceof ResourceBundleBasedAdapter rbba) { + if (LocaleProviderAdapter.forType(LocaleProviderAdapter.Type.CLDR) + instanceof ResourceBundleBasedAdapter rbba) { var candList = rbba.getCandidateLocales("", locale); - // make sure there is at least one parent locale - if (candList.size() >= 2) { - var parentPatterns = adapter.getLocaleResources(candList.get(1)).getListPatterns(type, style); - for (int i = 0; i < 3; i++) { // exclude optional ones, ie, "two"/"three" - if (lpArray[i].isEmpty()) { - lpArray[i] = parentPatterns[i]; + if (!candList.isEmpty()) { + for (var p : candList.subList(1, candList.size())) { + var parentPatterns = localeData.getDateFormatData(p).getStringArray(rbKey); + for (int i = 0; i < 3; i++) { // exclude optional ones, ie, "two"/"three" + if (lpArray[i].isEmpty()) { + lpArray[i] = parentPatterns[i]; + } } } } diff --git a/test/jdk/java/text/Format/ListFormat/TestListFormat.java b/test/jdk/java/text/Format/ListFormat/TestListFormat.java index 7f8258dbed0..2d260c9a94c 100644 --- a/test/jdk/java/text/Format/ListFormat/TestListFormat.java +++ b/test/jdk/java/text/Format/ListFormat/TestListFormat.java @@ -316,10 +316,11 @@ void getInstance_3Arg_InheritanceValidation() { // English ("en") has Oxford-comma "end" pattern. Thus missing "standard"/"middle" // should be inherited from "en", but "end" should stay non-Oxford for "en-001" // Note that this test depends on a particular version of CLDR data. + var world = Locale.forLanguageTag("en-001"); assertEquals(""" - ListFormat [locale: "English (world)", start: "{0}, {1}", middle: "{0}, {1}", end: "{0} and {1}", two: "{0} and {1}", three: "{0}, {1} and {2}"] - """, - ListFormat.getInstance(Locale.forLanguageTag("en-001"), ListFormat.Type.STANDARD, ListFormat.Style.FULL).toString()); + ListFormat [locale: "%s", start: "{0}, {1}", middle: "{0}, {1}", end: "{0} and {1}", two: "{0} and {1}", three: "{0}, {1} and {2}"] + """.formatted(world.getDisplayName()), + ListFormat.getInstance(world, ListFormat.Type.STANDARD, ListFormat.Style.FULL).toString()); } private static void compareResult(ListFormat f, List input, String expected, boolean roundTrip) throws ParseException {